diff --git a/.ct.yml b/.ct.yml new file mode 100644 index 00000000000..68a9198e920 --- /dev/null +++ b/.ct.yml @@ -0,0 +1,5 @@ +# See: https://github.com/helm/chart-testing +target-branch: develop +chart-dirs: 'charts' +check-version-increment: false +validate-maintainers: false diff --git a/.github/actions/build-test-image/action.yml b/.github/actions/build-test-image/action.yml index b7a7948d2cf..1cd1dd8b939 100644 --- a/.github/actions/build-test-image/action.yml +++ b/.github/actions/build-test-image/action.yml @@ -15,7 +15,7 @@ inputs: required: false suites: description: The test suites to build into the image - default: chaos migration performance reorg smoke soak benchmark load/automationv2_1 + default: chaos migration reorg smoke soak benchmark load/automationv2_1 required: false QA_AWS_ROLE_TO_ASSUME: description: The AWS role to assume as the CD user, if any. Used in configuring the docker/login-action diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml index 055960ff282..0047c6a54bd 100644 --- a/.github/actions/golangci-lint/action.yml +++ b/.github/actions/golangci-lint/action.yml @@ -42,14 +42,9 @@ runs: shell: bash run: mkdir -p core/web/assets && touch core/web/assets/index.html - name: Build binary - if: ${{ inputs.go-directory == '.' }} - shell: bash - run: go build ./... - - name: Build binary - if: ${{ inputs.go-directory != '.' }} working-directory: ${{ inputs.go-directory }} shell: bash - run: go build + run: go build ./... - name: golangci-lint uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: diff --git a/.github/actions/notify-slack-jobs-result/README.md b/.github/actions/notify-slack-jobs-result/README.md new file mode 100644 index 00000000000..298930c0d95 --- /dev/null +++ b/.github/actions/notify-slack-jobs-result/README.md @@ -0,0 +1,37 @@ +# Notify Slack Jobs Result + +Sends a Slack message to a specified channel detailing the results of one to many GHA job results using a regex. The job results will be grouped by the `github_job_name_regex` and displayed underneath the `message_title`, with the regex matching group displayed as an individual result. This is primarily designed for when you have test groups running in a matrix, and would like condensed reporting on their status by group. It's often accompanied by posting a Slack message before to start a thread, then attaching all the results to that thread like we do in the reporting section of the [live-testnet-test.yml workflow](../../workflows/live-testnet-tests.yml). Check out the example below, where we post an initial summary message, then use this action to thread together specific results: + +```yaml +message_title: Optimism Goerli +github_job_name_regex: ^Optimism Goerli (?.*?) Tests$ # Note that the regex MUST have a capturing group named "cap" +``` + +![example](image.png) + +## Inputs + +```yaml +inputs: + github_token: + description: "The GitHub token to use for authentication (usually ${{ github.token }})" + required: true + github_repository: + description: "The GitHub owner/repository to use for authentication (usually ${{ github.repository }}))" + required: true + workflow_run_id: + description: "The workflow run ID to get the results from (usually ${{ github.run_id }})" + required: true + github_job_name_regex: + description: "The regex to use to match 1..many job name(s) to collect results from. Should include a capture group named 'cap' for the part of the job name you want to display in the Slack message (e.g. ^Client Compatability Test (?.*?)$)" + required: true + message_title: + description: "The title of the Slack message" + required: true + slack_channel_id: + description: "The Slack channel ID to post the message to" + required: true + slack_thread_ts: + description: "The Slack thread timestamp to post the message to, handy for keeping multiple related results in a single thread" + required: false +``` diff --git a/.github/actions/notify-slack-jobs-result/action.yml b/.github/actions/notify-slack-jobs-result/action.yml new file mode 100644 index 00000000000..63840cfa393 --- /dev/null +++ b/.github/actions/notify-slack-jobs-result/action.yml @@ -0,0 +1,110 @@ +name: Notify Slack Jobs Result +description: Will send a notification in Slack for the result of a GitHub action run, typically for test results +inputs: + github_token: + description: "The GitHub token to use for authentication (usually github.token)" + required: true + github_repository: + description: "The GitHub owner/repository to use for authentication (usually github.repository))" + required: true + workflow_run_id: + description: "The workflow run ID to get the results from (usually github.run_id)" + required: true + github_job_name_regex: + description: "The regex to use to match 1..many job name(s) to collect results from. Should include a capture group named 'cap' for the part of the job name you want to display in the Slack message (e.g. ^Client Compatability Test (?.*?)$)" + required: true + message_title: + description: "The title of the Slack message" + required: true + slack_channel_id: + description: "The Slack channel ID to post the message to" + required: true + slack_bot_token: + description: "The Slack bot token to use for authentication which needs permission and an installed app in the channel" + required: true + slack_thread_ts: + description: "The Slack thread timestamp to post the message to, handy for keeping multiple related results in a single thread" + required: false + +runs: + using: composite + steps: + - name: Get Results + shell: bash + id: test-results + run: | + # I feel like there's some clever, fully jq way to do this, but I ain't got the motivation to figure it out + echo "Querying test results at https://api.github.com/repos/${{inputs.github_repository}}/actions/runs/${{ inputs.workflow_run_id }}/jobs" + + PARSED_RESULTS=$(curl \ + -H "Authorization: Bearer ${{ inputs.github_token }}" \ + 'https://api.github.com/repos/${{inputs.github_repository}}/actions/runs/${{ inputs.workflow_run_id }}/jobs' \ + | jq -r --arg pattern "${{ inputs.github_job_name_regex }}" '.jobs[] + | select(.name | test($pattern)) as $job + | $job.steps[] + | select(.name == "Run Tests") + | { conclusion: (if .conclusion == "success" then ":white_check_mark:" else ":x:" end), cap: ("*" + ($job.name | capture($pattern).cap) + "*"), html_url: $job.html_url }') + + echo "Parsed Results:" + echo $PARSED_RESULTS + + ALL_SUCCESS=true + echo "Checking for failures" + echo "$PARSED_RESULTS" | jq -s | jq -r '.[] | select(.conclusion != ":white_check_mark:")' + for row in $(echo "$PARSED_RESULTS" | jq -s | jq -r '.[] | select(.conclusion != ":white_check_mark:")'); do + ALL_SUCCESS=false + break + done + echo "Success: $ALL_SUCCESS" + + echo all_success=$ALL_SUCCESS >> $GITHUB_OUTPUT + + FORMATTED_RESULTS=$(echo $PARSED_RESULTS | jq -s '[.[] + | { + conclusion: .conclusion, + cap: .cap, + html_url: .html_url + } + ] + | map("{\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": \"<\(.html_url)|\(.cap)>: \(.conclusion)\"}}") + | join(",")') + + echo "Formatted Results:" + echo $FORMATTED_RESULTS + + # Cleans out backslashes and quotes from jq + CLEAN_RESULTS=$(echo "$FORMATTED_RESULTS" | sed 's/\\\"/"/g' | sed 's/^"//;s/"$//') + + echo "Clean Results" + echo $CLEAN_RESULTS + + echo results=$CLEAN_RESULTS >> $GITHUB_OUTPUT + - name: Post Results + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + env: + SLACK_BOT_TOKEN: ${{ inputs.slack_bot_token }} + with: + channel-id: ${{ inputs.slack_channel_id }} + payload: | + { + "thread_ts": "${{ inputs.slack_thread_ts }}", + "attachments": [ + { + "color": "${{ steps.test-results.outputs.all_success == 'true' && '#2E7D32' || '#C62828' }}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "${{ inputs.message_title }} ${{ steps.test-results.outputs.all_success == 'true' && ':white_check_mark:' || ':x:'}}", + "emoji": true + } + }, + { + "type": "divider" + }, + ${{ steps.test-results.outputs.results }} + ] + } + ] + } diff --git a/.github/actions/notify-slack-jobs-result/image.png b/.github/actions/notify-slack-jobs-result/image.png new file mode 100644 index 00000000000..3bd398101fb Binary files /dev/null and b/.github/actions/notify-slack-jobs-result/image.png differ diff --git a/.github/actions/setup-create-base64-config-live-testnets/action.yml b/.github/actions/setup-create-base64-config-live-testnets/action.yml new file mode 100644 index 00000000000..5bf83191b59 --- /dev/null +++ b/.github/actions/setup-create-base64-config-live-testnets/action.yml @@ -0,0 +1,130 @@ +name: Create Base64 Config +description: A composite action that creates a base64-encoded config to be used by integration tests + +inputs: + runId: + description: The run id + testLogCollect: + description: Whether to always collect logs, even for passing tests + default: "false" + chainlinkImage: + description: The chainlink image to use + default: "public.ecr.aws/chainlink/chainlink" + chainlinkVersion: + description: The git commit sha to use for the image tag + pyroscopeServer: + description: URL of Pyroscope server + pyroscopeEnvironment: + description: Name of Pyroscope environment + pyroscopeKey: + description: Pyroscope server key + lokiEndpoint: + description: Loki push endpoint + lokiTenantId: + description: Loki tenant id + lokiBasicAuth: + description: Loki basic auth + logstreamLogTargets: + description: Where to send logs (e.g. file, loki) + grafanaUrl: + description: Grafana URL + grafanaDashboardUrl: + description: Grafana dashboard URL + network: + description: Network to run tests on + httpEndpoints: + description: HTTP endpoints to use for network + wsEndpoints: + description: WS endpoints to use for network + fundingKeys: + description: Funding keys to use for network + +runs: + using: composite + steps: + - name: Prepare Base64 TOML override + shell: bash + id: base64-config-override + env: + RUN_ID: ${{ inputs.runId }} + PYROSCOPE_SERVER: ${{ inputs.pyroscopeServer }} + PYROSCOPE_ENVIRONMENT: ${{ inputs.pyroscopeEnvironment }} + PYROSCOPE_KEY: ${{ inputs.pyroscopeKey }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + LOKI_ENDPOINT: ${{ inputs.lokiEndpoint }} + LOKI_TENANT_ID: ${{ inputs.lokiTenantId }} + LOKI_BASIC_AUTH: ${{ inputs.lokiBasicAuth }} + LOGSTREAM_LOG_TARGETS: ${{ inputs.logstreamLogTargets }} + GRAFANA_URL: ${{ inputs.grafanaUrl }} + GRAFANA_DASHBOARD_URL: ${{ inputs.grafanaDashboardUrl }} + NETWORK: ${{ inputs.network }} + HTTP_ENDPOINTS: ${{ inputs.httpEndpoints }} + WS_ENDPOINTS: ${{ inputs.wsEndpoints }} + FUNDING_KEYS: ${{ inputs.fundingKeys }} + run: | + convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" + } + + if [ -n "$PYROSCOPE_SERVER" ]; then + pyroscope_enabled=true + else + pyroscope_enabled=false + fi + + cat << EOF > config.toml + [Common] + chainlink_node_funding=0.5 + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="$CHAINLINK_VERSION" + + [Pyroscope] + enabled=$pyroscope_enabled + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + + [Logging] + run_id="$RUN_ID" + + [Logging.LogStream] + log_targets=$(convert_to_toml_array "$LOGSTREAM_LOG_TARGETS") + + [Logging.Loki] + tenant_id="$LOKI_TENANT_ID" + endpoint="$LOKI_URL" + basic_auth="$LOKI_BASIC_AUTH" + + [Logging.Grafana] + base_url="$GRAFANA_URL" + dashboard_url="$GRAFANA_DASHBOARD_URL" + + [Network] + selected_networks=["$NETWORK"] + + [Network.RpcHttpUrls] + "$NETWORK" = $(convert_to_toml_array "$HTTP_ENDPOINTS") + + [Network.RpcWsUrls] + "$NETWORK" = $(convert_to_toml_array "$WS_ENDPOINTS") + + [Network.WalletKeys] + "$NETWORK" = $(convert_to_toml_array "$FUNDING_KEYS") + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + touch .root_dir diff --git a/.github/actions/setup-create-base64-config/action.yml b/.github/actions/setup-create-base64-config/action.yml new file mode 100644 index 00000000000..55e5924bd76 --- /dev/null +++ b/.github/actions/setup-create-base64-config/action.yml @@ -0,0 +1,120 @@ +name: Create Base64 Config +description: A composite action that creates a base64-encoded config to be used by integration tests + +inputs: + runId: + description: The run id + testLogCollect: + description: Whether to always collect logs, even for passing tests + default: "false" + selectedNetworks: + description: The networks to run tests against + chainlinkImage: + description: The chainlink image to use + default: "public.ecr.aws/chainlink/chainlink" + chainlinkVersion: + description: The git commit sha to use for the image tag + pyroscopeServer: + description: URL of Pyroscope server + pyroscopeEnvironment: + description: Name of Pyroscope environment + pyroscopeKey: + description: Pyroscope server key + lokiEndpoint: + description: Loki push endpoint + lokiTenantId: + description: Loki tenant id + lokiBasicAuth: + description: Loki basic auth + logstreamLogTargets: + description: Where to send logs (e.g. file, loki) + grafanaUrl: + description: Grafana URL + grafanaDashboardUrl: + description: Grafana dashboard URL + +runs: + using: composite + steps: + - name: Prepare Base64 TOML override + shell: bash + id: base64-config-override + env: + RUN_ID: ${{ inputs.runId }} + TEST_LOG_COLLECT: ${{ inputs.testLogCollect }} + SELECTED_NETWORKS: ${{ inputs.selectedNetworks }} + PYROSCOPE_SERVER: ${{ inputs.pyroscopeServer }} + PYROSCOPE_ENVIRONMENT: ${{ inputs.pyroscopeEnvironment }} + PYROSCOPE_KEY: ${{ inputs.pyroscopeKey }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + LOKI_ENDPOINT: ${{ inputs.lokiEndpoint }} + LOKI_TENANT_ID: ${{ inputs.lokiTenantId }} + LOKI_BASIC_AUTH: ${{ inputs.lokiBasicAuth }} + LOGSTREAM_LOG_TARGETS: ${{ inputs.logstreamLogTargets }} + GRAFANA_URL: ${{ inputs.grafanaUrl }} + GRAFANA_DASHBOARD_URL: ${{ inputs.grafanaDashboardUrl }} + run: | + echo ::add-mask::$CHAINLINK_IMAGE + function convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" + } + + selected_networks=$(convert_to_toml_array "$SELECTED_NETWORKS") + log_targets=$(convert_to_toml_array "$LOGSTREAM_LOG_TARGETS") + + if [ -n "$PYROSCOPE_SERVER" ]; then + pyroscope_enabled=true + else + pyroscope_enabled=false + fi + + if [ -n "$TEST_LOG_COLLECT" ]; then + test_log_collect=true + else + test_log_collect=false + fi + + cat << EOF > config.toml + [Network] + selected_networks=$selected_networks + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="$CHAINLINK_VERSION" + + [Pyroscope] + enabled=$pyroscope_enabled + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + + [Logging] + test_log_collect=$test_log_collect + run_id="$RUN_ID" + + [Logging.LogStream] + log_targets=$log_targets + + [Logging.Loki] + tenant_id="$LOKI_TENANT_ID" + endpoint="$LOKI_ENDPOINT" + basic_auth="$LOKI_BASIC_AUTH" + + [Logging.Grafana] + base_url="$GRAFANA_URL" + dashboard_url="$GRAFANA_DASHBOARD_URL" + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV diff --git a/.github/actions/setup-create-base64-upgrade-config/action.yml b/.github/actions/setup-create-base64-upgrade-config/action.yml new file mode 100644 index 00000000000..900b15e515a --- /dev/null +++ b/.github/actions/setup-create-base64-upgrade-config/action.yml @@ -0,0 +1,61 @@ +name: Create Base64 Upgrade Config +description: A composite action that creates a base64-encoded config to be used by Chainlink version upgrade tests + +inputs: + selectedNetworks: + description: The networks to run tests against + chainlinkImage: + description: The chainlink image to upgrade from + default: "public.ecr.aws/chainlink/chainlink" + chainlinkVersion: + description: The git commit sha to use for the image tag + upgradeImage: + description: The chainlink image to upgrade to + default: "public.ecr.aws/chainlink/chainlink" + upgradeVersion: + description: The git commit sha to use for the image tag + +runs: + using: composite + steps: + - name: Prepare Base64 TOML override + shell: bash + id: base64-config-override + env: + SELECTED_NETWORKS: ${{ inputs.selectedNetworks }} + CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} + CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} + UPGRADE_IMAGE: ${{ inputs.upgradeImage }} + UPGRADE_VERSION: ${{ inputs.upgradeVersion }} + run: | + function convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" + } + + selected_networks=$(convert_to_toml_array "$SELECTED_NETWORKS") + + cat << EOF > config.toml + [Network] + selected_networks=$selected_networks + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="$CHAINLINK_VERSION" + + [ChainlinkUpgradeImage] + image="$UPGRADE_IMAGE" + version="$UPGRADE_VERSION" + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV diff --git a/.github/actions/setup-merge-base64-config/action.yml b/.github/actions/setup-merge-base64-config/action.yml new file mode 100644 index 00000000000..9651242f8f1 --- /dev/null +++ b/.github/actions/setup-merge-base64-config/action.yml @@ -0,0 +1,54 @@ +name: Merge Base64 Config +description: A composite action that merges user-provided Base64-encoded config with repository's secrets + +inputs: + base64Config: + description: Base64-encoded config to decode + +runs: + using: composite + steps: + - name: Add masks and export base64 config + shell: bash + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + + decoded_toml=$(echo $BASE64_CONFIG_OVERRIDE | base64 -d) + CHAINLINK_IMAGE=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*image[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + echo ::add-mask::$CHAINLINK_IMAGE + CHAINLINK_VERSION=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*version[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + NETWORKS=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*selected_networks[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + + if [ -n "$CHAINLINK_IMAGE" ]; then + echo "CHAINLINK_IMAGE=$CHAINLINK_IMAGE" >> $GITHUB_ENV + else + echo "No Chainlink Image found in base64-ed config. Exiting" + exit 1 + fi + if [ -n "$CHAINLINK_VERSION" ]; then + echo "CHAINLINK_VERSION=$CHAINLINK_VERSION" >> $GITHUB_ENV + else + echo "No Chainlink Version found in base64-ed config. Exiting" + exit 1 + fi + if [ -n "$NETWORKS" ]; then + echo "NETWORKS=$NETWORKS" >> $GITHUB_ENV + fi + + # use Loki config from GH secrets and merge it with base64 input + cat << EOF > config.toml + [Logging.Loki] + tenant_id="$LOKI_TENANT_ID" + endpoint="$LOKI_URL" + basic_auth="$LOKI_BASIC_AUTH" + # legacy, you only need this to access the cloud version + # bearer_token="bearer_token" + EOF + + echo "$decoded_toml" >> final_config.toml + cat config.toml >> final_config.toml + BASE64_CONFIG_OVERRIDE=$(cat final_config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV \ No newline at end of file diff --git a/.github/actions/setup-parse-base64-config/action.yml b/.github/actions/setup-parse-base64-config/action.yml new file mode 100644 index 00000000000..3acd2ab8940 --- /dev/null +++ b/.github/actions/setup-parse-base64-config/action.yml @@ -0,0 +1,38 @@ +name: Parse Base64 Config +description: A composite action that extracts the chainlink image, version and network from a base64-encoded config + +inputs: + base64Config: + description: Base64-encoded config to decode + +runs: + using: composite + steps: + - name: Add masks and export base64 config + shell: bash + run: | + decoded_toml=$(echo $BASE64_CONFIG_OVERRIDE | base64 -d) + CHAINLINK_IMAGE=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*image[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + echo ::add-mask::$CHAINLINK_IMAGE + CHAINLINK_VERSION=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*version[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + NETWORKS=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*selected_networks[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + ETH2_EL_CLIENT=$(echo "$decoded_toml" | awk -F'=' '/^[[:space:]]*execution_layer[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2}' 2>/dev/null) + + if [ -n "$CHAINLINK_IMAGE" ]; then + echo "CHAINLINK_IMAGE=$CHAINLINK_IMAGE" >> $GITHUB_ENV + else + echo "No Chainlink Image found in base64-ed config. Exiting" + exit 1 + fi + if [ -n "$CHAINLINK_VERSION" ]; then + echo "CHAINLINK_VERSION=$CHAINLINK_VERSION" >> $GITHUB_ENV + else + echo "No Chainlink Version found in base64-ed config. Exiting" + exit 1 + fi + if [ -n "$NETWORKS" ]; then + echo "NETWORKS=$NETWORKS" >> $GITHUB_ENV + fi + if [ -n "$ETH2_EL_CLIENT" ]; then + echo "ETH2_EL_CLIENT=$ETH2_EL_CLIENT" >> $GITHUB_ENV + fi \ No newline at end of file diff --git a/.github/scripts/functions.sh b/.github/scripts/functions.sh new file mode 100644 index 00000000000..53b53392269 --- /dev/null +++ b/.github/scripts/functions.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Function to convert a comma-separated list into a TOML array format. +# Usage: convert_to_toml_array "elem1,elem2,elem3" +# Effect: "a,b,c" -> ["a","b","c"] +function convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" +} \ No newline at end of file diff --git a/.github/tracing/README.md b/.github/tracing/README.md index feba31feb65..06b2eef6652 100644 --- a/.github/tracing/README.md +++ b/.github/tracing/README.md @@ -9,8 +9,18 @@ One way to generate traces locally today is with the OCR2 basic smoke test. 1. navigate to `.github/tracing/` and then run `docker compose --file local-smoke-docker-compose.yaml up` 2. setup a local docker registry at `127.0.0.1:5000` (https://www.docker.com/blog/how-to-use-your-own-registry-2/) 3. run `make build_push_plugin_docker_image` in `chainlink/integration-tests/Makefile` -4. run `SELECTED_NETWORKS=SIMULATED CHAINLINK_IMAGE="127.0.0.1:5000/chainlink" CHAINLINK_VERSION="develop" go test -run TestOCRv2Basic ./smoke/ocr2_test.go` -5. navigate to `localhost:3000/explore` in a web browser to query for traces +4. preapre your `overrides.toml` file with selected network and CL image name and version and place it anywhere +inside `integration-tests` directory. Sample `overrides.toml` file: +```toml +[ChainlinkImage] +image="127.0.0.1:5000/chainlink" +version="develop" + +[Network] +selected_networks=["simulated"] +``` +5. run `go test -run TestOCRv2Basic ./smoke/ocr2_test.go` +6. navigate to `localhost:3000/explore` in a web browser to query for traces Core and the median plugins are instrumented with open telemetry traces, which are sent to the OTEL collector and forwarded to the Tempo backend. The grafana UI can then read the trace data from the Tempo backend. @@ -48,4 +58,55 @@ This folder contains the following config files: These config files are for an OTEL collector, grafana Tempo, and a grafana UI instance to run as containers on the same network. `otel-collector-dev.yaml` is the configuration for dev (i.e. your local machine) environments, and forwards traces from the otel collector to the grafana tempo instance on the same network. -`otel-collector-ci.yaml` is the configuration for the CI runs, and exports the trace data to the artifact from the github run. \ No newline at end of file +`otel-collector-ci.yaml` is the configuration for the CI runs, and exports the trace data to the artifact from the github run. + +## Adding Traces to Plugins and to core + +Adding traces requires identifying an observability gap in a related group of code executions or a critical path in your application. This is intuitive for the developer: + +- "What's the flow of component interaction in this distributed system?" +- "What's the behavior of the JobProcessorOne component when jobs with [x, y, z] attributes are processed?" +- "Is this critical path workflow behaving the way we expect?" + +The developer will measure a flow of execution from end to end in one trace. Each logically separate measure of this flow is called a span. Spans have either one or no parent span and multiple children span. The relationship between parent and child spans in agreggate will form a directed acyclic graph. The trace begins at the root of this graph. + +The most trivial application of a span is measuring top level performance in one critical path. There is much more you can do, including creating human readable and timestamped events within a span (useful for monitoring concurrent access to resources), recording errors, linking parent and children spans through large parts of an application, and even extending a span beyond a single process. + +Spans are created by `tracers` and passed through go applications by `Context`s. A tracer must be initialized first. Both core and plugin developers will initialize a tracer from the globally registered trace provider: + +``` +tracer := otel.GetTracerProvider().Tracer("example.com/foo") +``` + +The globally registered tracer provider is available for plugins after they are initialized, and available in core after configuration is processed (`initGlobals`). + +Add spans by: +``` + func interestingFunc() { + // Assuming there is an appropriate parentContext + ctx, span := tracer.Start(parentContext, "hello-span") + defer span.End() + + // do some work to track with hello-span + } +``` +As implied by the example, `span` is a child of its parent span captured by `parentContext`. + + +Note that in certain situations, there are 3rd party libraries that will setup spans. For instance: + +``` +import ( + "github.com/gin-gonic/gin" + "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" +) + +router := gin.Default() +router.Use(otelgin.Middleware("service-name")) +``` + +The developer aligns with best practices when they: +- Start with critical paths +- Measure paths from end to end (Context is wired all the way through) +- Emphasize broadness of measurement over depth +- Use automatic instrumentation if possible \ No newline at end of file diff --git a/.github/workflows/auto-update.yml b/.github/workflows/auto-update.yml new file mode 100644 index 00000000000..963145c4049 --- /dev/null +++ b/.github/workflows/auto-update.yml @@ -0,0 +1,17 @@ +name: Auto Update +on: + push: + branches: + - develop +jobs: + autoupdate: + name: Auto Update + runs-on: ubuntu-latest + steps: + - uses: docker://chinthakagodawita/autoupdate-action:v1 + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + PR_FILTER: "labelled" + PR_LABELS: "auto-update" + MERGE_MSG: "Branch was auto-updated." + MERGE_CONFLICT_ACTION: "ignore" diff --git a/.github/workflows/automation-benchmark-tests.yml b/.github/workflows/automation-benchmark-tests.yml index efe6d2eb59d..740975ae5ee 100644 --- a/.github/workflows/automation-benchmark-tests.yml +++ b/.github/workflows/automation-benchmark-tests.yml @@ -2,52 +2,20 @@ name: Automation Benchmark Test on: workflow_dispatch: inputs: - chainlinkVersion: - description: Chainlink image version to use + testType: + description: Type of test to run (benchmark, soak) required: true + default: benchmark type: string - default: 2.6.0 - chainlinkImage: - description: Chainlink image repo to use + base64Config: + description: base64-ed config required: true type: string - default: public.ecr.aws/chainlink/chainlink - network: - description: Network to run tests on - required: true - type: choice - options: - - SIMULATED - - SIMULATED_NONDEV - - GOERLI - - ARBITRUM_GOERLI - - OPTIMISM_GOERLI - - MUMBAI - - SEPOLIA - - BASE_GOERLI - - ARBITRUM_SEPOLIA - TestInputs: - description: TestInputs - required: false - type: string - wsURL: - description: WS URL for the network (Skip for Simulated) - required: false - type: string - httpURL: - description: HTTP URL for the network (Skip for Simulated) - required: false - type: string slackMemberID: description: Notifies test results (Not your @) required: true default: U02Q14G80TY type: string - fundingPrivateKey: - description: Private funding key (Skip for Simulated) - required: false - type: string - jobs: automation_benchmark: environment: integration @@ -56,52 +24,40 @@ jobs: pull-requests: write id-token: write contents: read - name: ${{ inputs.network }} Automation Benchmark Test + name: Automation Benchmark Test runs-on: ubuntu20.04-16cores-64GB env: - SELECTED_NETWORKS: ${{ inputs.network }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: C03KJ5S7KEK - TEST_INPUTS: ${{ inputs.TestInputs }} CHAINLINK_ENV_USER: ${{ github.actor }} REF_NAME: ${{ github.head_ref || github.ref_name }} steps: - - name: Setup Push Tag - shell: bash - run: | - echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY - echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY - echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - - name: Add mask + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ env.REF_NAME }} + - name: Get Slack config and mask base64 config run: | - EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) - EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) - EVM_KEYS=$(jq -r '.inputs.fundingPrivateKey' $GITHUB_EVENT_PATH) SLACK_USER=$(jq -r '.inputs.slackMemberID' $GITHUB_EVENT_PATH) - echo ::add-mask::$EVM_URLS - echo ::add-mask::$EVM_HTTP_URLS - echo ::add-mask::$EVM_KEYS echo ::add-mask::$SLACK_USER - echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV - echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV - echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV echo SLACK_USER=$SLACK_USER >> $GITHUB_ENV - while IFS=',' read -ra EVM_URLS_2; do - for i in "${EVM_URLS_2[@]}"; do - echo ::add-mask::$i - done - done <<< "$EVM_URLS" - while IFS=',' read -ra EVM_HTTP_URLS_2; do - for i in "${EVM_HTTP_URLS_2[@]}"; do - echo ::add-mask::$i - done - done <<< "$EVM_HTTP_URLS" - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Parse base64 config + uses: ./.github/actions/setup-parse-base64-config with: - ref: ${{ env.REF_NAME }} + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Build Test Image uses: ./.github/actions/build-test-image with: @@ -117,11 +73,13 @@ jobs: TEST_ARGS: -test.timeout 720h ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:${{ github.sha }} INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com + TEST_TYPE: ${{ github.event.inputs.testType }} + TEST_TEST_TYPE: ${{ github.event.inputs.testType }} with: test_command_to_run: cd integration-tests && go test -timeout 30m -v -run ^TestAutomationBenchmark$ ./benchmark -count=1 test_download_vendor_packages_command: make gomod - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} token: ${{ secrets.GITHUB_TOKEN }} should_cleanup: false go_mod_path: ./integration-tests/go.mod @@ -135,6 +93,6 @@ jobs: with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: ${{ inputs.network }} Automation Benchmark Test + this-job-name: Automation Benchmark Test test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true diff --git a/.github/workflows/automation-load-tests.yml b/.github/workflows/automation-load-tests.yml index b19ac8fd24c..8045b589edc 100644 --- a/.github/workflows/automation-load-tests.yml +++ b/.github/workflows/automation-load-tests.yml @@ -2,26 +2,10 @@ name: Automation Load Test on: workflow_dispatch: inputs: - chainlinkVersion: - description: Chainlink image version to use + base64Config: + description: base64-ed config required: true - type: string - default: 2.6.0 - chainlinkImage: - description: Chainlink image repo to use - required: true - type: string - default: public.ecr.aws/chainlink/chainlink - network: - description: Network to run tests on - required: true - type: choice - options: - - SIMULATED - TestInputs: - description: TestInputs - required: false - type: string + type: string slackMemberID: description: Notifies test results (Not your @) required: true @@ -36,33 +20,60 @@ jobs: pull-requests: write id-token: write contents: read - name: ${{ inputs.network }} Automation Load Test + name: Automation Load Test runs-on: ubuntu20.04-16cores-64GB env: - SELECTED_NETWORKS: ${{ inputs.network }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: C03KJ5S7KEK - TEST_INPUTS: ${{ inputs.TestInputs }} CHAINLINK_ENV_USER: ${{ github.actor }} REF_NAME: ${{ github.head_ref || github.ref_name }} steps: - - name: Setup Push Tag - shell: bash - run: | - echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY - echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY - echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - - name: Add mask + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ env.REF_NAME }} + - name: Get Slack config and mask base64 config run: | SLACK_USER=$(jq -r '.inputs.slackMemberID' $GITHUB_EVENT_PATH) echo ::add-mask::$SLACK_USER echo SLACK_USER=$SLACK_USER >> $GITHUB_ENV - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Merge Pyrsoscope config + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: "automation-load-test" + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + run: | + decoded_toml=$(echo $BASE64_CONFIG_OVERRIDE | base64 -d) + + # use Pyroscope config from GH secrets and merge it with base64 input + cat << EOF > config.toml + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + EOF + + echo "$decoded_toml" >> final_config.toml + cat config.toml >> final_config.toml + BASE64_CONFIG_OVERRIDE=$(cat final_config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Parse base64 config + uses: ./.github/actions/setup-parse-base64-config with: - ref: ${{ env.REF_NAME }} + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Build Test Image uses: ./.github/actions/build-test-image with: @@ -85,8 +96,8 @@ jobs: with: test_command_to_run: cd integration-tests && go test -timeout 1h -v -run TestLogTrigger ./load/automationv2_1 -count=1 test_download_vendor_packages_command: make gomod - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} token: ${{ secrets.GITHUB_TOKEN }} should_cleanup: false go_mod_path: ./integration-tests/go.mod @@ -100,6 +111,6 @@ jobs: with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: ${{ inputs.network }} Automation Load Test + this-job-name: Automation Load Test test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true diff --git a/.github/workflows/automation-nightly-tests.yml b/.github/workflows/automation-nightly-tests.yml new file mode 100644 index 00000000000..9f4e4353e2d --- /dev/null +++ b/.github/workflows/automation-nightly-tests.yml @@ -0,0 +1,261 @@ +name: Automation Nightly Tests +on: + schedule: + - cron: "0 0 * * *" # Run nightly + push: + tags: + - "*" + workflow_dispatch: + +env: + CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink + +jobs: + build-chainlink: + environment: integration + permissions: + id-token: write + contents: read + name: Build Chainlink Image + runs-on: ubuntu20.04-16cores-64GB + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Build Chainlink Image + continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Build Chainlink Image + uses: ./.github/actions/build-chainlink-image + with: + tag_suffix: "" + dockerfile: core/chainlink.Dockerfile + git_commit_sha: ${{ github.sha }} + GRAFANA_CLOUD_BASIC_AUTH: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + GRAFANA_CLOUD_HOST: ${{ secrets.GRAFANA_CLOUD_HOST }} + AWS_REGION: ${{ secrets.QA_AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + + automation-upgrade-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink] + env: + CHAINLINK_COMMIT_SHA: ${{ github.sha }} + CHAINLINK_ENV_USER: ${{ github.actor }} + TEST_LOG_LEVEL: debug + SELECTED_NETWORKS: "SIMULATED" + strategy: + fail-fast: false + matrix: + tests: + - name: Upgrade + suite: smoke + nodes: 6 + os: ubuntu20.04-8cores-32GB + network: SIMULATED + command: -run ^TestAutomationNodeUpgrade$ ./smoke + runs-on: ${{ matrix.tests.os }} + name: Automation ${{ matrix.tests.name }} Test + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.head_ref || github.ref_name }} + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-upgrade-config + with: + selectedNetworks: ${{ env.SELECTED_NETWORKS }} + chainlinkImage: "public.ecr.aws/chainlink/chainlink" + chainlinkVersion: "latest" + upgradeImage: ${{ env.CHAINLINK_IMAGE }} + upgradeVersion: ${{ github.sha }} + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + env: + TEST_SUITE: ${{ matrix.tests.suite }} + with: + test_command_to_run: cd ./integration-tests && go test -timeout 60m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: 'public.ecr.aws/chainlink/chainlink' + cl_image_tag: 'latest' + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_location: ./integration-tests/${{ matrix.tests.suite }}/logs + publish_check_name: Automation Results ${{ matrix.tests.name }} + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Upload test log + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + if: failure() + with: + name: test-log-${{ matrix.tests.name }} + path: /tmp/gotest.log + retention-days: 7 + continue-on-error: true + - name: Collect Metrics + if: always() + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Automation ${{ matrix.tests.name }} Test + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true + + test-notify: + name: Start Slack Thread + if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} + environment: integration + outputs: + thread_ts: ${{ steps.slack.outputs.thread_ts }} + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + runs-on: ubuntu-latest + needs: [ automation-upgrade-tests ] + steps: + - name: Debug Result + run: echo ${{ join(needs.*.result, ',') }} + - name: Main Slack Notification + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + id: slack + with: + channel-id: C03KJ5S7KEK + payload: | + { + "attachments": [ + { + "color": "${{ contains(join(needs.*.result, ','), 'failure') && '#C62828' || '#2E7D32' }}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "Automation Nightly Tests ${{ contains(join(needs.*.result, ','), 'failure') && ':x:' || ':white_check_mark:'}}", + "emoji": true + } + }, + { + "type": "divider" + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "<${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ github.ref_name }}|${{ github.ref_name }}> | <${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}> | <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Run>" + } + } + ] + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + + test-results: + name: Post Test Results for ${{ matrix.name }} + if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + runs-on: ubuntu-latest + needs: test-notify + strategy: + fail-fast: false + matrix: + name: [ Upgrade ] + steps: + - name: Get Results + id: test-results + run: | + # I feel like there's some clever, fully jq way to do this, but I ain't got the motivation to figure it out + echo "Querying test results" + + PARSED_RESULTS=$(curl \ + -H "Authorization: Bearer ${{ github.token }}" \ + 'https://api.github.com/repos/${{github.repository}}/actions/runs/${{ github.run_id }}/jobs' \ + | jq -r --arg pattern "${{ matrix.name }} Test" '.jobs[] + | select(.name | test($pattern)) as $job + | $job.steps[] + | select(.name == "Run Tests") + | { conclusion: (if .conclusion == "success" then ":white_check_mark:" else ":x:" end), product: ("*" + ($job.name | capture($pattern).product) + "*") }') + + echo "Parsed Results:" + echo $PARSED_RESULTS + + ALL_SUCCESS=true + for row in $(echo "$PARSED_RESULTS" | jq -s | jq -r '.[] | select(.conclusion != ":white_check_mark:")'); do + success=false + break + done + + echo all_success=$ALL_SUCCESS >> $GITHUB_OUTPUT + + FORMATTED_RESULTS=$(echo $PARSED_RESULTS | jq -s '[.[] + | { + conclusion: .conclusion, + product: .product + } + ] + | map("{\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": \"\(.product): \(.conclusion)\"}}") + | join(",")') + + echo "Formatted Results:" + echo $FORMATTED_RESULTS + + # Cleans out backslashes and quotes from jq + CLEAN_RESULTS=$(echo "$FORMATTED_RESULTS" | sed 's/\\\"/"/g' | sed 's/^"//;s/"$//') + + echo "Clean Results" + echo $CLEAN_RESULTS + + echo results=$CLEAN_RESULTS >> $GITHUB_OUTPUT + + - name: Test Details + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + with: + channel-id: C03KJ5S7KEK + payload: | + { + "thread_ts": "${{ needs.test-notify.outputs.thread_ts }}", + "attachments": [ + { + "color": "${{ steps.test-results.outputs.all_success && '#2E7D32' || '#C62828' }}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "${{ matrix.name }} ${{ steps.test-results.outputs.all_success && ':white_check_mark:' || ':x: Notifying <@U02Q14G80TY>'}}", + "emoji": true + } + }, + { + "type": "divider" + }, + ${{ steps.test-results.outputs.results }} + ] + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} \ No newline at end of file diff --git a/.github/workflows/automation-ondemand-tests.yml b/.github/workflows/automation-ondemand-tests.yml index 016a10252be..ddf26d5607a 100644 --- a/.github/workflows/automation-ondemand-tests.yml +++ b/.github/workflows/automation-ondemand-tests.yml @@ -140,7 +140,7 @@ jobs: command: -run ^TestAutomationReorg$ ./reorg - name: upgrade suite: smoke - nodes: 3 + nodes: 6 os: ubuntu20.04-8cores-32GB pyroscope_env: ci-automation-on-demand-upgrade network: SIMULATED @@ -162,25 +162,70 @@ jobs: echo "upgrade_version=${{ github.sha }}" >>$GITHUB_OUTPUT echo "upgrade_image=${{ env.CHAINLINK_IMAGE }}" >>$GITHUB_OUTPUT else - echo "image=${{ inputs.chainlinkImage }}" >>$GITHUB_OUTPUT + READ_CL_IMAGE=$(jq -r '.inputs.chainlinkImage' $GITHUB_EVENT_PATH) + echo ::add-mask::$READ_CL_IMAGE + echo "image=$READ_CL_IMAGE" >>$GITHUB_OUTPUT echo "version=${{ inputs.chainlinkVersion }}" >>$GITHUB_OUTPUT echo "upgrade_version=${{ inputs.chainlinkVersion }}" >>$GITHUB_OUTPUT - echo "upgrade_image=${{ inputs.chainlinkImage }}" >>$GITHUB_OUTPUT + echo "upgrade_image=$READ_CL_IMAGE" >>$GITHUB_OUTPUT fi if [[ "${{ matrix.tests.name }}" == "upgrade" ]]; then - echo "image=${{ inputs.chainlinkImageUpdate }}" >>$GITHUB_OUTPUT + READ_CL_UPGR_IMAGE=$(jq -r '.inputs.chainlinkImageUpdate' $GITHUB_EVENT_PATH) + echo ::add-mask::$READ_CL_UPGR_IMAGE + echo "image=$READ_CL_UPGR_IMAGE" >>$GITHUB_OUTPUT echo "version=${{ inputs.chainlinkVersionUpdate }}" >>$GITHUB_OUTPUT fi - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + - name: Prepare Base64 TOML config env: - PYROSCOPE_SERVER: ${{ matrix.tests.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 - PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }} - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} SELECTED_NETWORKS: ${{ matrix.tests.network }} - TEST_SUITE: ${{ matrix.tests.suite }} + OLD_IMAGE: ${{ steps.determine-build.outputs.image }} + OLD_VERSION: ${{ steps.determine-build.outputs.version }} UPGRADE_VERSION: ${{ steps.determine-build.outputs.upgrade_version }} UPGRADE_IMAGE: ${{ steps.determine-build.outputs.upgrade_image }} + PYROSCOPE_SERVER: ${{ matrix.tests.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + PYROSCOPE_ENVIRONMENT: ${{ matrix.tests.pyroscope_env }} + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + run: | + echo ::add-mask::$UPGRADE_IMAGE + echo ::add-mask::$OLD_IMAGE + + # load reusable functions + source ./.github/scripts/functions.sh + + selected_networks=$(convert_to_toml_array "$SELECTED_NETWORKS") + + if [ -n "$PYROSCOPE_SERVER" ]; then + pyroscope_enabled=true + else + pyroscope_enabled=false + fi + + cat << EOF > config.toml + [Network] + selected_networks=$selected_networks + + [ChainlinkImage] + image="$OLD_IMAGE" + version="$OLD_VERSION" + + [ChainlinkUpgradeImage] + image="$UPGRADE_IMAGE" + version="$UPGRADE_VERSION" + + [Pyroscope] + enabled=$pyroscope_enabled + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + env: + TEST_SUITE: ${{ matrix.tests.suite }} with: test_command_to_run: cd ./integration-tests && go test -timeout 60m -count=1 -json -test.parallel=${{ matrix.tests.nodes }} ${{ matrix.tests.command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download diff --git a/.github/workflows/bash-scripts.yml b/.github/workflows/bash-scripts.yml new file mode 100644 index 00000000000..52ce17f1f28 --- /dev/null +++ b/.github/workflows/bash-scripts.yml @@ -0,0 +1,35 @@ +name: Bash Scripts + +on: + pull_request: + +jobs: + changes: + name: detect changes + runs-on: ubuntu-latest + outputs: + bash-scripts-src: ${{ steps.bash-scripts.outputs.src }} + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 + id: bash-scripts + with: + filters: | + src: + - 'tools/bin/**' + - '.github/workflows/bash-scripts.yml' + shellcheck: + name: ShellCheck Lint + runs-on: ubuntu-latest + needs: [changes] + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Run ShellCheck + if: needs.changes.outputs.bash-scripts-src == 'true' + uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0 + with: + scandir: "./tools/bin" + # Consider changing this to check for warnings once all warnings are fixed. + severity: error diff --git a/.github/workflows/build-publish-pr.yml b/.github/workflows/build-publish-pr.yml index a7186ee5a11..25ffa394551 100644 --- a/.github/workflows/build-publish-pr.yml +++ b/.github/workflows/build-publish-pr.yml @@ -2,8 +2,8 @@ name: "Build and Publish from PR" ## # This workflow builds and publishes a Docker image for Chainlink from a PR. -# It doesn't use an environment, has its own special IAM role, does not sign -# the image, and publishes to a special ECR repo. +# It has its own special IAM role, does not sign the image, and publishes to +# a special ECR repo. ## on: @@ -13,14 +13,34 @@ jobs: build-publish-untrusted: if: ${{ ! startsWith(github.ref_name, 'release/') }} runs-on: ubuntu-20.04 + environment: sdlc permissions: id-token: write contents: read + env: + ECR_IMAGE_NAME: crib-chainlink-untrusted steps: - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Git Short SHA + shell: bash + env: + GIT_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + echo "GIT_SHORT_SHA=${GIT_PR_HEAD_SHA:0:7}" | tee -a "$GITHUB_ENV" + + - name: Check if image exists + id: check-image + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + with: + repository: ${{ env.ECR_IMAGE_NAME}} + tag: sha-${{ env.GIT_SHORT_SHA }} + AWS_REGION: ${{ secrets.AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }} + - name: Build and publish chainlink image + if: steps.check-image.outputs.exists == 'false' uses: ./.github/actions/build-sign-publish-chainlink with: publish: true @@ -29,10 +49,55 @@ jobs: aws-region: ${{ secrets.AWS_REGION }} sign-images: false ecr-hostname: ${{ secrets.AWS_SDLC_ECR_HOSTNAME }} - ecr-image-name: crib-chainlink-untrusted + ecr-image-name: ${{ env.ECR_IMAGE_NAME }} dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + - name: Get PR labels + id: pr-labels + env: + GH_TOKEN: ${{ github.token }} + PR_NUMBER: ${{ github.event.number }} + run: | + RESPONSE=$(gh pr view ${PR_NUMBER} --json labels) + # Check if the labels command was successful + if [[ $? -ne 0 ]]; then + echo "Error fetching labels" + exit 1 + fi + echo "RESPONSE=${RESPONSE}" + LABELS=$(echo "$RESPONSE" | jq -r '.labels | map(.name) | join(", ")') + # Check if any labels were found + if [[ -z "${LABELS:-}" ]]; then + echo "No labels found" + else + echo "labels=${LABELS}" | tee -a "${GITHUB_OUTPUT}" + fi + + - name: Setup GAP + if: contains(steps.pr-labels.outputs.labels, 'crib') + uses: smartcontractkit/.github/actions/setup-gap@main + with: + aws-region: ${{ secrets.AWS_REGION }} + aws-role-arn: ${{ secrets.AWS_OIDC_IAM_ROLE_PUBLISH_PR_ARN }} + api-gateway-host: ${{ secrets.AWS_API_GW_HOST_ARGO_SAND }} + use-argocd: "true" + argocd-user: ${{ secrets.ARGOCD_USER_SAND }} + argocd-pass: ${{ secrets.ARGOCD_PASS_SAND }} + + # Run an Argo CD sync after the image is built. + - name: Argo CD App Sync + if: contains(steps.pr-labels.outputs.labels, 'crib') + shell: bash + env: + PR_NUMBER: ${{ github.event.number }} + run: | + argocd app sync \ + --plaintext \ + --grpc-web \ + --async \ + "crib-chainlink-${PR_NUMBER}" + - name: Collect Metrics if: always() id: collect-gha-metrics diff --git a/.github/workflows/ci-chaincli.yml b/.github/workflows/ci-chaincli.yml deleted file mode 100644 index fd58d08005c..00000000000 --- a/.github/workflows/ci-chaincli.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: chaincli CI - -on: - push: - paths: - - "core/scripts/chaincli/**" - pull_request: - paths: - - "core/scripts/chaincli/**" - -jobs: - golangci: - if: ${{ github.event_name == 'pull_request' || github.event_name == 'schedule' }} - name: chaincli-lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Golang Lint - uses: ./.github/actions/golangci-lint - with: - name: chaincli-lint - go-directory: core/scripts/chaincli - go-version-file: core/scripts/go.mod - go-module-file: core/scripts/go.sum - gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index fd8dfed88ab..6ba88247220 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -41,7 +41,7 @@ jobs: strategy: fail-fast: false matrix: - cmd: ["go_core_tests", "go_core_race_tests"] + cmd: ["go_core_tests", "go_core_race_tests", "go_core_fuzz"] name: Core Tests (${{ matrix.cmd }}) runs-on: ubuntu20.04-64cores-256GB env: @@ -50,7 +50,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup node - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs with: @@ -71,6 +71,17 @@ jobs: run: go build -o chainlink.test . - name: Setup DB run: ./chainlink.test local db preparetest + - name: Install LOOP Plugins + run: | + pushd $(go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-feeds) + go install ./cmd/chainlink-feeds + popd + pushd $(go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-solana) + go install ./pkg/solana/cmd/chainlink-solana + popd + pushd $(go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-starknet/relayer) + go install ./pkg/chainlink/cmd/chainlink-starknet + popd - name: Increase Race Timeout if: github.event.schedule != '' run: | @@ -84,7 +95,7 @@ jobs: run: ./tools/bin/${{ matrix.cmd }} ./... - name: Print Filtered Test Results if: ${{ failure() && matrix.cmd == 'go_core_tests' }} - uses: smartcontractkit/chainlink-github-actions/go/go-test-results-parsing@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/go/go-test-results-parsing@a052942591aaa12716eb9835b490d812a77d0831 # v2.3.1 with: results-file: ./output.txt output-file: ./output-short.txt @@ -97,7 +108,7 @@ jobs: working-directory: ./.github/actions/setup-postgres - name: Store logs artifacts if: always() - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 with: name: ${{ matrix.cmd }}_logs path: | @@ -136,7 +147,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup node - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 - name: Setup NodeJS uses: ./.github/actions/setup-nodejs with: @@ -154,7 +165,7 @@ jobs: - name: Setup DB run: ./chainlink.test local db preparetest - name: Load test outputs - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: path: ./artifacts - name: Build flakey test runner diff --git a/.github/workflows/ci-scripts.yml b/.github/workflows/ci-scripts.yml new file mode 100644 index 00000000000..dd46dfd7799 --- /dev/null +++ b/.github/workflows/ci-scripts.yml @@ -0,0 +1,45 @@ +name: CI Scripts + +on: + push: + pull_request: + +jobs: + lint-scripts: + if: ${{ github.event_name == 'pull_request' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Golang Lint + uses: ./.github/actions/golangci-lint + with: + name: lint-scripts + go-directory: core/scripts + go-version-file: core/scripts/go.mod + go-module-file: core/scripts/go.sum + gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} + + test-scripts: + if: ${{ github.event_name == 'pull_request' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Setup Go + uses: ./.github/actions/setup-go + with: + go-version-file: core/scripts/go.mod + go-module-file: core/scripts/go.sum + - name: Run Tests + shell: bash + working-directory: core/scripts + run: go test ./... + - name: Collect Metrics + if: always() + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: test-scripts + continue-on-error: true diff --git a/.github/workflows/client-compatibility-tests.yml b/.github/workflows/client-compatibility-tests.yml new file mode 100644 index 00000000000..a96ace1b5a2 --- /dev/null +++ b/.github/workflows/client-compatibility-tests.yml @@ -0,0 +1,331 @@ +name: Client Compatibility Tests +on: + schedule: + - cron: "30 5 * * *" # Run every night at midnight + 30min EST + push: + tags: + - "*" + workflow_dispatch: + +env: + CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink + INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com + MOD_CACHE_VERSION: 2 + +jobs: + # Build Test Dependencies + + build-chainlink: + environment: integration + permissions: + id-token: write + contents: read + name: Build Chainlink Image + runs-on: ubuntu-latest + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Build Chainlink Image + continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Build Chainlink Image + uses: ./.github/actions/build-chainlink-image + with: + tag_suffix: "" + dockerfile: core/chainlink.Dockerfile + git_commit_sha: ${{ github.sha }} + GRAFANA_CLOUD_BASIC_AUTH: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + GRAFANA_CLOUD_HOST: ${{ secrets.GRAFANA_CLOUD_HOST }} + AWS_REGION: ${{ secrets.QA_AWS_REGION }} + AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + + build-tests: + environment: integration + permissions: + id-token: write + contents: read + name: Build Tests Binary + runs-on: ubuntu-latest + steps: + - name: Collect Metrics + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: Build Tests Binary + continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Build Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@bce4caa154b1e0e652d042788e14c8870832acd2 # v2.3.0 + with: + test_download_vendor_packages_command: cd ./integration-tests && go mod download + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + go_tags: embed + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + binary_name: tests + + # End Build Test Dependencies + + client-compatibility-matrix: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + env: + SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 + CHAINLINK_COMMIT_SHA: ${{ github.sha }} + CHAINLINK_ENV_USER: ${{ github.actor }} + TEST_LOG_LEVEL: debug + strategy: + fail-fast: false + matrix: + include: + - name: ocr-geth + os: ubuntu-latest + test: TestOCRBasic + file: ocr + client: geth + timeout: 30m + pyroscope_env: ci-smoke-ocr-geth-simulated + - name: ocr-nethermind + test: TestOCRBasic + file: ocr + client: nethermind + timeout: 30m + pyroscope_env: ci-smoke-ocr-nethermind-simulated + - name: ocr-besu + test: TestOCRBasic + file: ocr + client: besu + timeout: 30m + pyroscope_env: ci-smoke-ocr-besu-simulated + - name: ocr-erigon + test: TestOCRBasic + file: ocr + client: erigon + timeout: 30m + pyroscope_env: ci-smoke-ocr-erigon-simulated + - name: ocr2-geth + test: "^TestOCRv2Basic/plugins$" + file: ocr2 + client: geth + timeout: 30m + pyroscope_env: ci-smoke-ocr2-geth-simulated + - name: ocr2-nethermind + test: "^TestOCRv2Basic/plugins$" + file: ocr2 + client: nethermind + timeout: 30m + pyroscope_env: ci-smoke-nethermind-evm-simulated + - name: ocr2-besu + test: "^TestOCRv2Basic/plugins$" + file: ocr2 + client: besu + timeout: 30m + pyroscope_env: ci-smoke-ocr2-besu-simulated + - name: ocr2-erigon + test: "^TestOCRv2Basic/plugins$" + file: ocr2 + client: erigon + timeout: 60m + pyroscope_env: ci-smoke-ocr2-erigon-simulated + runs-on: ubuntu-latest + name: Client Compatibility Test ${{ matrix.name }} + steps: + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Prepare Base64 TOML config + env: + SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-client-compatability-${{ matrix.client }}-testnet + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + ETH2_EL_CLIENT: ${{matrix.client}} + CHAINLINK_VERSION: ${{ github.sha }} + run: | + convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" + } + + selected_networks=$(convert_to_toml_array "$SELECTED_NETWORKS") + + if [ -n "$ETH2_EL_CLIENT" ]; then + execution_layer="$ETH2_EL_CLIENT" + else + execution_layer="geth" + fi + + if [ -n "$PYROSCOPE_SERVER" ]; then + pyroscope_enabled=true + else + pyroscope_enabled=false + fi + + cat << EOF > config.toml + [Network] + selected_networks=$selected_networks + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="$CHAINLINK_VERSION" + + [Pyroscope] + enabled=$pyroscope_enabled + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + + [PrivateEthereumNetwork] + consensus_type="pos" + consensus_layer="prysm" + execution_layer="$execution_layer" + wait_for_finalization=false + + [PrivateEthereumNetwork.EthereumChainConfig] + chain_id=1337 + genesis_delay=15 + seconds_per_slot=3 + validator_count=8 + slots_per_epoch=2 + addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + touch .root_dir + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@912bed7e07a1df4d06ea53a031e9773bb65dc7bd # v2.3.0 + with: + test_command_to_run: ./tests -test.timeout ${{ matrix.timeout }} -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + + start-slack-thread: + name: Start Slack Thread + if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} + environment: integration + outputs: + thread_ts: ${{ steps.slack.outputs.thread_ts }} + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + runs-on: ubuntu-latest + needs: [client-compatibility-matrix] + steps: + - name: Debug Result + run: echo ${{ join(needs.*.result, ',') }} + - name: Main Slack Notification + uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + id: slack + with: + channel-id: ${{ secrets.QA_SLACK_CHANNEL }} + payload: | + { + "attachments": [ + { + "color": "${{ contains(join(needs.*.result, ','), 'failure') && '#C62828' || '#2E7D32' }}", + "blocks": [ + { + "type": "header", + "text": { + "type": "plain_text", + "text": "Client Compatability Test Results ${{ contains(join(needs.*.result, ','), 'failure') && ':x:' || ':white_check_mark:'}}", + "emoji": true + } + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "${{ contains(join(needs.*.result, ','), 'failure') && 'Some tests failed, notifying <@U060CGGPY8H>' || 'All Good!' }}" + } + }, + { + "type": "divider" + }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "<${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ github.ref_name }}|${{ github.ref_name }}> | <${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}> | <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Run>" + } + } + ] + } + ] + } + env: + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + + post-test-results-to-slack: + name: Post Test Results for ${{matrix.product}} + if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + runs-on: ubuntu-latest + needs: start-slack-thread + strategy: + fail-fast: false + matrix: + product: [ocr, ocr2] + steps: + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Post Test Results to Slack + uses: ./.github/actions/notify-slack-jobs-result + with: + github_token: ${{ github.token }} + github_repository: ${{ github.repository }} + workflow_run_id: ${{ github.run_id }} + github_job_name_regex: ^Client Compatibility Test ${{ matrix.product }}-(?.*?)$ + message_title: ${{ matrix.product }} + slack_channel_id: ${{ secrets.QA_SLACK_CHANNEL }} + slack_bot_token: ${{ secrets.QA_SLACK_API_KEY }} + slack_thread_ts: ${{ needs.start-slack-thread.outputs.thread_ts }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8bc066f408c..fea4260fdc9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -13,7 +13,7 @@ on: jobs: analyze: name: Analyze ${{ matrix.language }} - runs-on: ubuntu20.04-4cores-16GB + runs-on: ubuntu-latest strategy: fail-fast: false @@ -26,7 +26,7 @@ jobs: - name: Set up Go if: ${{ matrix.language == 'go' }} - uses: actions/setup-go@v4 + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version-file: 'go.mod' diff --git a/.github/workflows/dependency-check.yml b/.github/workflows/dependency-check.yml index dbf08895757..0143042abd9 100644 --- a/.github/workflows/dependency-check.yml +++ b/.github/workflows/dependency-check.yml @@ -29,7 +29,7 @@ jobs: - name: Set up Go if: needs.changes.outputs.src == 'true' - uses: actions/setup-go@v4 + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version-file: 'go.mod' id: go diff --git a/.github/workflows/helm-publish.yml b/.github/workflows/helm-chart-publish.yml similarity index 92% rename from .github/workflows/helm-publish.yml rename to .github/workflows/helm-chart-publish.yml index 6ea46e6a52d..156268d66b0 100644 --- a/.github/workflows/helm-publish.yml +++ b/.github/workflows/helm-chart-publish.yml @@ -31,7 +31,7 @@ jobs: uses: azure/setup-helm@5119fcb9089d432beecbf79bb2c7915207344b78 # v3.5 - name: Run chart-releaser - uses: helm/chart-releaser-action@be16258da8010256c6e82849661221415f031968 # v1.5.0 + uses: helm/chart-releaser-action@a917fd15b20e8b64b94d9158ad54cd6345335584 # v1.6.0 with: charts_dir: charts config: .github/cr.yaml diff --git a/.github/workflows/helm-chart.yml b/.github/workflows/helm-chart.yml new file mode 100644 index 00000000000..c988d14f30c --- /dev/null +++ b/.github/workflows/helm-chart.yml @@ -0,0 +1,25 @@ +name: Helm Chart + +on: + pull_request: + paths: + - "charts/**" + - ".github/workflows/helm-chart.yml" + +jobs: + ci-lint-helm-charts: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + actions: read + steps: + - name: ci-lint-helm-charts + uses: smartcontractkit/.github/actions/ci-lint-charts@9fd15fe8e698a5e28bfd06b3a91471c56568dcb3 # ci-lint-charts@0.1.1 + with: + # chart testing inputs + chart-testing-extra-args: "--lint-conf=lintconf.yaml" + # grafana inputs + metrics-job-name: ci-lint-helm-charts + gc-basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + gc-host: ${{ secrets.GRAFANA_CLOUD_HOST }} diff --git a/.github/workflows/integration-chaos-tests.yml b/.github/workflows/integration-chaos-tests.yml index 10c62810996..82af083543e 100644 --- a/.github/workflows/integration-chaos-tests.yml +++ b/.github/workflows/integration-chaos-tests.yml @@ -12,7 +12,6 @@ env: ENV_JOB_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests:${{ github.sha }} TEST_SUITE: chaos TEST_ARGS: -test.timeout 1h - SELECTED_NETWORKS: SIMULATED CHAINLINK_COMMIT_SHA: ${{ github.sha }} CHAINLINK_ENV_USER: ${{ github.actor }} TEST_LOG_LEVEL: debug @@ -108,6 +107,24 @@ jobs: continue-on-error: true - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Prepare Base64 TOML config + env: + CHAINLINK_VERSION: ${{ github.sha }} + run: | + echo ::add-mask::$CHAINLINK_IMAGE + + cat << EOF > config.toml + [Network] + selected_networks=["SIMULATED"] + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="$CHAINLINK_VERSION" + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: diff --git a/.github/workflows/integration-staging-tests.yml b/.github/workflows/integration-staging-tests.yml index 2abb9a3cfae..ea0691b7ca5 100644 --- a/.github/workflows/integration-staging-tests.yml +++ b/.github/workflows/integration-staging-tests.yml @@ -1,3 +1,4 @@ +# NEEDS ADJUSTING TO TOML CONFIG BEFORE USING!! name: E2E Functions staging tests on: @@ -41,18 +42,86 @@ jobs: env: LOKI_URL: ${{ secrets.LOKI_URL }} LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }} - SELECTED_NETWORKS: ${{ inputs.network }} SELECTED_TEST: ${{ inputs.test_type }} MUMBAI_URLS: ${{ secrets.FUNCTIONS_STAGING_MUMBAI_URLS }} MUMBAI_KEYS: ${{ secrets.FUNCTIONS_STAGING_MUMBAI_KEYS }} - WASP_LOG_LEVEL: info steps: - name: Checkout code uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 + - name: Prepare Base64 TOML override + env: + PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} + PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + run: | + convert_to_toml_array() { + local IFS=',' + local input_array=($1) + local toml_array_format="[" + + for element in "${input_array[@]}"; do + toml_array_format+="\"$element\"," + done + + toml_array_format="${toml_array_format%,}]" + echo "$toml_array_format" + } + + if [ -n "$PYROSCOPE_SERVER" ]; then + pyroscope_enabled=true + else + pyroscope_enabled=false + fi + + cat << EOF > config.toml + [Common] + chainlink_node_funding=0.5 + + [ChainlinkImage] + image="$CHAINLINK_IMAGE" + version="${{ github.sha }}" + + [Pyroscope] + enabled=$pyroscope_enabled + server_url="$PYROSCOPE_SERVER" + environment="$PYROSCOPE_ENVIRONMENT" + key="$PYROSCOPE_KEY" + + [Logging] + run_id="$RUN_ID" + + [Logging.LogStream] + log_targets=$log_targets + + [Logging.Loki] + tenant_id="$LOKI_TENANT_ID" + endpoint="$LOKI_URL" + basic_auth="$LOKI_BASIC_AUTH" + + [Logging.Grafana] + base_url="$GRAFANA_URL" + dashboard_url="/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + + [Network] + selected_networks=["sepolia"] + + [Network.RpcHttpUrls] + sepolia = $(convert_to_toml_array "$SEPOLIA_HTTP_URLS") + + [Network.RpcWsUrls] + sepolia = $(convert_to_toml_array "$SEPOLIA_URLS") + + [Network.WalletKeys] + sepolia = $(convert_to_toml_array "$EVM_KEYS") + EOF + + BASE64_CONFIG_OVERRIDE=$(cat config.toml | base64 -w 0) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV - name: Run E2E soak tests run: | cd integration-tests/load/functions diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index e51d783a6ed..08ecd670a4d 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -45,7 +45,7 @@ jobs: echo "should-enforce=$SHOULD_ENFORCE" >> $GITHUB_OUTPUT - name: Enforce CTF Version if: steps.condition-check.outputs.should-enforce == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/mod-version@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: go-project-path: ./integration-tests module-name: github.com/smartcontractkit/chainlink-testing-framework @@ -87,7 +87,7 @@ jobs: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Go - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download go_mod_path: ./integration-tests/go.mod @@ -97,7 +97,7 @@ jobs: run: | cd ./integration-tests go build ./... - SELECTED_NETWORKS=SIMULATED go test -run=^# ./... + go test -run=^# ./... - name: Lint Go uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: @@ -121,15 +121,15 @@ jobs: - name: "" dockerfile: core/chainlink.Dockerfile tag-suffix: "" - - name: (plugins) - dockerfile: plugins/chainlink.Dockerfile - tag-suffix: -plugins + # - name: (plugins) + # dockerfile: plugins/chainlink.Dockerfile + # tag-suffix: -plugins name: Build Chainlink Image ${{ matrix.image.name }} runs-on: ubuntu20.04-16cores-64GB needs: [changes, enforce-ctf-version] steps: - name: Collect Metrics - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: @@ -142,7 +142,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Chainlink Image - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' uses: ./.github/actions/build-chainlink-image with: tag_suffix: ${{ matrix.image.tag-suffix }} @@ -164,7 +164,7 @@ jobs: needs: [changes] steps: - name: Collect Metrics - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: @@ -177,7 +177,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Test Image - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' uses: ./.github/actions/build-test-image with: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} @@ -189,7 +189,8 @@ jobs: runs-on: ubuntu-latest name: Compare/Build Automation Test List outputs: - matrix: ${{ env.MATRIX_JSON }} + automation-matrix: ${{ env.AUTOMATION_JOB_MATRIX_JSON }} + lp-matrix: ${{ env.LP_JOB_MATRIX_JSON }} steps: - name: Check for Skip Tests Label if: contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') @@ -203,24 +204,44 @@ jobs: cd ./integration-tests ./scripts/compareTestList.sh ./smoke/automation_test.go ./scripts/compareTestList.sh ./smoke/keeper_test.go + ./scripts/compareTestList.sh ./smoke/log_poller_test.go - name: Build Test Matrix Lists id: build-test-matrix-list run: | cd ./integration-tests - MATRIX_JSON_AUTOMATION=$(./scripts/buildTestMatrixList.sh ./smoke/automation_test.go automation ubuntu20.04-8cores-32GB 1) - MATRIX_JSON_KEEPER=$(./scripts/buildTestMatrixList.sh ./smoke/keeper_test.go keeper ubuntu20.04-8cores-32GB 1) + MATRIX_JSON_AUTOMATION=$(./scripts/buildTestMatrixList.sh ./smoke/automation_test.go automation ubuntu-latest 1) + MATRIX_JSON_KEEPER=$(./scripts/buildTestMatrixList.sh ./smoke/keeper_test.go keeper ubuntu-latest 1) COMBINED_ARRAY=$(jq -c -n "$MATRIX_JSON_AUTOMATION + $MATRIX_JSON_KEEPER") - echo "MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV + + LOG_POLLER_MATRIX_JSON=$(./scripts/buildTestMatrixList.sh ./smoke/log_poller_test.go log_poller ubuntu-latest 1) + echo "LP_JOB_MATRIX_JSON=${LOG_POLLER_MATRIX_JSON}" >> $GITHUB_ENV + + # if we running a PR against the develop branch we should only run the automation tests unless we are in the merge group event + if [[ "$GITHUB_EVENT_NAME" == "merge_group" ]]; then + echo "We are in a merge_group event, run both automation and keepers tests" + echo "AUTOMATION_JOB_MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV + else + echo "we are not in a merge_group event, if this is a PR to develop run only automation tests, otherwise run everything because we could be running against a release branch" + target_branch=$(cat $GITHUB_EVENT_PATH | jq -r .pull_request.base.ref) + if [[ "$target_branch" == "develop" ]]; then + echo "only run automation tests" + echo "AUTOMATION_JOB_MATRIX_JSON=${MATRIX_JSON_AUTOMATION}" >> $GITHUB_ENV + else + echo "run both automation and keepers tests" + echo "AUTOMATION_JOB_MATRIX_JSON=${COMBINED_ARRAY}" >> $GITHUB_ENV + fi + fi eth-smoke-tests-matrix-automation: - if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || (github.event_name == 'workflow_dispatch' && !inputs.simulatedNetwork)) }} + if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} environment: integration permissions: checks: write pull-requests: write id-token: write contents: read - needs: [build-chainlink, changes, compare-tests, build-lint-integration-tests] + needs: + [build-chainlink, changes, compare-tests, build-lint-integration-tests] env: SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 CHAINLINK_COMMIT_SHA: ${{ github.sha }} @@ -229,10 +250,20 @@ jobs: strategy: fail-fast: false matrix: - product: ${{fromJson(needs.compare-tests.outputs.matrix)}} + product: ${{fromJson(needs.compare-tests.outputs.automation-matrix)}} runs-on: ${{ matrix.product.os }} name: ETH Smoke Tests ${{ matrix.product.name }} steps: + - name: Collect Metrics + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: ETH Smoke Tests ${{ matrix.product.name }} + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: @@ -246,14 +277,28 @@ jobs: else echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT" fi + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + selectedNetworks: ${{ env.SELECTED_NETWORKS }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ${{ matrix.product.pyroscope_env }} + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + ## Run this step when changes that require tests to be run are made - name: Run Tests - if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - env: - PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 - PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -269,8 +314,34 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: "" - - name: Collect Metrics + - name: Print failed test summary if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + + eth-smoke-tests-matrix-log-poller: + if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || github.event_name == 'workflow_dispatch') }} + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: + [build-chainlink, changes, compare-tests, build-lint-integration-tests] + env: + SELECTED_NETWORKS: SIMULATED,SIMULATED_1,SIMULATED_2 + CHAINLINK_COMMIT_SHA: ${{ github.sha }} + CHAINLINK_ENV_USER: ${{ github.actor }} + TEST_LOG_LEVEL: debug + strategy: + fail-fast: false + matrix: + product: ${{fromJson(needs.compare-tests.outputs.lp-matrix)}} + runs-on: ${{ matrix.product.os }} + name: ETH Smoke Tests ${{ matrix.product.name }} + steps: + - name: Collect Metrics + if: needs.changes.outputs.src == 'true' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: @@ -279,9 +350,58 @@ jobs: this-job-name: ETH Smoke Tests ${{ matrix.product.name }} test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Build Go Test Command + id: build-go-test-command + run: | + # if the matrix.product.run is set, use it for a different command + if [ "${{ matrix.product.run }}" != "" ]; then + echo "run_command=${{ matrix.product.run }} ./smoke/${{ matrix.product.file }}_test.go" >> "$GITHUB_OUTPUT" + else + echo "run_command=./smoke/${{ matrix.product.name }}_test.go" >> "$GITHUB_OUTPUT" + fi + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + selectedNetworks: ${{ env.SELECTED_NETWORKS }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ${{ matrix.product.pyroscope_env }} + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + ## Run this step when changes that require tests to be run are made + - name: Run Tests + if: needs.changes.outputs.src == 'true' + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + with: + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_location: ./integration-tests/smoke/logs/ + publish_check_name: ${{ matrix.product.name }} + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: "" eth-smoke-tests-matrix: - if: ${{ !(contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') || (github.event_name == 'workflow_dispatch' && !inputs.simulatedNetwork)) }} + if: ${{ !contains(join(github.event.pull_request.labels.*.name, ' '), 'skip-smoke-tests') }} environment: integration permissions: checks: write @@ -298,54 +418,66 @@ jobs: fail-fast: false matrix: product: + - name: runlog + nodes: 2 + os: ubuntu-latest + pyroscope_env: "ci-smoke-runlog-evm-simulated" - name: cron - nodes: 1 + nodes: 2 os: ubuntu-latest - pyroscope_env: "" + pyroscope_env: "ci-smoke-cron-evm-simulated" - name: flux nodes: 1 os: ubuntu-latest - pyroscope_env: "" + pyroscope_env: "ci-smoke-flux-evm-simulated" - name: ocr - nodes: 1 - os: ubuntu20.04-8cores-32GB + nodes: 2 + os: ubuntu-latest + file: ocr pyroscope_env: ci-smoke-ocr-evm-simulated - name: ocr2 - nodes: 1 - os: ubuntu20.04-8cores-32GB + nodes: 6 + os: ubuntu-latest + file: ocr2 pyroscope_env: ci-smoke-ocr2-evm-simulated - name: ocr2 - nodes: 1 - os: ubuntu20.04-8cores-32GB - pyroscope_env: ci-smoke-ocr2-evm-simulated - tag_suffix: "-plugins" - - name: runlog - nodes: 1 + nodes: 6 os: ubuntu-latest - pyroscope_env: "" + pyroscope_env: ci-smoke-ocr2-plugins-evm-simulated + tag_suffix: "-plugins" - name: vrf - nodes: 1 - os: ubuntu20.04-8cores-32GB + nodes: 2 + os: ubuntu-latest pyroscope_env: ci-smoke-vrf-evm-simulated - name: vrfv2 - nodes: 1 - os: ubuntu20.04-8cores-32GB + nodes: 3 + os: ubuntu-latest pyroscope_env: ci-smoke-vrf2-evm-simulated - name: vrfv2plus - nodes: 1 - os: ubuntu20.04-8cores-32GB + nodes: 3 + os: ubuntu-latest pyroscope_env: ci-smoke-vrf2plus-evm-simulated - name: forwarder_ocr - nodes: 1 - os: ubuntu20.04-8cores-32GB + nodes: 2 + os: ubuntu-latest pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated - name: forwarders_ocr2 - nodes: 1 - os: ubuntu20.04-8cores-32GB + nodes: 2 + os: ubuntu-latest pyroscope_env: ci-smoke-forwarder-ocr-evm-simulated runs-on: ${{ matrix.product.os }} name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} steps: + - name: Collect Metrics + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' + id: collect-gha-metrics + uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 + with: + basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} + hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} + this-job-name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} + test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + continue-on-error: true - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: @@ -410,22 +542,35 @@ jobs: - name: Show Otel-Collector Logs if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | - docker logs otel-collector + docker logs otel-collector + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + selectedNetworks: ${{ env.SELECTED_NETWORKS }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ${{ matrix.product.pyroscope_env }} + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" ## Run this step when changes that require tests to be run are made - name: Run Tests - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - env: - PYROSCOPE_SERVER: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 - PYROSCOPE_ENVIRONMENT: ${{ matrix.product.pyroscope_env }} - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download cl_repo: ${{ env.CHAINLINK_IMAGE }} cl_image_tag: ${{ github.sha }}${{ matrix.product.tag_suffix }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - artifacts_name: ${{ matrix.product.name }}-test-logs + artifacts_name: ${{ matrix.product.name }}${{ matrix.product.tag_suffix }}-test-logs artifacts_location: ./integration-tests/smoke/logs/ publish_check_name: ${{ matrix.product.name }} token: ${{ secrets.GITHUB_TOKEN }} @@ -435,10 +580,10 @@ jobs: QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: "" - ## Run this step when changes that do not need the test to run are made + # Run this step when changes that do not need the test to run are made - name: Run Setup if: needs.changes.outputs.src == 'false' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_download_vendor_packages_command: cd ./integration-tests && go mod download go_mod_path: ./integration-tests/go.mod @@ -450,28 +595,22 @@ jobs: - name: Show Otel-Collector Logs if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | - docker logs otel-collector - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: ETH Smoke Tests ${{ matrix.product.name }}${{ matrix.product.tag_suffix }} - test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' - continue-on-error: true + docker logs otel-collector - name: Permissions on traces if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' run: | - ls -l ./integration-tests/smoke/traces + ls -l ./integration-tests/smoke/traces - name: Upload Trace Data if: steps.check-label.outputs.trace == 'true' && matrix.product.name == 'ocr2' && matrix.product.tag_suffix == '-plugins' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 with: name: trace-data path: ./integration-tests/smoke/traces/trace-data.json - + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: ./integration-tests/smoke/ ### Used to check the required checks box when the matrix completes eth-smoke-tests: @@ -479,6 +618,7 @@ jobs: runs-on: ubuntu-latest name: ETH Smoke Tests needs: [eth-smoke-tests-matrix, eth-smoke-tests-matrix-automation] + # needs: [eth-smoke-tests-matrix] steps: - name: Check smoke test matrix status if: needs.eth-smoke-tests-matrix.result != 'success' || needs.eth-smoke-tests-matrix-automation.result != 'success' @@ -537,7 +677,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Run Setup - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-go@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_download_vendor_packages_command: | cd ./integration-tests @@ -584,8 +724,16 @@ jobs: - name: Name Versions run: | echo "Running migration tests from version '${{ steps.get_latest_version.outputs.latest_version }}' to: '${{ github.sha }}'" + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-upgrade-config + with: + selectedNetworks: ${{ env.SELECTED_NETWORKS }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ steps.get_latest_version.outputs.latest_version }} + upgradeImage: ${{ env.UPGRADE_IMAGE }} + upgradeVersion: ${{ env.UPGRADE_VERSION }} - name: Run Migration Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download @@ -619,7 +767,7 @@ jobs: test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' continue-on-error: true - ### Solana Section + ## Solana Section get_solana_sha: name: Get Solana Sha From Go Mod environment: Integration @@ -697,7 +845,7 @@ jobs: steps: - name: Check if image exists id: check-image - uses: smartcontractkit/chainlink-github-actions/docker/image-exists@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + uses: smartcontractkit/chainlink-github-actions/docker/image-exists@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: repository: chainlink-solana-tests tag: ${{ needs.get_solana_sha.outputs.sha }} @@ -727,7 +875,7 @@ jobs: FORCE_COLOR: 1 steps: - name: Collect Metrics - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: @@ -743,8 +891,8 @@ jobs: repository: smartcontractkit/chainlink-solana ref: ${{ needs.get_solana_sha.outputs.sha }} - name: Build contracts - if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' - uses: smartcontractkit/chainlink-solana/.github/actions/build_contract_artifacts@23816fcf7d380a30c87b6d87e4fb0ca94419b259 # stable action on April 17 2023 + if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false' + uses: smartcontractkit/chainlink-solana/.github/actions/build_contract_artifacts@21675b3a7dcdff8e790391708d4763020cace21e # stable action on December 18 2023 with: ref: ${{ needs.get_solana_sha.outputs.sha }} @@ -768,7 +916,7 @@ jobs: CONTRACT_ARTIFACTS_PATH: contracts/target/deploy steps: - name: Collect Metrics - if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' + if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: @@ -777,13 +925,13 @@ jobs: this-job-name: Solana Build Test Image continue-on-error: true - name: Checkout the repo - if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' + if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false' uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: repository: smartcontractkit/chainlink-solana ref: ${{ needs.get_solana_sha.outputs.sha }} - name: Build Test Image - if: needs.changes.outputs.src == 'true' && needs.solana-test-image-exists.outputs.exists == 'false' + if: (needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch') && needs.solana-test-image-exists.outputs.exists == 'false' uses: ./.github/actions/build-test-image with: tag: ${{ needs.get_solana_sha.outputs.sha }} @@ -819,7 +967,7 @@ jobs: CONTRACT_ARTIFACTS_PATH: contracts/target/deploy steps: - name: Collect Metrics - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: @@ -834,8 +982,8 @@ jobs: repository: smartcontractkit/chainlink-solana ref: a28100b7f2954604a8ca2ff9ec7bccc6ec952953 # temporarily using specific commit for release branch ${{ needs.get_solana_sha.outputs.sha }} - name: Run Setup - if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/setup-run-tests-environment@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: go_mod_path: ./integration-tests/go.mod cache_restore_only: true @@ -847,7 +995,7 @@ jobs: QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Pull Artfacts - if: needs.changes.outputs.src == 'true' + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' run: | IMAGE_NAME=${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-solana-tests:${{ needs.get_solana_sha.outputs.sha }} # Pull the Docker image @@ -863,8 +1011,8 @@ jobs: # Remove the created container docker rm "$CONTAINER_ID" - name: Run Tests - if: needs.changes.outputs.src == 'true' - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 + if: needs.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: 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 }} diff --git a/.github/workflows/live-testnet-tests.yml b/.github/workflows/live-testnet-tests.yml index f174e8847bd..45207fad3ce 100644 --- a/.github/workflows/live-testnet-tests.yml +++ b/.github/workflows/live-testnet-tests.yml @@ -1,7 +1,16 @@ +# *** +# This workflow is a monstrosity of copy-paste, and that's to increase legibility in reporting and running, so the code be damned. +# I suspect this can be cleaned up significantly with some clever trickery of the GitHub actions matrices, but I am not that clever. +# We want each chain to run in parallel, but each test within the chain needs to be able to run sequentially +# (we're trying to eliminate this as a requirement, should make it a lot easier). +# Each chain can have a variety of tests to run. +# We also want reporting to be clear in the start-slack-thread and post-test-results-to-slack jobs. +# *** + name: Live Testnet Tests on: schedule: - - cron: "0 0 * * *" # Run nightly + - cron: "0 5 * * *" # Run every night at midnight EST push: tags: - "*" @@ -11,30 +20,30 @@ env: CHAINLINK_IMAGE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink INTERNAL_DOCKER_REPO: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com MOD_CACHE_VERSION: 2 - CHAINLINK_NODE_FUNDING: .1 + CHAINLINK_NODE_FUNDING: .5 + PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + LOKI_TENANT_ID: ${{ vars.LOKI_TENANT_ID }} + LOKI_URL: ${{ secrets.LOKI_URL }} + LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} + LOGSTREAM_LOG_TARGETS: loki + GRAFANA_URL: ${{ vars.GRAFANA_URL }} + RUN_ID: ${{ github.run_id }} CHAINLINK_COMMIT_SHA: ${{ github.sha }} CHAINLINK_ENV_USER: ${{ github.actor }} TEST_LOG_LEVEL: debug - EVM_KEYS: ${{ secrets.QA_EVM_KEYS }} - - SEPOLIA_URLS: ${{ secrets.QA_SEPOLIA_URLS }} - SEPOLIA_HTTP_URLS: ${{ secrets.QA_SEPOLIA_HTTP_URLS }} - OPTIMISM_GOERLI_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_URLS }} - OPTIMISM_GOERLI_HTTP_URLS: ${{ secrets.QA_OPTIMISM_GOERLI_HTTP_URLS }} +jobs: - ARBITRUM_GOERLI_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_URLS }} - ARBITRUM_GOERLI_HTTP_URLS: ${{ secrets.QA_ARBITRUM_GOERLI_HTTP_URLS }} + # Build Test Dependencies -jobs: build-chainlink: environment: integration permissions: id-token: write contents: read name: Build Chainlink Image - runs-on: ubuntu20.04-16cores-64GB + runs-on: ubuntu-latest steps: - name: Collect Metrics id: collect-gha-metrics @@ -50,7 +59,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - name: Build Chainlink Image uses: ./.github/actions/build-chainlink-image - with: + with: tag_suffix: "" dockerfile: core/chainlink.Dockerfile git_commit_sha: ${{ github.sha }} @@ -59,188 +68,42 @@ jobs: AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - # TODO: Re-enable when we have secrets properly configured - # sepolia-smoke-tests: - # environment: integration - # permissions: - # checks: write - # pull-requests: write - # id-token: write - # contents: read - # needs: [build-chainlink] - # env: - # SELECTED_NETWORKS: SEPOLIA - # strategy: - # max-parallel: 1 - # fail-fast: false - # matrix: - # include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations - # - product: OCR - # test: TestOCRBasic - # - product: Automation - # test: TestAutomationBasic/registry_2_0 - # name: Sepolia ${{ matrix.product }} Tests - # runs-on: ubuntu-latest - # steps: - # - name: Checkout the repo - # uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - # with: - # ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - # - name: Run Tests - # uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - # env: - # PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - # PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-sepolia - # PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - # with: - # test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 -run ${{ matrix.test }} ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt - # test_download_vendor_packages_command: cd ./integration-tests && go mod download - # cl_repo: ${{ env.CHAINLINK_IMAGE }} - # cl_image_tag: ${{ github.sha }} - # aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - # dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - # dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - # artifacts_location: ./integration-tests/smoke/logs - # publish_check_name: Seplia ${{ matrix.product }} Smoke Test Results - # token: ${{ secrets.GITHUB_TOKEN }} - # go_mod_path: ./integration-tests/go.mod - # cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - # cache_restore_only: "true" - # QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - # QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - # QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - # - name: Collect Metrics - # if: always() - # id: collect-gha-metrics - # uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - # with: - # basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - # hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - # this-job-name: Sepolia ${{ matrix.product }} Tests - # test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' - # continue-on-error: true - - optimism-goerli-smoke-tests: + build-tests: environment: integration permissions: - checks: write - pull-requests: write id-token: write contents: read - needs: [build-chainlink] - env: - SELECTED_NETWORKS: OPTIMISM_GOERLI - strategy: - fail-fast: false - max-parallel: 1 - matrix: - include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations - - product: OCR - test: TestOCRBasic - - product: Automation - test: TestAutomationBasic/registry_2_0 - name: Optimism Goerli ${{ matrix.product }} Tests + name: Build Tests Binary runs-on: ubuntu-latest steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-optimism-goerli - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} - with: - test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 -run ${{ matrix.test }} ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt - test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - artifacts_location: ./integration-tests/smoke/logs - publish_check_name: Seplia ${{ matrix.product }} Smoke Test Results - token: ${{ secrets.GITHUB_TOKEN }} - go_mod_path: ./integration-tests/go.mod - cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} - cache_restore_only: "true" - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - name: Collect Metrics - if: always() id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 with: basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Optimism Goerli ${{ matrix.product }} Tests - test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' + this-job-name: Build Tests Binary continue-on-error: true - - arbitrum-goerli-smoke-tests: - environment: integration - permissions: - checks: write - pull-requests: write - id-token: write - contents: read - needs: [build-chainlink] - env: - SELECTED_NETWORKS: ARBITRUM_GOERLI - strategy: - max-parallel: 1 - fail-fast: false - matrix: - include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations - - product: OCR - test: TestOCRBasic - - product: Automation - test: TestAutomationBasic/registry_2_0 - name: Arbitrum Goerli ${{ matrix.product }} Tests - runs-on: ubuntu-latest - steps: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - env: - PYROSCOPE_SERVER: ${{ secrets.QA_PYROSCOPE_INSTANCE }} - PYROSCOPE_ENVIRONMENT: ci-smoke-${{ matrix.product }}-arbitrum-goerli - PYROSCOPE_KEY: ${{ secrets.QA_PYROSCOPE_KEY }} + - name: Build Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/build-tests@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 with: - test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=1 -run ${{ matrix.test }} ./smoke 2>&1 | tee /tmp/gotest.log | gotestfmt test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ env.CHAINLINK_IMAGE }} - cl_image_tag: ${{ github.sha }} - aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} - dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} - dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} - artifacts_location: ./integration-tests/smoke/logs - publish_check_name: Arbitrum Goerli ${{ matrix.product }} Smoke Test Results token: ${{ secrets.GITHUB_TOKEN }} go_mod_path: ./integration-tests/go.mod + go_tags: embed cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} cache_restore_only: "true" - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Arbitrum Goerli ${{ matrix.product }} Tests - test-results-file: '{"testType":"go","filePath":"/tmp/gotest.log"}' - continue-on-error: true + binary_name: tests - testnet-smoke-tests-notify: + # End Build Test Dependencies + + # Reporting Jobs + + start-slack-thread: name: Start Slack Thread if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} environment: integration @@ -252,7 +115,7 @@ jobs: id-token: write contents: read runs-on: ubuntu-latest - needs: [optimism-goerli-smoke-tests, arbitrum-goerli-smoke-tests] + needs: [sepolia-smoke-tests, optimism-sepolia-smoke-tests, arbitrum-sepolia-smoke-tests, base-sepolia-smoke-tests, polygon-mumbai-smoke-tests, avalanche-fuji-smoke-tests, fantom-testnet-smoke-tests, celo-alfajores-smoke-tests, linea-goerli-smoke-tests] steps: - name: Debug Result run: echo ${{ join(needs.*.result, ',') }} @@ -275,6 +138,13 @@ jobs: "emoji": true } }, + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "${{ contains(join(needs.*.result, ','), 'failure') && 'Some tests failed, notifying <@U01Q4N37KFG>' || 'All Good!' }}" + } + }, { "type": "divider" }, @@ -292,7 +162,7 @@ jobs: env: SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} - testnet-smoke-tests-results: + post-test-results-to-slack: name: Post Test Results for ${{ matrix.network }} if: ${{ always() && needs.*.result != 'skipped' && needs.*.result != 'cancelled' }} environment: integration @@ -302,84 +172,806 @@ jobs: id-token: write contents: read runs-on: ubuntu-latest - needs: testnet-smoke-tests-notify + needs: start-slack-thread strategy: fail-fast: false matrix: - network: [Optimism Goerli, Arbitrum Goerli] + network: [Sepolia, Optimism Sepolia, Arbitrum Sepolia, Base Sepolia, Polygon Mumbai, Avalanche Fuji, Fantom Testnet, Celo Alfajores, Linea Goerli] steps: - - name: Get Results - id: test-results - run: | - # I feel like there's some clever, fully jq way to do this, but I ain't got the motivation to figure it out - echo "Querying test results" + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} + - name: Post Test Results + uses: ./.github/actions/notify-slack-jobs-result + with: + github_token: ${{ github.token }} + github_repository: ${{ github.repository }} + workflow_run_id: ${{ github.run_id }} + github_job_name_regex: ^${{ matrix.network }} (?.*?) Tests$ + message_title: ${{ matrix.network }} + slack_channel_id: ${{ secrets.QA_SLACK_CHANNEL }} + slack_bot_token: ${{ secrets.QA_SLACK_API_KEY }} + slack_thread_ts: ${{ needs.start-slack-thread.outputs.thread_ts }} - PARSED_RESULTS=$(curl \ - -H "Authorization: Bearer ${{ github.token }}" \ - 'https://api.github.com/repos/${{github.repository}}/actions/runs/${{ github.run_id }}/jobs' \ - | jq -r --arg pattern "${{ matrix.network }} (?\\w+) Tests" '.jobs[] - | select(.name | test($pattern)) as $job - | $job.steps[] - | select(.name == "Run Tests") - | { conclusion: (if .conclusion == "success" then ":white_check_mark:" else ":x:" end), product: ("*" + ($job.name | capture($pattern).product) + "*") }') + # End Reporting Jobs + + sepolia-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-sepolia + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "sepolia" + httpEndpoints: ${{ secrets.QA_SEPOLIA_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_SEPOLIA_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" - echo "Parsed Results:" - echo $PARSED_RESULTS + bsc-testnet-tests: + # TODO: BSC RPCs are all in a bad state right now, so we're skipping these tests until they're fixed + if: false + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: BSC Testnet ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-bsc-testnet + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "bsc_testnet" + httpEndpoints: ${{ secrets.QA_BSC_TESTNET_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_BSC_TESTNET_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" - ALL_SUCCESS=true - for row in $(echo "$PARSED_RESULTS" | jq -s | jq -r '.[] | select(.conclusion != ":white_check_mark:")'); do - success=false - break - done + optimism-sepolia-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Optimism Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-optimism-sepolia + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "optimism_sepolia" + httpEndpoints: ${{ secrets.QA_OPTIMISM_SEPOLIA_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_OPTIMISM_SEPOLIA_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" - echo all_success=$ALL_SUCCESS >> $GITHUB_OUTPUT + arbitrum-sepolia-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Arbitrum Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-arbitrum-sepolia + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "arbitrum_sepolia" + httpEndpoints: ${{ secrets.QA_ARBITRUM_SEPOLIA_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_ARBITRUM_SEPOLIA_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" - FORMATTED_RESULTS=$(echo $PARSED_RESULTS | jq -s '[.[] - | { - conclusion: .conclusion, - product: .product - } - ] - | map("{\"type\": \"section\", \"text\": {\"type\": \"mrkdwn\", \"text\": \"\(.product): \(.conclusion)\"}}") - | join(",")') + base-sepolia-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + name: Base Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-base-sepolia + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "base_sepolia" + httpEndpoints: ${{ secrets.QA_BASE_SEPOLIA_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_BASE_SEPOLIA_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" - echo "Formatted Results:" - echo $FORMATTED_RESULTS + polygon-mumbai-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Polygon Mumbai ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-polygon-mumbai + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "polygon_mumbai" + httpEndpoints: ${{ secrets.QA_POLYGON_MUMBAI_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_POLYGON_MUMBAI_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" + + avalanche-fuji-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Avalanche Fuji ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-avalanche-fuji + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "avalanche_fuji" + httpEndpoints: ${{ secrets.QA_AVALANCHE_FUJI_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_AVALANCHE_FUJI_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" - # Cleans out backslashes and quotes from jq - CLEAN_RESULTS=$(echo "$FORMATTED_RESULTS" | sed 's/\\\"/"/g' | sed 's/^"//;s/"$//') + fantom-testnet-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + - product: Automation Conditional + test: TestAutomationBasic/registry_2_1_conditional + - product: Automation Log Trigger + test: TestAutomationBasic/registry_2_1_logtrigger + name: Fantom Testnet ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-fantom-testnet + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "fantom_testnet" + httpEndpoints: ${{ secrets.QA_FANTOM_TESTNET_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_FANTOM_TESTNET_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" - echo "Clean Results" - echo $CLEAN_RESULTS + celo-alfajores-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + name: Celo Alfajores ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-celo-alfajores + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "celo_alfajores" + httpEndpoints: ${{ secrets.QA_CELO_ALFAJORES_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_CELO_ALFAJORES_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" - echo results=$CLEAN_RESULTS >> $GITHUB_OUTPUT + scroll-sepolia-smoke-tests: + # TODO: Disabled until bug TT-767 is fixed + if: false + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + name: Scroll Sepolia ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-scroll-sepolia + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "scroll_sepolia" + httpEndpoints: ${{ secrets.QA_SCROLL_SEPOLIA_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_SCROLL_SEPOLIA_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" - - name: Test Details - uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0 + linea-goerli-smoke-tests: + environment: integration + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + needs: [build-chainlink, build-tests] + strategy: + max-parallel: 1 + fail-fast: false + matrix: + include: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#example-adding-configurations + - product: OCR + test: TestOCRBasic + name: Linea Goerli ${{ matrix.product }} Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: - channel-id: ${{ secrets.QA_SLACK_CHANNEL }} - payload: | - { - "thread_ts": "${{ needs.testnet-smoke-tests-notify.outputs.thread_ts }}", - "attachments": [ - { - "color": "${{ steps.test-results.outputs.all_success && '#2E7D32' || '#C62828' }}", - "blocks": [ - { - "type": "header", - "text": { - "type": "plain_text", - "text": "${{ matrix.network }} ${{ steps.test-results.outputs.all_success && ':white_check_mark:' || ':x: Notifying <@U01Q4N37KFG>'}}", - "emoji": true - } - }, - { - "type": "divider" - }, - ${{ steps.test-results.outputs.results }} - ] - } - ] - } - env: - SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + fetch-depth: 0 + - name: Prepare Base64 TOML override + uses: ./.github/actions/setup-create-base64-config-live-testnets + with: + runId: ${{ github.run_id }} + testLogCollect: ${{ vars.TEST_LOG_COLLECT }} + chainlinkImage: ${{ env.CHAINLINK_IMAGE }} + chainlinkVersion: ${{ github.sha }} + pyroscopeServer: ${{ matrix.product.pyroscope_env == '' && '' || !startsWith(github.ref, 'refs/tags/') && '' || secrets.QA_PYROSCOPE_INSTANCE }} # Avoid sending blank envs https://github.com/orgs/community/discussions/25725 + pyroscopeEnvironment: ci-smoke-${{ matrix.product }}-linea-goerli + pyroscopeKey: ${{ secrets.QA_PYROSCOPE_KEY }} + lokiEndpoint: ${{ secrets.LOKI_URL }} + lokiTenantId: ${{ vars.LOKI_TENANT_ID }} + lokiBasicAuth: ${{ secrets.LOKI_BASIC_AUTH }} + logstreamLogTargets: ${{ vars.LOGSTREAM_LOG_TARGETS }} + grafanaUrl: ${{ vars.GRAFANA_URL }} + grafanaDashboardUrl: "/d/ddf75041-1e39-42af-aa46-361fe4c36e9e/ci-e2e-tests-logs" + network: "linea_goerli" + httpEndpoints: ${{ secrets.QA_LINEA_GOERLI_HTTP_URLS }} + wsEndpoints: ${{ secrets.QA_LINEA_GOERLI_URLS }} + fundingKeys: ${{ secrets.QA_EVM_KEYS }} + - name: Download Tests Binary + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 + with: + name: tests + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests-binary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_command_to_run: ./tests -test.timeout 30m -test.count=1 -test.parallel=1 -test.run ${{ matrix.test }} + binary_name: tests + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ github.sha }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + dockerhub_username: ${{ secrets.DOCKERHUB_READONLY_USERNAME }} + dockerhub_password: ${{ secrets.DOCKERHUB_READONLY_PASSWORD }} + artifacts_location: ./logs + token: ${{ secrets.GITHUB_TOKEN }} + cache_key_id: core-e2e-${{ env.MOD_CACHE_VERSION }} + cache_restore_only: "true" + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} + - name: Print failed test summary + if: always() + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@ea889b3133bd7f16ab19ba4ba130de5d9162c669 # v2.3.4 + with: + test_directory: "./" diff --git a/.github/workflows/on-demand-log-poller.yml b/.github/workflows/on-demand-log-poller.yml index 42f901ec304..ad3617841d3 100644 --- a/.github/workflows/on-demand-log-poller.yml +++ b/.github/workflows/on-demand-log-poller.yml @@ -2,81 +2,28 @@ name: On Demand Log Poller Consistency Test on: workflow_dispatch: inputs: - contracts: - description: Number of test contracts - default: "2" - required: true - eventsPerTx: - description: Number of events to emit per transaction - default: "10" - required: true - useFinalityTag: - description: Use finality tag - default: "false" - required: true - loadDuration: - description: Load duration (e.g. 10s, 10m, 1h) - default: "10m" - required: true - chainlinkImage: - description: Chainlink image to use - default: "public.ecr.aws/chainlink/chainlink" - required: true - chainlinkVersion: - description: Chainlink version to use - default: "2.7.0-beta1" - required: true - selectedNetworks: - type: choice - options: - - "SIMULATED" - - "SEPOLIA" - - "MUMBAI" - fundingPrivateKey: - description: Private funding key (Skip for Simulated) + base64Config: + description: base64-ed config required: true type: string - wsURL: - description: WS URL for the network (Skip for Simulated) - required: true - type: string - httpURL: - description: HTTP URL for the network (Skip for Simulated) - required: true - type: string jobs: test: env: - CONTRACTS: ${{ inputs.contracts }} - EVENTS_PER_TX: ${{ inputs.eventsPerTx }} - LOAD_DURATION: ${{ inputs.loadDuration }} - USE_FINALITY_TAG: ${{ inputs.useFinalityTag }} - CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} - CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} - SELECTED_NETWORKS: ${{ inputs.selectedNetworks }} REF_NAME: ${{ github.head_ref || github.ref_name }} runs-on: ubuntu20.04-8cores-32GB steps: - - name: Get Inputs + - name: Add masks and export base64 config run: | - EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) - EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) - EVM_KEYS=$(jq -r '.inputs.fundingPrivateKey' $GITHUB_EVENT_PATH) - - echo ::add-mask::$EVM_URLS - echo ::add-mask::$EVM_HTTP_URLS - echo ::add-mask::$EVM_KEYS - - echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV - echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV - echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: - ref: ${{ env.REF_NAME }} + ref: ${{ env.REF_NAME }} - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 with: go-version-file: "integration-tests/go.mod" cache: true @@ -84,4 +31,4 @@ jobs: run: | cd integration-tests go mod download - go test -v -timeout 5h -v -count=1 -run ^TestLogPollerFromEnv$ ./reorg/log_poller_maybe_reorg_test.go + go test -v -timeout 5h -v -count=1 -run ^TestLogPollerFewFiltersFixedDepth$ ./smoke/log_poller_test.go diff --git a/.github/workflows/on-demand-ocr-soak-test.yml b/.github/workflows/on-demand-ocr-soak-test.yml index 567d9510de9..b02e44db117 100644 --- a/.github/workflows/on-demand-ocr-soak-test.yml +++ b/.github/workflows/on-demand-ocr-soak-test.yml @@ -2,75 +2,19 @@ name: On Demand OCR Soak Test on: workflow_dispatch: inputs: - network: - description: Network to run tests on - type: choice - options: - - "SIMULATED" - - "GOERLI" - - "OPTIMISM_GOERLI" - - "ARBITRUM_GOERLI" - - "ARBITRUM_SEPOLIA" - - "ARBITRUM_MAINNET" - - "CELO_ALFAJORES" - - "CELO_MAINNET" - - "BASE_GOERLI" - - "BASE_MAINNET" - - "BSC_MAINNET" - - "BSC_TESTNET" - - "SCROLL_SEPOLIA" - - "SCROLL_MAINNET" - - "POLYGON_MUMBAI" - - "POLYGON_MAINNET" - - "LINEA_GOERLI" - - "LINEA_MAINNET" - - "FANTOM_TESTNET" - - "FANTOM_MAINNET" - - "KROMA_MAINNET" - - "KROMA_SEPOLIA" - - "WEMIX_TESTNET" - - "WEMIX_MAINNET" - fundingPrivateKey: - description: Private funding key (Skip for Simulated) - required: false - type: string - wsURL: - description: WS URL for the network (Skip for Simulated) - required: false - type: string - httpURL: - description: HTTP URL for the network (Skip for Simulated) - required: false - type: string + base64Config: + description: base64-ed config + required: true + type: string slackMemberID: description: Slack Member ID (Not your @) required: true default: U01A2B2C3D4 type: string - chainlinkImage: - description: Container image location for the Chainlink nodes - required: true - default: public.ecr.aws/chainlink/chainlink - chainlinkVersion: - description: Container image version for the Chainlink nodes - required: true - default: "2.7.0" - testDuration: - description: Duration of the test (time string) - required: false - default: 15m - chainlinkNodeFunding: - description: How much to fund each Chainlink node (in ETH) - required: false - default: ".001" - timeBetweenRounds: - description: How long to wait before starting a new round - required: false - default: 1m jobs: ocr_soak_test: - name: ${{ inputs.network }} OCR Soak Test + name: OCR Soak Test environment: integration runs-on: ubuntu-latest permissions: @@ -79,14 +23,9 @@ jobs: id-token: write contents: read env: - CHAINLINK_COMMIT_SHA: ${{ inputs.chainlinkVersion }} CHAINLINK_ENV_USER: ${{ github.actor }} - SELECTED_NETWORKS: ${{ inputs.network }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: ${{ secrets.QA_SLACK_CHANNEL }} - OCR_TEST_DURATION: ${{ inputs.testDuration }} - OCR_CHAINLINK_NODE_FUNDING: ${{ inputs.chainlinkNodeFunding }} - OCR_TIME_BETWEEN_ROUNDS: ${{ inputs.timeBetweenRounds }} TEST_LOG_LEVEL: debug REF_NAME: ${{ github.head_ref || github.ref_name }} ENV_JOB_IMAGE_BASE: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink-tests @@ -99,33 +38,32 @@ jobs: hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} this-job-name: ${{ inputs.network }} OCR Soak Test continue-on-error: true - - name: Get Inputs + - name: Checkout the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ env.REF_NAME }} + - name: Get Slack config and mask base64 config run: | - EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) - EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) - EVM_KEYS=$(jq -r '.inputs.fundingPrivateKey' $GITHUB_EVENT_PATH) SLACK_USER=$(jq -r '.inputs.slackMemberID' $GITHUB_EVENT_PATH) - - echo ::add-mask::$EVM_URLS - echo ::add-mask::$EVM_HTTP_URLS - echo ::add-mask::$EVM_KEYS echo ::add-mask::$SLACK_USER - - echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV - echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV - echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV echo SLACK_USER=$SLACK_USER >> $GITHUB_ENV - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Parse base64 config + uses: ./.github/actions/setup-parse-base64-config with: - ref: ${{ env.REF_NAME }} + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} - name: Setup Push Tag shell: bash run: | echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Build Image uses: ./.github/actions/build-test-image with: @@ -145,8 +83,8 @@ jobs: with: test_command_to_run: cd ./integration-tests && go test -v -count=1 -run ^TestOCRSoak$ ./soak test_download_vendor_packages_command: make gomod - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} token: ${{ secrets.GITHUB_TOKEN }} should_cleanup: false go_mod_path: ./integration-tests/go.mod diff --git a/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml b/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml new file mode 100644 index 00000000000..de53b493a5f --- /dev/null +++ b/.github/workflows/on-demand-vrfv2-eth2-clients-test.yml @@ -0,0 +1,63 @@ +name: On Demand VRFV2 Smoke Test (Ethereum clients) +on: + workflow_dispatch: + inputs: + base64Config: + description: base64-ed config + required: true + type: string + +jobs: + vrfv2_smoke_test: + name: VRFV2 Smoke Test with custom EL client client + environment: integration + runs-on: ubuntu20.04-8cores-32GB + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + env: + TEST_LOG_LEVEL: debug + REF_NAME: ${{ github.head_ref || github.ref_name }} + steps: + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Mask base64 config + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Parse base64 config + uses: ./.github/actions/setup-parse-base64-config + with: + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY + echo "### Execution client used" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.ETH2_EL_CLIENT }}\`" >>$GITHUB_STEP_SUMMARY + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + with: + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -run TestVRFv2Basic ./smoke/vrfv2_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: vrf-test-logs + artifacts_location: ./integration-tests/smoke/logs/ + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + should_cleanup: false + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: "" diff --git a/.github/workflows/on-demand-vrfv2-performance-test.yml b/.github/workflows/on-demand-vrfv2-performance-test.yml index 100fdf73e61..7fd0d2b83b1 100644 --- a/.github/workflows/on-demand-vrfv2-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2-performance-test.yml @@ -2,44 +2,10 @@ name: On Demand VRFV2 Performance Test on: workflow_dispatch: inputs: - network: - description: Network to run tests on - type: choice - options: - - "ETHEREUM_MAINNET" - - "SIMULATED" - - "SEPOLIA" - - "OPTIMISM_MAINNET" - - "OPTIMISM_GOERLI" - - "ARBITRUM_MAINNET" - - "ARBITRUM_GOERLI" - - "ARBITRUM_SEPOLIA" - - "BSC_MAINNET" - - "BSC_TESTNET" - - "POLYGON_MAINNET" - - "POLYGON_MUMBAI" - - "AVALANCHE_FUJI" - - "AVALANCHE_MAINNET" - fundingPrivateKey: - description: Private funding key (Skip for Simulated) - required: false - type: string - wsURL: - description: WS URL for the network (Skip for Simulated) - required: false - type: string - httpURL: - description: HTTP URL for the network (Skip for Simulated) - required: false - type: string - chainlinkImage: - description: Container image location for the Chainlink nodes + base64Config: + description: base64-ed config required: true - default: public.ecr.aws/chainlink/chainlink - chainlinkVersion: - description: Container image version for the Chainlink nodes - required: true - default: "2.6.0" + type: string performanceTestType: description: Performance Test Type of test to run type: choice @@ -48,20 +14,9 @@ on: - "Load" - "Stress" - "Spike" - testDuration: - description: Duration of the test (time string) - required: true - default: 5m - useExistingEnv: - description: Set `true` to use existing environment or `false` to deploy CL node and all contracts - required: false - default: false - configBase64: - description: TOML config in base64 (Needed when overriding config or providing contract addresses for existing env) - required: false jobs: vrfv2_performance_test: - name: ${{ inputs.network }} VRFV2 Performance Test + name: VRFV2 Performance Test environment: integration runs-on: ubuntu20.04-8cores-32GB permissions: @@ -71,16 +26,11 @@ jobs: contents: read env: LOKI_URL: ${{ secrets.LOKI_URL }} - LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }} - SELECTED_NETWORKS: ${{ inputs.network }} + LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} + LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} TEST_TYPE: ${{ inputs.performanceTestType }} - VRFV2_TEST_DURATION: ${{ inputs.testDuration }} - VRFV2_USE_EXISTING_ENV: ${{ inputs.useExistingEnv }} - CONFIG: ${{ inputs.configBase64 }} TEST_LOG_LEVEL: debug REF_NAME: ${{ github.head_ref || github.ref_name }} - CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} - CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} WASP_LOG_LEVEL: info @@ -93,38 +43,35 @@ jobs: hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} this-job-name: ${{ inputs.network }} VRFV2 Performance Test continue-on-error: true - - name: Setup Push Tag + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Mask base64 config + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Merge and export base64 config + uses: ./.github/actions/setup-merge-base64-config + with: + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary shell: bash run: | echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - name: Get Inputs - run: | - EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) - EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) - EVM_KEYS=$(jq -r '.inputs.fundingPrivateKey' $GITHUB_EVENT_PATH) - - echo ::add-mask::$EVM_URLS - echo ::add-mask::$EVM_HTTP_URLS - echo ::add-mask::$EVM_KEYS - - echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV - echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV - echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV - - - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 with: test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 24h -run TestVRFV2Performance/vrfv2_performance_test ./load/vrfv2 test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_name: vrf-test-logs artifacts_location: ./integration-tests/load/vrfv2/logs/ diff --git a/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml b/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml new file mode 100644 index 00000000000..1772730075e --- /dev/null +++ b/.github/workflows/on-demand-vrfv2plus-eth2-clients-test.yml @@ -0,0 +1,63 @@ +name: On Demand VRFV2Plus Smoke Test (Ethereum clients) +on: + workflow_dispatch: + inputs: + base64Config: + description: base64-ed config + required: true + type: string + +jobs: + vrfv2plus_smoke_test: + name: VRFV2Plus Smoke Test with custom EL client + environment: integration + runs-on: ubuntu20.04-8cores-32GB + permissions: + checks: write + pull-requests: write + id-token: write + contents: read + env: + TEST_LOG_LEVEL: debug + REF_NAME: ${{ github.head_ref || github.ref_name }} + steps: + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Mask base64 config + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Parse base64 config + uses: ./.github/actions/setup-parse-base64-config + with: + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary + shell: bash + run: | + echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY + echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY + echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY + echo "### Execution client used" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.ETH2_EL_CLIENT }}\`" >>$GITHUB_STEP_SUMMARY + - name: Run Tests + uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@7d541cbbca52d45b8a718257af86d9cf49774d1f # v2.2.15 + with: + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -run ^TestVRFv2Plus$/^Link_Billing$ ./smoke/vrfv2plus_test.go 2>&1 | tee /tmp/gotest.log | gotestfmt + test_download_vendor_packages_command: cd ./integration-tests && go mod download + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} + aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} + artifacts_name: vrfplus-test-logs + artifacts_location: ./integration-tests/smoke/logs/ + token: ${{ secrets.GITHUB_TOKEN }} + go_mod_path: ./integration-tests/go.mod + should_cleanup: false + QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} + QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} + QA_KUBECONFIG: "" diff --git a/.github/workflows/on-demand-vrfv2plus-performance-test.yml b/.github/workflows/on-demand-vrfv2plus-performance-test.yml index 238f40de882..858eecff761 100644 --- a/.github/workflows/on-demand-vrfv2plus-performance-test.yml +++ b/.github/workflows/on-demand-vrfv2plus-performance-test.yml @@ -2,44 +2,10 @@ name: On Demand VRFV2 Plus Performance Test on: workflow_dispatch: inputs: - network: - description: Network to run tests on - type: choice - options: - - "ETHEREUM_MAINNET" - - "SIMULATED" - - "SEPOLIA" - - "OPTIMISM_MAINNET" - - "OPTIMISM_GOERLI" - - "ARBITRUM_MAINNET" - - "ARBITRUM_GOERLI" - - "ARBITRUM_SEPOLIA" - - "BSC_MAINNET" - - "BSC_TESTNET" - - "POLYGON_MAINNET" - - "POLYGON_MUMBAI" - - "AVALANCHE_FUJI" - - "AVALANCHE_MAINNET" - fundingPrivateKey: - description: Private funding key (Skip for Simulated) - required: false - type: string - wsURL: - description: WS URL for the network (Skip for Simulated) - required: false - type: string - httpURL: - description: HTTP URL for the network (Skip for Simulated) - required: false - type: string - chainlinkImage: - description: Container image location for the Chainlink nodes - required: true - default: public.ecr.aws/chainlink/chainlink - chainlinkVersion: - description: Container image version for the Chainlink nodes + base64Config: + description: base64-ed config required: true - default: "2.6.0" + type: string performanceTestType: description: Performance Test Type of test to run type: choice @@ -47,21 +13,11 @@ on: - "Soak" - "Load" - "Stress" - - "Spike" - testDuration: - description: Duration of the test (time string) - required: true - default: 5m - useExistingEnv: - description: Set `true` to use existing environment or `false` to deploy CL node and all contracts - required: false - default: "false" - configBase64: - description: TOML config in base64 (Needed when overriding config or providing contract addresses for existing env) - required: false + - "Spike" + jobs: vrfv2plus_performance_test: - name: ${{ inputs.network }} VRFV2 Plus Performance Test + name: VRFV2 Plus Performance Test environment: integration runs-on: ubuntu20.04-8cores-32GB permissions: @@ -71,20 +27,15 @@ jobs: contents: read env: LOKI_URL: ${{ secrets.LOKI_URL }} - LOKI_TOKEN: ${{ secrets.LOKI_TOKEN }} - SELECTED_NETWORKS: ${{ inputs.network }} + LOKI_TENANT_ID: ${{ secrets.LOKI_TENANT_ID }} + LOKI_BASIC_AUTH: ${{ secrets.LOKI_BASIC_AUTH }} TEST_TYPE: ${{ inputs.performanceTestType }} - VRFV2PLUS_TEST_DURATION: ${{ inputs.testDuration }} - VRFV2PLUS_USE_EXISTING_ENV: ${{ inputs.useExistingEnv }} - CONFIG: ${{ inputs.configBase64 }} TEST_LOG_LEVEL: debug REF_NAME: ${{ github.head_ref || github.ref_name }} - CHAINLINK_IMAGE: ${{ inputs.chainlinkImage }} - CHAINLINK_VERSION: ${{ inputs.chainlinkVersion }} SLACK_API_KEY: ${{ secrets.QA_SLACK_API_KEY }} SLACK_CHANNEL: ${{ secrets.QA_VRF_SLACK_CHANNEL }} WASP_LOG_LEVEL: info - steps: + steps: - name: Collect Metrics id: collect-gha-metrics uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 @@ -93,38 +44,35 @@ jobs: hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} this-job-name: ${{ inputs.network }} VRFV2 Plus Performance Test continue-on-error: true - - name: Setup Push Tag + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + - name: Mask base64 config + run: | + BASE64_CONFIG_OVERRIDE=$(jq -r '.inputs.base64Config' $GITHUB_EVENT_PATH) + echo ::add-mask::$BASE64_CONFIG_OVERRIDE + echo "BASE64_CONFIG_OVERRIDE=$BASE64_CONFIG_OVERRIDE" >> $GITHUB_ENV + - name: Merge and export base64 config + uses: ./.github/actions/setup-merge-base64-config + with: + base64Config: ${{ env.BASE64_CONFIG_OVERRIDE }} + - name: Send details to Step Summary shell: bash run: | echo "### chainlink image used for this test run :link:" >>$GITHUB_STEP_SUMMARY - echo "\`${{ inputs.chainlinkVersion }}\`" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.CHAINLINK_IMAGE }}\`" >>$GITHUB_STEP_SUMMARY echo "### chainlink-tests image tag for this test run :ship:" >>$GITHUB_STEP_SUMMARY echo "\`${GITHUB_SHA}\`" >>$GITHUB_STEP_SUMMARY - - name: Get Inputs - run: | - EVM_URLS=$(jq -r '.inputs.wsURL' $GITHUB_EVENT_PATH) - EVM_HTTP_URLS=$(jq -r '.inputs.httpURL' $GITHUB_EVENT_PATH) - EVM_KEYS=$(jq -r '.inputs.fundingPrivateKey' $GITHUB_EVENT_PATH) - - echo ::add-mask::$EVM_URLS - echo ::add-mask::$EVM_HTTP_URLS - echo ::add-mask::$EVM_KEYS - - echo EVM_URLS=$EVM_URLS >> $GITHUB_ENV - echo EVM_HTTP_URLS=$EVM_HTTP_URLS >> $GITHUB_ENV - echo EVM_KEYS=$EVM_KEYS >> $GITHUB_ENV - - - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 + echo "### Networks on which test was run" >>$GITHUB_STEP_SUMMARY + echo "\`${{ env.NETWORKS }}\`" >>$GITHUB_STEP_SUMMARY - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 with: test_command_to_run: cd ./integration-tests && go test -v -count=1 -timeout 24h -run TestVRFV2PlusPerformance/vrfv2plus_performance_test ./load/vrfv2plus test_download_vendor_packages_command: cd ./integration-tests && go mod download - cl_repo: ${{ inputs.chainlinkImage }} - cl_image_tag: ${{ inputs.chainlinkVersion }} + cl_repo: ${{ env.CHAINLINK_IMAGE }} + cl_image_tag: ${{ env.CHAINLINK_VERSION }} aws_registries: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }} artifacts_name: vrf-test-logs artifacts_location: ./integration-tests/load/vrfv2plus/logs/ diff --git a/.github/workflows/performance-tests.yml b/.github/workflows/performance-tests.yml deleted file mode 100644 index 4b6dd1a2280..00000000000 --- a/.github/workflows/performance-tests.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: Performance Tests -on: - workflow_dispatch: - inputs: - focus: - description: cron|directrequest|flux|keeper|ocr|vrf|suite - required: true - default: suite - type: string - -jobs: - build-chainlink: - environment: integration - permissions: - id-token: write - contents: read - name: Build Chainlink Image - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 - with: - aws-region: ${{ secrets.QA_AWS_REGION }} - role-to-assume: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - role-duration-seconds: 3600 - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@062b18b96a7aff071d4dc91bc00c4c1a7945b076 # v2.0.1 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - - name: Build and Push - uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0 - with: - context: . - file: core/chainlink.Dockerfile - # comma separated like: KEY1=VAL1,KEY2=VAL2,... - build-args: COMMIT_SHA=${{ github.sha }} - tags: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink:latest.${{ github.sha }} - push: true - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: Build Chainlink Image - continue-on-error: true - run_tests: - environment: integration - name: run core evm ${{ github.event.inputs.focus }} performance tests - runs-on: ubuntu-latest - needs: build-chainlink - steps: - - name: Checkout the repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - name: Run Tests - uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@e865e376b8c2d594028c8d645dd6c47169b72974 # v2.2.16 - with: - test_command_to_run: cd integration-tests && go test -timeout 1h -count=1 -json -test.parallel 10 ./performance 2>&1 | tee /tmp/gotest.log | gotestfmt - test_download_vendor_packages_command: make gomod - cl_repo: ${{ secrets.QA_AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.QA_AWS_REGION }}.amazonaws.com/chainlink - cl_image_tag: latest.${{ github.sha }} - artifacts_location: ./integration-tests/performance/logs - publish_report_paths: ./tests-perf-report.xml - publish_check_name: Core Performance Test Results - go_mod_path: ./integration-tests/go.mod - QA_AWS_REGION: ${{ secrets.QA_AWS_REGION }} - QA_AWS_ROLE_TO_ASSUME: ${{ secrets.QA_AWS_ROLE_TO_ASSUME }} - QA_KUBECONFIG: ${{ secrets.QA_KUBECONFIG }} - - name: Publish pprof artifacts - if: ${{ success() }} - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 - with: - name: pprof_results - path: ./integration-tests/performance/logs - - name: Collect Metrics - if: always() - id: collect-gha-metrics - uses: smartcontractkit/push-gha-metrics-action@d1618b772a97fd87e6505de97b872ee0b1f1729a # v2.0.2 - with: - basic-auth: ${{ secrets.GRAFANA_CLOUD_BASIC_AUTH }} - hostname: ${{ secrets.GRAFANA_CLOUD_HOST }} - this-job-name: run core evm ${{ github.event.inputs.focus }} performance tests - continue-on-error: true diff --git a/.github/workflows/pr-labels.yml b/.github/workflows/pr-labels.yml new file mode 100644 index 00000000000..66ef95434cf --- /dev/null +++ b/.github/workflows/pr-labels.yml @@ -0,0 +1,54 @@ +name: PR Labels + +on: + pull_request: + types: [labeled] + +jobs: + crib: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - name: Comment on PR + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const labelsToCheck = ["crib"]; + const { owner, repo, number: prNumber } = context.issue; + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ owner, repo, issue_number: prNumber }); + const labelMatches = labels.some(label => labelsToCheck.includes(label.name)); + + if (!labelMatches) { + core.info("No 'crib' PR label found. Proceeding."); + return; + } + + const comment = `## CRIB Environment Details :information_source: + + CRIB activated via the 'crib' label. To destroy the environment, remove the 'crib' PR label or close the PR. + + Please review the following details: + + ### Subdomains + + _Use these subdomains to access the CRIB environment. They are prefixes to the internal base domain._ + + - crib-chain-${prNumber}-node1. + - crib-chain-${prNumber}-node2. + - crib-chain-${prNumber}-node3. + - crib-chain-${prNumber}-node4. + - crib-chain-${prNumber}-node5. + - crib-chain-${prNumber}-node6. + - crib-chain-${prNumber}-geth-http. + - crib-chain-${prNumber}-geth-ws. + - crib-chain-${prNumber}-mockserver. + `; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: comment + }); diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index 7f6fa4f482e..447018eb62e 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -32,7 +32,7 @@ jobs: strategy: fail-fast: false matrix: - product: [vrf, automation, llo-feeds, functions, shared] + product: [vrf, automation, llo-feeds, l2ep, functions, shared] needs: [changes] name: Foundry Tests ${{ matrix.product }} # See https://github.com/foundry-rs/foundry/issues/3827 @@ -58,7 +58,7 @@ jobs: uses: foundry-rs/foundry-toolchain@v1 with: # Has to match the `make foundry` version. - version: nightly-09fe3e041369a816365a020f715ad6f94dbce9f2 + version: nightly-5b7e4cb3c882b28f3c32ba580de27ce7381f415a - name: Run Forge build if: needs.changes.outputs.changes == 'true' diff --git a/.github/workflows/solidity-hardhat.yml b/.github/workflows/solidity-hardhat.yml index 129f37c0de6..9e29d034225 100644 --- a/.github/workflows/solidity-hardhat.yml +++ b/.github/workflows/solidity-hardhat.yml @@ -63,7 +63,7 @@ jobs: fail-fast: false matrix: split: ${{ fromJson(needs.split-tests.outputs.splits) }} - runs-on: ubuntu20.04-4cores-16GB + runs-on: ubuntu-latest steps: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -84,7 +84,7 @@ jobs: - name: Rename coverage run: mv ./contracts/coverage.json ./contracts/coverage-${{ matrix.split.idx }}.json - name: Upload coverage - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 with: name: solidity-coverage-${{ matrix.split.idx }} path: ./contracts/coverage-${{ matrix.split.idx }}.json @@ -110,7 +110,7 @@ jobs: - name: Make coverage directory run: mkdir ./contracts/coverage-reports - name: Download coverage - uses: actions/download-artifact@v3 + uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: path: ./contracts/coverage-reports - name: Display structure of downloaded files @@ -128,7 +128,7 @@ jobs: fail-fast: false matrix: split: ${{ fromJson(needs.split-tests.outputs.splits) }} - runs-on: ubuntu20.04-4cores-16GB + runs-on: ubuntu-latest steps: - name: Checkout the repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 6c5207e0f05..8eb95f4147c 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -18,7 +18,7 @@ jobs: pull-requests: write steps: - - uses: actions/stale@1160a2240286f5da8ec72b1c0816ce2481aabf84 # v8.0.0 + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} exempt-all-pr-assignees: true diff --git a/.gitignore b/.gitignore index 3f016503a81..ae69535d352 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,13 @@ go.work* # This sometimes shows up for some reason tools/flakeytests/coverage.txt + +# Integration tests create these files +.test_summary/ +.run.id + +# Fuzz tests can create these files +**/testdata/fuzz/* + +# Runtime test configuration that might contain secrets +overrides.toml \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml index f9d06ad471c..3672692f599 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -10,6 +10,9 @@ linters: - misspell - rowserrcheck - errorlint + - unconvert + - sqlclosecheck + - noctx linters-settings: exhaustive: default-signifies-exhaustive: true diff --git a/.tool-versions b/.tool-versions index c60396ccb86..d8f0afd901d 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,5 +1,5 @@ -golang 1.21.4 -mockery 2.35.4 +golang 1.21.5 +mockery 2.38.0 nodejs 16.16.0 postgres 13.3 helm 3.10.3 diff --git a/CODEOWNERS b/CODEOWNERS index e34d3ea1bef..83505b0ed8c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -120,6 +120,7 @@ core/scripts/gateway @bolekk @pinebit /.github/workflows/automation-ondemand-tests.yml @smartcontractkit/keepers /.github/workflows/automation-benchmark-tests.yml @smartcontractkit/keepers /.github/workflows/automation-load-tests.yml @smartcontractkit/keepers +/.github/workflows/automation-nightly-tests.yml @smartcontractkit/keepers /core/chainlink.Dockerfile @smartcontractkit/prodsec-public diff --git a/GNUmakefile b/GNUmakefile index 6cd5ab7143e..549a7222a82 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -6,7 +6,7 @@ GO_LDFLAGS := $(shell tools/bin/ldflags) GOFLAGS = -ldflags "$(GO_LDFLAGS)" .PHONY: install -install: operator-ui-autoinstall install-chainlink-autoinstall ## Install chainlink and all its dependencies. +install: install-chainlink-autoinstall ## Install chainlink and all its dependencies. .PHONY: install-git-hooks install-git-hooks: ## Install git hooks. @@ -14,8 +14,6 @@ install-git-hooks: ## Install git hooks. .PHONY: install-chainlink-autoinstall install-chainlink-autoinstall: | pnpmdep gomod install-chainlink ## Autoinstall chainlink. -.PHONY: operator-ui-autoinstall -operator-ui-autoinstall: | operator-ui ## Autoinstall frontend UI. .PHONY: pnpmdep pnpmdep: ## Install solidity contract dependencies through pnpm @@ -44,13 +42,16 @@ godoc: ## Install and run godoc install-chainlink: operator-ui ## Install the chainlink binary. go install $(GOFLAGS) . -chainlink: operator-ui ## Build the chainlink binary. +.PHONY: chainlink +chainlink: ## Build the chainlink binary. go build $(GOFLAGS) . -chainlink-dev: operator-ui ## Build a dev build of chainlink binary. +.PHONY: chainlink-dev +chainlink-dev: ## Build a dev build of chainlink binary. go build -tags dev $(GOFLAGS) . -chainlink-test: operator-ui ## Build a test build of chainlink binary. +.PHONY: chainlink-test +chainlink-test: ## Build a test build of chainlink binary. go build $(GOFLAGS) . .PHONY: chainlink-local-start @@ -112,7 +113,7 @@ presubmit: ## Format go files and imports. .PHONY: mockery mockery: $(mockery) ## Install mockery. - go install github.com/vektra/mockery/v2@v2.35.4 + go install github.com/vektra/mockery/v2@v2.38.0 .PHONY: codecgen codecgen: $(codecgen) ## Install codecgen @@ -147,6 +148,10 @@ goreleaser-dev-build: ## Run goreleaser snapshot build goreleaser-dev-release: ## run goreleaser snapshot release ./tools/bin/goreleaser_wrapper release --snapshot --rm-dist --config ${GORELEASER_CONFIG} +.PHONY: modgraph +modgraph: + ./tools/bin/modgraph > go.md + help: @echo "" @echo " .__ .__ .__ .__ __" diff --git a/VERSION b/VERSION index 834f2629538..dedcc7d4335 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.8.0 +2.9.1 diff --git a/charts/chainlink-cluster/.gitignore b/charts/chainlink-cluster/.gitignore new file mode 100644 index 00000000000..3ee791f740a --- /dev/null +++ b/charts/chainlink-cluster/.gitignore @@ -0,0 +1,3 @@ +# Helm +charts/ +requirements.lock diff --git a/charts/chainlink-cluster/Chart.yaml b/charts/chainlink-cluster/Chart.yaml index 127f5b6e326..498b0670812 100644 --- a/charts/chainlink-cluster/Chart.yaml +++ b/charts/chainlink-cluster/Chart.yaml @@ -1,10 +1,10 @@ -apiVersion: v1 +apiVersion: v2 name: chainlink-cluster description: Chainlink nodes cluster -version: 0.1.3 +version: 0.2.0 appVersion: "2.6.0" dependencies: - name: mockserver version: "5.14.0" - repository: "@mockserver" - condition: mockserver.enabled \ No newline at end of file + repository: "https://www.mock-server.com" + condition: mockserver.enabled diff --git a/charts/chainlink-cluster/README.md b/charts/chainlink-cluster/README.md index 5fb55536635..3deb37794a6 100644 --- a/charts/chainlink-cluster/README.md +++ b/charts/chainlink-cluster/README.md @@ -16,13 +16,8 @@ nix 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 +Configure the cluster, see `deployments.app.helm.values` and [values.yaml](./values.yaml) comments for more details -Set your registry for the image, example for `ECR`: -``` -aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin ${aws_account}.dkr.ecr.us-west-2.amazonaws.com -export DEVSPACE_IMAGE="${aws_account}.dkr.ecr.us-west-2.amazonaws.com/chainlink-devspace" -``` Enter the shell and deploy ``` # set your unique namespace if it's a new cluster @@ -45,11 +40,12 @@ Fix something in the code locally, it'd automatically sync, rebuild it inside co make chainlink make chainlink-local-start ``` -If you need to update the whole cluster run `deploy` again with a new set of images + +Reset the pod to original image ``` devspace reset pods -devspace deploy ``` + Destroy the cluster ``` devspace purge diff --git a/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go b/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go index 93619fe6148..b65be29501d 100644 --- a/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go +++ b/charts/chainlink-cluster/dashboard/cmd/dashboard_deploy.go @@ -3,7 +3,7 @@ package main import ( "os" - "github.com/smartcontractkit/chainlink/v2/dashboard/dashboard" + "github.com/smartcontractkit/chainlink/charts/chainlink-cluster/dashboard/dashboard" "github.com/smartcontractkit/wasp" ) diff --git a/charts/chainlink-cluster/devspace.yaml b/charts/chainlink-cluster/devspace.yaml index cb4c8bfce49..0157ce7451c 100644 --- a/charts/chainlink-cluster/devspace.yaml +++ b/charts/chainlink-cluster/devspace.yaml @@ -2,6 +2,7 @@ version: v2beta1 name: chainlink vars: + NS_TTL: 72h DEVSPACE_IMAGE: source: env @@ -17,20 +18,45 @@ pipelines: # You can run this pipeline via `devspace deploy` (or `devspace run-pipeline deploy`) deploy: run: |- - run_dependencies --all # 1. Deploy any projects this project needs (see "dependencies") - ensure_pull_secrets --all # 2. Ensure pull secrets - build_images --all -t $(git rev-parse --short HEAD) # 3. Build, tag (git commit hash) and push all images (see "images") - create_deployments --all # 4. Deploy Helm charts and manifests specfied as "deployments" + run_dependencies --all + ensure_pull_secrets --all + build_images ---var DOCKER_DEFAULT_PLATFORM=linux/amd64 --all -t $(git rev-parse --short HEAD) + kubectl annotate namespace ${DEVSPACE_NAMESPACE} janitor/ttl=${NS_TTL} || true + kubectl label namespace/${DEVSPACE_NAMESPACE} network=crib || true + create_deployments --all + echo "Namespace ${DEVSPACE_NAMESPACE} will be deleted in ${NS_TTL}" + purge: + run: |- + kubectl delete ns ${DEVSPACE_NAMESPACE} + +commands: + connect: |- + sudo kubefwd svc -n ${DEVSPACE_NAMESPACE} images: app: image: ${DEVSPACE_IMAGE} dockerfile: ../../core/chainlink.devspace.Dockerfile context: ../.. + docker: + disableFallback: true + +hooks: + - wait: + running: true + terminatedWithCode: 0 + timeout: 600 + container: + labelSelector: + # vars don't work here, = releaseName + release: "app" + events: ["after:deploy:app"] + name: "wait-for-pod-hook" # This is a list of `deployments` that DevSpace can create for this project deployments: app: + namespace: ${DEVSPACE_NAMESPACE} helm: releaseName: "app" chart: @@ -58,6 +84,16 @@ deployments: - name: node-1 image: ${DEVSPACE_IMAGE} version: latest + # default resources are 300m/1Gi + # first node need more resources to build faster inside container + # at least 2Gi of memory is required otherwise build will fail (OOM) + resources: + requests: + cpu: 2000m + memory: 2048Mi + limits: + cpu: 2000m + memory: 2048Mi # override default config per node # for example, use OCRv2 P2P setup, the whole config # toml: | @@ -105,13 +141,6 @@ deployments: - name: node-6 image: ${DEVSPACE_IMAGE} version: latest - resources: - requests: - cpu: 350m - memory: 1024Mi - limits: - cpu: 350m - memory: 1024Mi # each CL node have a dedicated PostgreSQL 11.15 # use StatefulSet by setting: @@ -231,7 +260,7 @@ profiles: patches: - op: replace path: dev.app.workingDir - value: /home/root/chainlink/integration-tests + value: /home/chainlink/integration-tests - op: replace path: dev.app.container value: runner @@ -256,21 +285,20 @@ profiles: # This is a list of `dev` containers that are based on the containers created by your deployments dev: app: - workingDir: /home/root/chainlink + workingDir: /home/chainlink container: node labelSelector: instance: node-1 # Sync files between the local filesystem and the development container sync: - - path: ../../core/services/chainlink:/home/root/chainlink/core/services/chainlink + - path: ../../core/services/chainlink:/home/chainlink/core/services/chainlink printLogs: true disableDownload: true - - path: ../..:/home/root/chainlink + - path: ../..:/home/chainlink printLogs: true disableDownload: true uploadExcludePaths: - integration-tests/ - - .git/ - .github/ - belt/ - charts/ @@ -280,16 +308,16 @@ dev: - integration-scripts/ - testdata/ - evm-test-helpers/ - - tools/ # Open a terminal and use the following command terminal: command: bash ssh: enabled: true proxyCommands: - - command: devspace - - command: kubectl - - command: helm +# TODO: access issues +# - command: devspace +# - command: kubectl +# - command: helm - gitCredentials: true ports: - port: "2345" diff --git a/charts/chainlink-cluster/go.mod b/charts/chainlink-cluster/go.mod index 951fb1d2e3c..ae67574aa06 100644 --- a/charts/chainlink-cluster/go.mod +++ b/charts/chainlink-cluster/go.mod @@ -1,4 +1,4 @@ -module github.com/smartcontractkit/chainlink/v2/dashboard +module github.com/smartcontractkit/chainlink/charts/chainlink-cluster/dashboard go 1.21 @@ -170,10 +170,6 @@ require ( ) replace ( - // Fixes go mod tidy issue for ambiguous imports from go-ethereum - // See https://github.com/ugorji/go/issues/279 - github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1 - github.com/go-kit/log => github.com/go-kit/log v0.2.1 // replicating the replace directive on cosmos SDK diff --git a/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml index f335130ea9f..91924ba5005 100644 --- a/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml +++ b/charts/chainlink-cluster/templates/chainlink-db-deployment.yaml @@ -24,12 +24,20 @@ spec: selector: matchLabels: app: {{ $.Release.Name }}-db + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + havoc-component-group: db + havoc-network-group: db instance: {{ $cfg.name }}-db release: {{ $.Release.Name }} template: metadata: labels: app: {{ $.Release.Name }}-db + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + havoc-component-group: db + havoc-network-group: db instance: {{ $cfg.name }}-db release: {{ $.Release.Name }} {{- range $key, $value := $.Values.labels }} diff --git a/charts/chainlink-cluster/templates/chainlink-db-networkpolicy.yaml b/charts/chainlink-cluster/templates/chainlink-db-networkpolicy.yaml new file mode 100644 index 00000000000..e5d029b7865 --- /dev/null +++ b/charts/chainlink-cluster/templates/chainlink-db-networkpolicy.yaml @@ -0,0 +1,23 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $.Release.Name }}-db +spec: + podSelector: + matchLabels: + app: {{ $.Release.Name }}-db + policyTypes: + - Ingress + ingress: + - from: + # Allow all node pods to access the database pods. + - podSelector: + matchLabels: + app: {{ $.Release.Name }} + # Allow all runner pods to access the database pods. + - podSelector: + matchLabels: + app: runner + ports: + - protocol: TCP + port: 5432 diff --git a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml index 463453aff93..0ce16fd475b 100644 --- a/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml +++ b/charts/chainlink-cluster/templates/chainlink-node-deployment.yaml @@ -1,18 +1,38 @@ -{{- range $cfg := .Values.chainlink.nodes }} +{{- range $index, $cfg := .Values.chainlink.nodes }} apiVersion: apps/v1 kind: Deployment metadata: - name: {{ $.Release.Name }}-{{ $cfg.name }} + name: {{ if eq $index 0 }}{{ $.Release.Name }}-{{ $cfg.name }}-bootstrap{{ else }}{{ $.Release.Name }}-{{ $cfg.name }}{{ end }} spec: + strategy: + # Need to recreate the pod to deal with lease lock held by old pod. + type: Recreate selector: matchLabels: app: {{ $.Release.Name }} + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + {{ if eq $index 0 }}{{ else }} + havoc-component-group: node + {{ end }} + {{ if eq $index 0 }}{{ else }} + havoc-network-group: {{ if gt $index 2 }}"1"{{ else }}"2"{{ end }} + {{ end }} instance: {{ $cfg.name }} release: {{ $.Release.Name }} template: metadata: labels: app: {{ $.Release.Name }} + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + {{ if eq $index 0 }}{{ else }} + havoc-component-group: node + {{ end }} + {{ if eq $index 0 }}{{ else }} + havoc-network-group: {{ if gt $index 2 }}"1"{{ else }}"2"{{ end }} + {{ end }} + instance: {{ $cfg.name }} release: {{ $.Release.Name }} {{- range $key, $value := $.Values.labels }} @@ -36,7 +56,7 @@ spec: {{- toYaml $.Values.chainlink.securityContext | nindent 12 }} image: {{ default "public.ecr.aws/chainlink/chainlink" $cfg.image }} imagePullPolicy: Always - command: ["bash", "-c", "while ! pg_isready -U postgres --host {{ $.Release.Name }}-db-{{ $cfg.name }} --port 5432; do echo \"waiting for database to start\"; sleep 1; done && chainlink -c /etc/node-secrets-volume/default.toml -c /etc/node-secrets-volume/overrides.toml -secrets /etc/node-secrets-volume/secrets.toml node start -d -p /etc/node-secrets-volume/node-password -a /etc/node-secrets-volume/apicredentials --vrfpassword=/etc/node-secrets-volume/apicredentials"] + command: [ "bash", "-c", "while ! pg_isready -U postgres --host {{ $.Release.Name }}-db-{{ $cfg.name }} --port 5432; do echo \"waiting for database to start\"; sleep 1; done && chainlink -c /etc/node-secrets-volume/default.toml -c /etc/node-secrets-volume/overrides.toml -secrets /etc/node-secrets-volume/secrets.toml node start -d -p /etc/node-secrets-volume/node-password -a /etc/node-secrets-volume/apicredentials --vrfpassword=/etc/node-secrets-volume/apicredentials" ] ports: - name: access containerPort: {{ $.Values.chainlink.web_port }} @@ -71,14 +91,14 @@ spec: initialDelaySeconds: 15 periodSeconds: 5 failureThreshold: 20 - {{ if (hasKey $.Values.chainlink "resources") }} + {{ if (hasKey $cfg "resources") }} resources: requests: - memory: {{ default "1024Mi" $.Values.chainlink.resources.requests.memory }} - cpu: {{ default "500m" $.Values.chainlink.resources.requests.cpu }} + memory: {{ default "1024Mi" $cfg.resources.requests.memory }} + cpu: {{ default "300m" $cfg.resources.requests.cpu }} limits: - memory: {{ default "1024Mi" $.Values.chainlink.resources.limits.memory }} - cpu: {{ default "500m" $.Values.chainlink.resources.limits.cpu }} + memory: {{ default "1024Mi" $cfg.resources.limits.memory }} + cpu: {{ default "300m" $cfg.resources.limits.cpu }} {{ else }} {{ end }} {{- with $.Values.nodeSelector }} diff --git a/charts/chainlink-cluster/templates/chainlink-node-networkpolicy.yaml b/charts/chainlink-cluster/templates/chainlink-node-networkpolicy.yaml new file mode 100644 index 00000000000..321bc531626 --- /dev/null +++ b/charts/chainlink-cluster/templates/chainlink-node-networkpolicy.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $.Release.Name }}-node +spec: + podSelector: + matchLabels: + app: {{ $.Release.Name }} + policyTypes: + - Ingress + ingress: + # Allow all ingress traffic between the node pods and from runner pod. + - from: + - podSelector: + matchLabels: + app: {{ $.Release.Name }} + - podSelector: + matchLabels: + app: runner diff --git a/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml b/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml index 2cd9c3df2b6..05852642a29 100644 --- a/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml +++ b/charts/chainlink-cluster/templates/chainlink-pod-monitor.yaml @@ -8,7 +8,7 @@ metadata: spec: namespaceSelector: matchNames: - - "cl-cluster" + - {{ $.Release.Namespace }} podMetricsEndpoints: - port: access selector: diff --git a/charts/chainlink-cluster/templates/geth-deployment.yaml b/charts/chainlink-cluster/templates/geth-deployment.yaml index 6948c4df288..abc7853d978 100644 --- a/charts/chainlink-cluster/templates/geth-deployment.yaml +++ b/charts/chainlink-cluster/templates/geth-deployment.yaml @@ -7,11 +7,19 @@ spec: selector: matchLabels: app: geth + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + havoc-component-group: "blockchain" + havoc-network-group: "blockchain" release: {{ .Release.Name }} template: metadata: labels: app: geth + # Used for testing. + # havoc-component-group and havoc-network-group are used by "havoc" chaos testing tool + havoc-component-group: "blockchain" + havoc-network-group: "blockchain" release: {{ .Release.Name }} annotations: {{- range $key, $value := .Values.podAnnotations }} @@ -65,6 +73,8 @@ spec: - '--miner.etherbase' - '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266' - '--ipcdisable' + - '--http.api' + - 'admin,debug,web3,eth,txpool,personal,miner,net' - '--http' - '--http.vhosts' - '*' diff --git a/charts/chainlink-cluster/templates/geth-networkpolicy.yaml b/charts/chainlink-cluster/templates/geth-networkpolicy.yaml new file mode 100644 index 00000000000..5be59136251 --- /dev/null +++ b/charts/chainlink-cluster/templates/geth-networkpolicy.yaml @@ -0,0 +1,25 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $.Release.Name }}-geth +spec: + podSelector: + matchLabels: + app: geth + policyTypes: + - Ingress + ingress: + - from: + # Allow http and websocket connections from the node pods. + - podSelector: + matchLabels: + app: {{ $.Release.Name }} + # Allow http and websocket connections from the runner pods. + - podSelector: + matchLabels: + app: runner + ports: + - protocol: TCP + port: 8544 + - protocol: TCP + port: 8546 diff --git a/charts/chainlink-cluster/templates/ingress.yaml b/charts/chainlink-cluster/templates/ingress.yaml new file mode 100644 index 00000000000..f7d9791155b --- /dev/null +++ b/charts/chainlink-cluster/templates/ingress.yaml @@ -0,0 +1,42 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ $.Release.Name }} + labels: + app: {{ $.Release.Name }} + release: {{ $.Release.Name }} + {{- range $key, $value := $.Values.labels }} + {{ $key }}: {{ $value | quote }} + {{- end }} + annotations: + alb.ingress.kubernetes.io/backend-protocol: HTTP + alb.ingress.kubernetes.io/certificate-arn: {{ $.Values.ingress.annotation_certificate_arn | quote }} + alb.ingress.kubernetes.io/group.name: {{ $.Values.ingress.annotation_group_name | quote }} + alb.ingress.kubernetes.io/scheme: internal + alb.ingress.kubernetes.io/target-type: ip + {{- if .Values.ingress.extra_annotations }} + {{- range $key, $value := .Values.ingress.extra_annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} + {{- end }} +spec: + {{- with .Values.ingress.ingressClassName }} + ingressClassName: {{ . }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host }} + http: + paths: + {{- range .http.paths }} + - path: / + pathType: ImplementationSpecific + backend: + service: + name: {{ .backend.service.name }} + port: + number: {{ .backend.service.port.number }} + {{- end }} + {{- end }} +{{- end -}} diff --git a/charts/chainlink-cluster/templates/mockserver-networkpolicy.yaml b/charts/chainlink-cluster/templates/mockserver-networkpolicy.yaml new file mode 100644 index 00000000000..074b1ab089a --- /dev/null +++ b/charts/chainlink-cluster/templates/mockserver-networkpolicy.yaml @@ -0,0 +1,23 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $.Release.Name }}-mockserver +spec: + podSelector: + matchLabels: + app: mockserver + policyTypes: + - Ingress + ingress: + - from: + # Allow http traffic from the node pods. + - podSelector: + matchLabels: + app: {{ $.Release.Name }} + # Allow http traffic from the runner pods. + - podSelector: + matchLabels: + app: runner + ports: + - protocol: TCP + port: 1080 diff --git a/charts/chainlink-cluster/templates/networkpolicy-default.yaml b/charts/chainlink-cluster/templates/networkpolicy-default.yaml new file mode 100644 index 00000000000..f2d9416cf15 --- /dev/null +++ b/charts/chainlink-cluster/templates/networkpolicy-default.yaml @@ -0,0 +1,41 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default +spec: + podSelector: + matchLabels: {} + policyTypes: + - Ingress + - Egress + ingress: + {{- if and .Values.networkPolicyDefault.ingress.allowCustomCidrs (not (empty .Values.networkPolicyDefault.ingress.customCidrs)) }} + # Using a comma separated list to make it easy to pass in with: + # `helm template ... --set networkPolicyDefault.ingress.customCidrs=...` + {{- $cidrs := splitList "," .Values.networkPolicyDefault.ingress.customCidrs }} + - from: + {{- range $cidr := $cidrs }} + - ipBlock: + cidr: {{ $cidr | quote }} + {{- end }} + {{- else }} + # Deny all ingress if no rules are specified. Rules can still be specified in other templates. + - {} + {{- end }} + egress: + - to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: "{{ $.Release.Namespace }}" + - to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + podSelector: + matchLabels: + k8s-app: kube-dns + ports: + - protocol: TCP + port: 53 + - protocol: UDP + port: 53 diff --git a/charts/chainlink-cluster/templates/runner-networkpolicy.yaml b/charts/chainlink-cluster/templates/runner-networkpolicy.yaml new file mode 100644 index 00000000000..2bb6ac98625 --- /dev/null +++ b/charts/chainlink-cluster/templates/runner-networkpolicy.yaml @@ -0,0 +1,19 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ $.Release.Name }}-runner +spec: + podSelector: + matchLabels: + app: runner + policyTypes: + - Ingress + ingress: + # Allow all ingress traffic between the node pods and from runner pod. + - from: + - podSelector: + matchLabels: + app: {{ $.Release.Name }} + - podSelector: + matchLabels: + app: runner diff --git a/charts/chainlink-cluster/values.yaml b/charts/chainlink-cluster/values.yaml index eb93e6cefcf..24914a40a91 100644 --- a/charts/chainlink-cluster/values.yaml +++ b/charts/chainlink-cluster/values.yaml @@ -25,6 +25,16 @@ chainlink: nodes: - name: node-1 image: "public.ecr.aws/chainlink/chainlink:latest" + # default resources are 300m/1Gi + # first node need more resources to build faster inside container + # at least 2Gi of memory is required otherwise build will fail (OOM) + resources: + requests: + cpu: 2000m + memory: 2048Mi + limits: + cpu: 2000m + memory: 2048Mi # override default config per node # for example, use OCRv2 P2P setup, the whole config # toml: | @@ -125,6 +135,8 @@ geth: mockserver: enabled: true releasenameOverride: mockserver + service: + type: ClusterIP app: runAsUser: 999 readOnlyRootFilesystem: false @@ -168,6 +180,101 @@ runner: type: NodePort port: 8080 +ingress: + enabled: false + annotations: {} + ingressClassName: alb + hosts: + - host: chainlink-node-1.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: chainlink-node-1 + port: + number: 6688 + - host: chainlink-node-2.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: chainlink-node-2 + port: + number: 6688 + - host: chainlink-node-3.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: chainlink-node-3 + port: + number: 6688 + - host: chainlink-node-4.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: chainlink-node-4 + port: + number: 6688 + - host: chainlink-node-5.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: chainlink-node-5 + port: + number: 6688 + - host: chainlink-node-6.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: chainlink-node-6 + port: + number: 6688 + - host: chainlink-geth-http.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: geth + port: + number: 8544 + - host: chainlink-geth-ws.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: geth + port: + number: 8546 + - host: chainlink-mockserver.local + http: + paths: + - path: / + pathType: ImplementationSpecific + backend: + service: + name: mockserver + port: + number: 1080 # monitoring.coreos.com/v1 PodMonitor for each node prometheusMonitor: true @@ -176,3 +283,12 @@ podAnnotations: nodeSelector: tolerations: affinity: + +# Configure the default network policy. +networkPolicyDefault: + ingress: + allowCustomCidrs: false + # String of comma separated CIDRs + customCidrs: null + # Example: + # customCidrs: "10.0.0.0/16,192.168.0.1/24" diff --git a/common/client/mock_head_test.go b/common/client/mock_head_test.go index 1b69eedf438..747770480f5 100644 --- a/common/client/mock_head_test.go +++ b/common/client/mock_head_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -17,6 +17,10 @@ type mockHead struct { func (_m *mockHead) BlockDifficulty() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockDifficulty") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -33,6 +37,10 @@ func (_m *mockHead) BlockDifficulty() *big.Int { func (_m *mockHead) BlockNumber() int64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + var r0 int64 if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() diff --git a/common/client/mock_node_client_test.go b/common/client/mock_node_client_test.go index 7c8eb69171f..661ad68ede5 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -18,6 +18,10 @@ type mockNodeClient[CHAIN_ID types.ID, HEAD Head] struct { func (_m *mockNodeClient[CHAIN_ID, HEAD]) ChainID(ctx context.Context) (CHAIN_ID, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 CHAIN_ID var r1 error if rf, ok := ret.Get(0).(func(context.Context) (CHAIN_ID, error)); ok { @@ -42,6 +46,10 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) ChainID(ctx context.Context) (CHAIN_ID func (_m *mockNodeClient[CHAIN_ID, HEAD]) ClientVersion(_a0 context.Context) (string, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for ClientVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok { @@ -71,6 +79,10 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) Close() { func (_m *mockNodeClient[CHAIN_ID, HEAD]) Dial(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Dial") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -85,6 +97,10 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) Dial(ctx context.Context) error { func (_m *mockNodeClient[CHAIN_ID, HEAD]) DialHTTP() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DialHTTP") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -112,6 +128,10 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) Subscribe(ctx context.Context, channel _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + var r0 types.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) (types.Subscription, error)); ok { @@ -138,6 +158,10 @@ func (_m *mockNodeClient[CHAIN_ID, HEAD]) Subscribe(ctx context.Context, channel func (_m *mockNodeClient[CHAIN_ID, HEAD]) SubscribersCount() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribersCount") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() diff --git a/common/client/mock_node_selector_test.go b/common/client/mock_node_selector_test.go index e7b8d9ecb8d..bd0805fa4e6 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -16,6 +16,10 @@ type mockNodeSelector[CHAIN_ID types.ID, HEAD Head, RPC NodeClient[CHAIN_ID, HEA func (_m *mockNodeSelector[CHAIN_ID, HEAD, RPC]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -30,6 +34,10 @@ func (_m *mockNodeSelector[CHAIN_ID, HEAD, RPC]) Name() string { func (_m *mockNodeSelector[CHAIN_ID, HEAD, RPC]) Select() Node[CHAIN_ID, HEAD, RPC] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Select") + } + var r0 Node[CHAIN_ID, HEAD, RPC] if rf, ok := ret.Get(0).(func() Node[CHAIN_ID, HEAD, RPC]); ok { r0 = rf() diff --git a/common/client/mock_node_test.go b/common/client/mock_node_test.go index ea0e7d1a120..56132b2cee8 100644 --- a/common/client/mock_node_test.go +++ b/common/client/mock_node_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -20,6 +20,10 @@ type mockNode[CHAIN_ID types.ID, HEAD Head, RPC NodeClient[CHAIN_ID, HEAD]] stru func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Close() error { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) ConfiguredChainID() CHAIN_ID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ConfiguredChainID") + } + var r0 CHAIN_ID if rf, ok := ret.Get(0).(func() CHAIN_ID); ok { r0 = rf() @@ -48,6 +56,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) ConfiguredChainID() CHAIN_ID { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -62,6 +74,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Name() string { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Order() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Order") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() @@ -76,6 +92,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Order() int32 { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) RPC() RPC { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RPC") + } + var r0 RPC if rf, ok := ret.Get(0).(func() RPC); ok { r0 = rf() @@ -90,6 +110,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) RPC() RPC { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -104,6 +128,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Start(_a0 context.Context) error { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) State() nodeState { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for State") + } + var r0 nodeState if rf, ok := ret.Get(0).(func() nodeState); ok { r0 = rf() @@ -118,6 +146,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) State() nodeState { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *big.Int) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StateAndLatest") + } + var r0 nodeState var r1 int64 var r2 *big.Int @@ -151,6 +183,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *bi func (_m *mockNode[CHAIN_ID, HEAD, RPC]) String() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -165,6 +201,10 @@ func (_m *mockNode[CHAIN_ID, HEAD, RPC]) String() string { func (_m *mockNode[CHAIN_ID, HEAD, RPC]) SubscribersCount() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribersCount") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() diff --git a/common/client/mock_rpc_test.go b/common/client/mock_rpc_test.go index d5e8db82836..d87a02d47c1 100644 --- a/common/client/mock_rpc_test.go +++ b/common/client/mock_rpc_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -25,6 +25,10 @@ type mockRPC[CHAIN_ID types.ID, SEQ types.Sequence, ADDR types.Hashable, BLOCK_H func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) BalanceAt(ctx context.Context, accountAddress ADDR, blockNumber *big.Int) (*big.Int, error) { ret := _m.Called(ctx, accountAddress, blockNumber) + if len(ret) == 0 { + panic("no return value specified for BalanceAt") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) (*big.Int, error)); ok { @@ -51,6 +55,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) BatchCallContext(ctx context.Context, b []interface{}) 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, []interface{}) error); ok { r0 = rf(ctx, b) @@ -65,6 +73,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) BlockByHash(ctx context.Context, hash BLOCK_HASH) (HEAD, error) { ret := _m.Called(ctx, hash) + if len(ret) == 0 { + panic("no return value specified for BlockByHash") + } + var r0 HEAD var r1 error if rf, ok := ret.Get(0).(func(context.Context, BLOCK_HASH) (HEAD, error)); ok { @@ -89,6 +101,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) BlockByNumber(ctx context.Context, number *big.Int) (HEAD, error) { ret := _m.Called(ctx, number) + if len(ret) == 0 { + panic("no return value specified for BlockByNumber") + } + var r0 HEAD var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (HEAD, error)); ok { @@ -116,6 +132,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS _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...) @@ -130,6 +150,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) CallContract(ctx context.Context, msg interface{}, 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, interface{}, *big.Int) ([]byte, error)); ok { @@ -156,6 +180,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) ChainID(ctx context.Context) (CHAIN_ID, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 CHAIN_ID var r1 error if rf, ok := ret.Get(0).(func(context.Context) (CHAIN_ID, error)); ok { @@ -180,6 +208,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) ClientVersion(_a0 context.Context) (string, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for ClientVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok { @@ -209,6 +241,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) CodeAt(ctx context.Context, account ADDR, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for CodeAt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) ([]byte, error)); ok { @@ -235,6 +271,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) Dial(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Dial") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -249,6 +289,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) DialHTTP() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DialHTTP") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -268,6 +312,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) EstimateGas(ctx context.Context, call interface{}) (uint64, error) { ret := _m.Called(ctx, call) + if len(ret) == 0 { + panic("no return value specified for EstimateGas") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, interface{}) (uint64, error)); ok { @@ -292,6 +340,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) FilterEvents(ctx context.Context, query EVENT_OPS) ([]EVENT, error) { ret := _m.Called(ctx, query) + if len(ret) == 0 { + panic("no return value specified for FilterEvents") + } + var r0 []EVENT var r1 error if rf, ok := ret.Get(0).(func(context.Context, EVENT_OPS) ([]EVENT, error)); ok { @@ -318,6 +370,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) LINKBalance(ctx context.Context, accountAddress ADDR, linkAddress ADDR) (*assets.Link, error) { ret := _m.Called(ctx, accountAddress, linkAddress) + if len(ret) == 0 { + panic("no return value specified for LINKBalance") + } + var r0 *assets.Link var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, ADDR) (*assets.Link, error)); ok { @@ -344,6 +400,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) LatestBlockHeight(_a0 context.Context) (*big.Int, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for LatestBlockHeight") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -370,6 +430,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) PendingSequenceAt(ctx context.Context, addr ADDR) (SEQ, error) { ret := _m.Called(ctx, addr) + if len(ret) == 0 { + panic("no return value specified for PendingSequenceAt") + } + var r0 SEQ var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR) (SEQ, error)); ok { @@ -394,6 +458,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SendEmptyTransaction(ctx context.Context, newTxAttempt func(SEQ, uint32, FEE, ADDR) (interface{}, error), seq SEQ, gasLimit uint32, fee FEE, fromAddress ADDR) (string, error) { ret := _m.Called(ctx, newTxAttempt, seq, gasLimit, fee, fromAddress) + if len(ret) == 0 { + panic("no return value specified for SendEmptyTransaction") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(context.Context, func(SEQ, uint32, FEE, ADDR) (interface{}, error), SEQ, uint32, FEE, ADDR) (string, error)); ok { @@ -418,6 +486,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SendTransaction(ctx context.Context, tx TX) error { ret := _m.Called(ctx, tx) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, TX) error); ok { r0 = rf(ctx, tx) @@ -432,6 +504,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SequenceAt(ctx context.Context, accountAddress ADDR, blockNumber *big.Int) (SEQ, error) { ret := _m.Called(ctx, accountAddress, blockNumber) + if len(ret) == 0 { + panic("no return value specified for SequenceAt") + } + var r0 SEQ var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) (SEQ, error)); ok { @@ -461,6 +537,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SimulateTransaction(ctx context.Context, tx TX) error { ret := _m.Called(ctx, tx) + if len(ret) == 0 { + panic("no return value specified for SimulateTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, TX) error); ok { r0 = rf(ctx, tx) @@ -478,6 +558,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + var r0 types.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) (types.Subscription, error)); ok { @@ -504,6 +588,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SubscribersCount() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribersCount") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() @@ -518,6 +606,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) TokenBalance(ctx context.Context, accountAddress ADDR, tokenAddress ADDR) (*big.Int, error) { ret := _m.Called(ctx, accountAddress, tokenAddress) + if len(ret) == 0 { + panic("no return value specified for TokenBalance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, ADDR) (*big.Int, error)); ok { @@ -544,6 +636,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) TransactionByHash(ctx context.Context, txHash TX_HASH) (TX, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionByHash") + } + var r0 TX var r1 error if rf, ok := ret.Get(0).(func(context.Context, TX_HASH) (TX, error)); ok { @@ -568,6 +664,10 @@ func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) TransactionReceipt(ctx context.Context, txHash TX_HASH) (TX_RECEIPT, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionReceipt") + } + var r0 TX_RECEIPT var r1 error if rf, ok := ret.Get(0).(func(context.Context, TX_HASH) (TX_RECEIPT, error)); ok { diff --git a/common/client/mock_send_only_client_test.go b/common/client/mock_send_only_client_test.go index 481b2602ea3..b667a2ceb59 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -18,6 +18,10 @@ type mockSendOnlyClient[CHAIN_ID types.ID] struct { func (_m *mockSendOnlyClient[CHAIN_ID]) ChainID(_a0 context.Context) (CHAIN_ID, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 CHAIN_ID var r1 error if rf, ok := ret.Get(0).(func(context.Context) (CHAIN_ID, error)); ok { @@ -47,6 +51,10 @@ func (_m *mockSendOnlyClient[CHAIN_ID]) Close() { func (_m *mockSendOnlyClient[CHAIN_ID]) DialHTTP() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DialHTTP") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() diff --git a/common/client/mock_send_only_node_test.go b/common/client/mock_send_only_node_test.go index 524d7d8a6c5..0a319db5f78 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package client @@ -18,6 +18,10 @@ type mockSendOnlyNode[CHAIN_ID types.ID, RPC sendOnlyClient[CHAIN_ID]] struct { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Close() error { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) ConfiguredChainID() CHAIN_ID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ConfiguredChainID") + } + var r0 CHAIN_ID if rf, ok := ret.Get(0).(func() CHAIN_ID); ok { r0 = rf() @@ -46,6 +54,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) ConfiguredChainID() CHAIN_ID { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -60,6 +72,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Name() string { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) RPC() RPC { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RPC") + } + var r0 RPC if rf, ok := ret.Get(0).(func() RPC); ok { r0 = rf() @@ -74,6 +90,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) RPC() RPC { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -88,6 +108,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Start(_a0 context.Context) error { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) State() nodeState { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for State") + } + var r0 nodeState if rf, ok := ret.Get(0).(func() nodeState); ok { r0 = rf() @@ -102,6 +126,10 @@ func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) State() nodeState { func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) String() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() diff --git a/common/client/multi_node.go b/common/client/multi_node.go index db5380e91f5..30d21ba48a1 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -7,7 +7,6 @@ import ( "sync" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -87,7 +86,7 @@ type multiNode[ sendonlys []SendOnlyNode[CHAIN_ID, RPC_CLIENT] chainID CHAIN_ID chainType config.ChainType - lggr logger.Logger + lggr logger.SugaredLogger selectionMode string noNewHeadsThreshold time.Duration nodeSelector NodeSelector[CHAIN_ID, HEAD, RPC_CLIENT] @@ -119,7 +118,7 @@ func NewMultiNode[ HEAD types.Head[BLOCK_HASH], RPC_CLIENT RPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD], ]( - l logger.Logger, + lggr logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, @@ -132,9 +131,6 @@ func NewMultiNode[ ) MultiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT] { nodeSelector := newNodeSelector(selectionMode, nodes) - lggr := logger.Named(l, "MultiNode") - lggr = logger.With(lggr, "chainID", chainID.String()) - // Prometheus' default interval is 15s, set this to under 7.5s to avoid // aliasing (see: https://en.wikipedia.org/wiki/Nyquist_frequency) const reportInterval = 6500 * time.Millisecond @@ -143,7 +139,7 @@ func NewMultiNode[ sendonlys: sendonlys, chainID: chainID, chainType: chainType, - lggr: lggr, + lggr: logger.Sugared(lggr).Named("MultiNode").With("chainID", chainID.String()), selectionMode: selectionMode, noNewHeadsThreshold: noNewHeadsThreshold, nodeSelector: nodeSelector, @@ -166,12 +162,12 @@ func NewMultiNode[ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]) Dial(ctx context.Context) error { return c.StartOnce("MultiNode", func() (merr error) { if len(c.nodes) == 0 { - return errors.Errorf("no available nodes for chain %s", c.chainID.String()) + return fmt.Errorf("no available nodes for chain %s", c.chainID.String()) } var ms services.MultiStart for _, n := range c.nodes { if n.ConfiguredChainID().String() != c.chainID.String() { - return ms.CloseBecause(errors.Errorf("node %s has configured chain ID %s which does not match multinode configured chain ID of %s", n.String(), n.ConfiguredChainID().String(), c.chainID.String())) + return ms.CloseBecause(fmt.Errorf("node %s has configured chain ID %s which does not match multinode configured chain ID of %s", n.String(), n.ConfiguredChainID().String(), c.chainID.String())) } rawNode, ok := n.(*node[CHAIN_ID, HEAD, RPC_CLIENT]) if ok { @@ -188,7 +184,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP } for _, s := range c.sendonlys { if s.ConfiguredChainID().String() != c.chainID.String() { - return ms.CloseBecause(errors.Errorf("sendonly node %s has configured chain ID %s which does not match multinode configured chain ID of %s", s.String(), s.ConfiguredChainID().String(), c.chainID.String())) + return ms.CloseBecause(fmt.Errorf("sendonly node %s has configured chain ID %s which does not match multinode configured chain ID of %s", s.String(), s.ConfiguredChainID().String(), c.chainID.String())) } if err := ms.Start(ctx, s); err != nil { return err @@ -250,7 +246,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP c.activeNode = c.nodeSelector.Select() if c.activeNode == nil { - logger.Criticalw(c.lggr, "No live RPC nodes available", "NodeSelectionMode", c.nodeSelector.Name()) + c.lggr.Criticalw("No live RPC nodes available", "NodeSelectionMode", c.nodeSelector.Name()) errmsg := fmt.Errorf("no live nodes available for chain %s", c.chainID.String()) c.SvcErrBuffer.Append(errmsg) err = ErroringNodeError @@ -352,10 +348,10 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP } live := total - dead - logger.Tracew(c.lggr, fmt.Sprintf("MultiNode state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + c.lggr.Tracew(fmt.Sprintf("MultiNode state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) if total == dead { rerr := fmt.Errorf("no primary nodes available: 0/%d nodes are alive", total) - logger.Criticalw(c.lggr, rerr.Error(), "nodeStates", nodeStates) + c.lggr.Criticalw(rerr.Error(), "nodeStates", nodeStates) c.SvcErrBuffer.Append(rerr) } else if dead > 0 { c.lggr.Errorw(fmt.Sprintf("At least one primary node is dead: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) @@ -398,6 +394,10 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP // main node is used at the end for the return value continue } + + if n.State() != nodeStateAlive { + continue + } // Parallel call made to all other nodes with ignored return value wg.Add(1) go func(n SendOnlyNode[CHAIN_ID, RPC_CLIENT]) { @@ -406,7 +406,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP if err != nil { c.lggr.Debugw("Secondary node BatchCallContext failed", "err", err) } else { - logger.Trace(c.lggr, "Secondary node BatchCallContext success") + c.lggr.Trace("Secondary node BatchCallContext success") } }(n) } @@ -561,6 +561,10 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP // main node is used at the end for the return value continue } + + if n.State() != nodeStateAlive { + continue + } // Parallel send to all other nodes with ignored return value // Async - we do not want to block the main thread with secondary nodes // in case they are unreliable/slow. diff --git a/common/client/multi_node_test.go b/common/client/multi_node_test.go index 229f1320a14..397150890d5 100644 --- a/common/client/multi_node_test.go +++ b/common/client/multi_node_test.go @@ -1,13 +1,13 @@ package client import ( + "errors" "fmt" - big "math/big" + "math/big" "math/rand" "testing" "time" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -533,8 +533,10 @@ func TestMultiNode_BatchCallContextAll(t *testing.T) { // setup ok and failed auxiliary nodes okNode := newMockSendOnlyNode[types.ID, multiNodeRPCClient](t) okNode.On("RPC").Return(okRPC).Once() + okNode.On("State").Return(nodeStateAlive).Once() failedNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) failedNode.On("RPC").Return(failedRPC).Once() + failedNode.On("State").Return(nodeStateAlive).Once() // setup main node mainNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) @@ -555,6 +557,34 @@ func TestMultiNode_BatchCallContextAll(t *testing.T) { require.NoError(t, err) tests.RequireLogMessage(t, observedLogs, "Secondary node BatchCallContext failed") }) + t.Run("Skips nodes that are not alive", func(t *testing.T) { + // setup RPCs + okRPC := newMultiNodeRPCClient(t) + okRPC.On("BatchCallContext", mock.Anything, mock.Anything).Return(nil).Twice() + + // setup ok and failed auxiliary nodes + okNode := newMockSendOnlyNode[types.ID, multiNodeRPCClient](t) + okNode.On("RPC").Return(okRPC).Once() + okNode.On("State").Return(nodeStateAlive).Once() + unhealthyNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + unhealthyNode.On("State").Return(nodeStateUnreachable).Once() + + // setup main node + mainNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + mainNode.On("RPC").Return(okRPC) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(mainNode).Once() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: types.RandomID(), + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{unhealthyNode, mainNode}, + sendonlys: []SendOnlyNode[types.ID, multiNodeRPCClient]{okNode}, + }) + mn.nodeSelector = nodeSelector + + err := mn.BatchCallContextAll(tests.Context(t), nil) + require.NoError(t, err) + }) } func TestMultiNode_SendTransaction(t *testing.T) { @@ -601,9 +631,11 @@ func TestMultiNode_SendTransaction(t *testing.T) { okNode := newMockSendOnlyNode[types.ID, multiNodeRPCClient](t) okNode.On("RPC").Return(okRPC).Once() okNode.On("String").Return("okNode") + okNode.On("State").Return(nodeStateAlive).Once() failedNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) failedNode.On("RPC").Return(failedRPC).Once() failedNode.On("String").Return("failedNode") + failedNode.On("State").Return(nodeStateAlive).Once() // setup main node mainNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) @@ -632,4 +664,38 @@ func TestMultiNode_SendTransaction(t *testing.T) { tests.AssertLogEventually(t, observedLogs, "Sendonly node sent transaction") tests.AssertLogEventually(t, observedLogs, "RPC returned error") }) + t.Run("Skips RPCs that are unhealthy", func(t *testing.T) { + // setup RPCs + okRPC := newMultiNodeRPCClient(t) + okRPC.On("SendTransaction", mock.Anything, mock.Anything).Return(nil).Once() + + // setup ok and failed auxiliary nodes + unhealthySendOnlyNode := newMockSendOnlyNode[types.ID, multiNodeRPCClient](t) + unhealthySendOnlyNode.On("State").Return(nodeStateUnreachable).Once() + unhealthyNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + unhealthyNode.On("State").Return(nodeStateUnreachable).Once() + + // setup main node + mainNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + mainNode.On("RPC").Return(okRPC) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(mainNode).Once() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: types.RandomID(), + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{unhealthyNode, mainNode}, + sendonlys: []SendOnlyNode[types.ID, multiNodeRPCClient]{unhealthySendOnlyNode}, + sendOnlyErrorParser: func(err error) SendTxReturnCode { + if err != nil { + return Fatal + } + + return Successful + }, + }) + mn.nodeSelector = nodeSelector + + err := mn.SendTransaction(tests.Context(t), nil) + require.NoError(t, err) + }) } diff --git a/common/client/node.go b/common/client/node.go index 4fad18b42cf..ce144bbca86 100644 --- a/common/client/node.go +++ b/common/client/node.go @@ -2,13 +2,13 @@ package client import ( "context" + "errors" "fmt" "math/big" "net/url" "sync" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -256,15 +256,15 @@ func (n *node[CHAIN_ID, HEAD, RPC]) verify(callerCtx context.Context) (err error var chainID CHAIN_ID if chainID, err = n.rpc.ChainID(callerCtx); err != nil { promFailed() - return errors.Wrapf(err, "failed to verify chain ID for node %s", n.name) + return fmt.Errorf("failed to verify chain ID for node %s: %w", n.name, err) } else if chainID.String() != n.chainID.String() { promFailed() - return errors.Wrapf( - errInvalidChainID, - "rpc ChainID doesn't match local chain ID: RPC ID=%s, local ID=%s, node name=%s", + return fmt.Errorf( + "rpc ChainID doesn't match local chain ID: RPC ID=%s, local ID=%s, node name=%s: %w", chainID.String(), n.chainID.String(), n.name, + errInvalidChainID, ) } diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go index 59a59691c83..af8f27d498d 100644 --- a/common/client/node_lifecycle.go +++ b/common/client/node_lifecycle.go @@ -2,19 +2,20 @@ package client import ( "context" + "errors" "fmt" "math" "math/big" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" - "github.com/smartcontractkit/chainlink/v2/core/utils" + iutils "github.com/smartcontractkit/chainlink/v2/common/internal/utils" ) var ( @@ -92,9 +93,8 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { pollFailureThreshold := n.nodePoolCfg.PollFailureThreshold() pollInterval := n.nodePoolCfg.PollInterval() - lggr := logger.Named(n.lfcLog, "Alive") - lggr = logger.With(lggr, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) - logger.Tracew(lggr, "Alive loop starting", "nodeState", n.State()) + lggr := logger.Sugared(n.lfcLog).Named("Alive").With("noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) + lggr.Tracew("Alive loop starting", "nodeState", n.State()) headsC := make(chan HEAD) sub, err := n.rpc.Subscribe(n.nodeCtx, headsC, rpcSubscriptionMethodNewHeads) @@ -145,7 +145,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { case <-pollCh: var version string promPoolRPCNodePolls.WithLabelValues(n.chainID.String(), n.name).Inc() - logger.Tracew(lggr, "Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) + lggr.Tracew("Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) ctx, cancel := context.WithTimeout(n.nodeCtx, pollInterval) version, err := n.RPC().ClientVersion(ctx) cancel() @@ -165,7 +165,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint failed to respond to %d consecutive polls", pollFailures), "pollFailures", pollFailures, "nodeState", n.State()) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - logger.Criticalf(lggr, "RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) continue } } @@ -177,7 +177,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { // note: there must be another live node for us to be out of sync lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", num, "totalDifficulty", td, "nodeState", n.State()) if liveNodes < 2 { - logger.Criticalf(lggr, "RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) continue } n.declareOutOfSync(n.isOutOfSync) @@ -190,13 +190,13 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { return } promPoolRPCNodeNumSeenBlocks.WithLabelValues(n.chainID.String(), n.name).Inc() - logger.Tracew(lggr, "Got head", "head", bh) + lggr.Tracew("Got head", "head", bh) if bh.BlockNumber() > highestReceivedBlockNumber { promPoolRPCNodeHighestSeenBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(bh.BlockNumber())) - logger.Tracew(lggr, "Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) + lggr.Tracew("Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) highestReceivedBlockNumber = bh.BlockNumber() } else { - logger.Tracew(lggr, "Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) + lggr.Tracew("Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.BlockNumber(), "nodeState", n.State()) } if outOfSyncT != nil { outOfSyncT.Reset(noNewHeadsTimeoutThreshold) @@ -212,7 +212,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint detected out of sync; no new heads received for %s (last head received was %v)", noNewHeadsTimeoutThreshold, highestReceivedBlockNumber), "nodeState", n.State(), "latestReceivedBlockNumber", highestReceivedBlockNumber, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - logger.Criticalf(lggr, "RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) // We don't necessarily want to wait the full timeout to check again, we should // check regularly and log noisily in this state outOfSyncT.Reset(zombieNodeCheckInterval(n.noNewHeadsThreshold)) @@ -278,7 +278,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td outOfSyncAt := time.Now() - lggr := logger.Named(n.lfcLog, "OutOfSync") + lggr := logger.Sugared(logger.Named(n.lfcLog, "OutOfSync")) lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.State()) // Need to redial since out-of-sync nodes are automatically disconnected @@ -295,7 +295,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td return } - logger.Tracew(lggr, "Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) + lggr.Tracew("Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) ch := make(chan HEAD) sub, err := n.rpc.Subscribe(n.nodeCtx, ch, rpcSubscriptionMethodNewHeads) @@ -327,7 +327,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td case <-time.After(zombieNodeCheckInterval(n.noNewHeadsThreshold)): if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 1 { - logger.Critical(lggr, "RPC endpoint is still out of sync, but there are no other available nodes. This RPC node will be forcibly moved back into the live pool in a degraded state") + lggr.Critical("RPC endpoint is still out of sync, but there are no other available nodes. This RPC node will be forcibly moved back into the live pool in a degraded state") n.declareInSync() return } @@ -357,17 +357,17 @@ func (n *node[CHAIN_ID, HEAD, RPC]) unreachableLoop() { unreachableAt := time.Now() - lggr := logger.Named(n.lfcLog, "Unreachable") + lggr := logger.Sugared(logger.Named(n.lfcLog, "Unreachable")) lggr.Debugw("Trying to revive unreachable RPC node", "nodeState", n.State()) - dialRetryBackoff := utils.NewRedialBackoff() + dialRetryBackoff := iutils.NewRedialBackoff() for { select { case <-n.nodeCtx.Done(): return case <-time.After(dialRetryBackoff.Duration()): - logger.Tracew(lggr, "Trying to re-dial RPC node", "nodeState", n.State()) + lggr.Tracew("Trying to re-dial RPC node", "nodeState", n.State()) err := n.rpc.Dial(n.nodeCtx) if err != nil { @@ -416,7 +416,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) invalidChainIDLoop() { lggr := logger.Named(n.lfcLog, "InvalidChainID") lggr.Debugw(fmt.Sprintf("Periodically re-checking RPC node %s with invalid chain ID", n.String()), "nodeState", n.State()) - chainIDRecheckBackoff := utils.NewRedialBackoff() + chainIDRecheckBackoff := iutils.NewRedialBackoff() for { select { diff --git a/common/client/node_lifecycle_test.go b/common/client/node_lifecycle_test.go index 224b79d8378..bf94e6bd063 100644 --- a/common/client/node_lifecycle_test.go +++ b/common/client/node_lifecycle_test.go @@ -1,13 +1,13 @@ package client import ( + "errors" "fmt" big "math/big" "sync/atomic" "testing" "github.com/cometbft/cometbft/libs/rand" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "go.uber.org/zap" diff --git a/common/client/node_selector_priority_level_test.go b/common/client/node_selector_priority_level_test.go index ac84645e91c..15a7a7ac60b 100644 --- a/common/client/node_selector_priority_level_test.go +++ b/common/client/node_selector_priority_level_test.go @@ -17,72 +17,75 @@ func TestPriorityLevelNodeSelector(t *testing.T) { t.Parallel() type nodeClient NodeClient[types.ID, Head] - var nodes []Node[types.ID, Head, nodeClient] - n1 := newMockNode[types.ID, Head, nodeClient](t) - n1.On("State").Return(nodeStateAlive) - n1.On("Order").Return(int32(1)) - - n2 := newMockNode[types.ID, Head, nodeClient](t) - n2.On("State").Return(nodeStateAlive) - n2.On("Order").Return(int32(1)) - - n3 := newMockNode[types.ID, Head, nodeClient](t) - n3.On("State").Return(nodeStateAlive) - n3.On("Order").Return(int32(1)) - - nodes = append(nodes, n1, n2, n3) - selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) - assert.Same(t, nodes[0], selector.Select()) - assert.Same(t, nodes[1], selector.Select()) - assert.Same(t, nodes[2], selector.Select()) - assert.Same(t, nodes[0], selector.Select()) - assert.Same(t, nodes[1], selector.Select()) - assert.Same(t, nodes[2], selector.Select()) -} - -func TestPriorityLevelNodeSelector_None(t *testing.T) { - t.Parallel() - - type nodeClient NodeClient[types.ID, Head] - var nodes []Node[types.ID, Head, nodeClient] - - for i := 0; i < 3; i++ { - node := newMockNode[types.ID, Head, nodeClient](t) - if i == 0 { - // first node is out of sync - node.On("State").Return(nodeStateOutOfSync) - node.On("Order").Return(int32(1)) - } else { - // others are unreachable - node.On("State").Return(nodeStateUnreachable) - node.On("Order").Return(int32(1)) - } - nodes = append(nodes, node) + type testNode struct { + order int32 + state nodeState + } + type testCase struct { + name string + nodes []testNode + expect []int // indexes of the nodes expected to be returned by Select } - selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) - assert.Nil(t, selector.Select()) -} - -func TestPriorityLevelNodeSelector_DifferentOrder(t *testing.T) { - t.Parallel() - - type nodeClient NodeClient[types.ID, Head] - var nodes []Node[types.ID, Head, nodeClient] - n1 := newMockNode[types.ID, Head, nodeClient](t) - n1.On("State").Return(nodeStateAlive) - n1.On("Order").Return(int32(1)) - - n2 := newMockNode[types.ID, Head, nodeClient](t) - n2.On("State").Return(nodeStateAlive) - n2.On("Order").Return(int32(2)) - - n3 := newMockNode[types.ID, Head, nodeClient](t) - n3.On("State").Return(nodeStateAlive) - n3.On("Order").Return(int32(3)) + testCases := []testCase{ + { + name: "TwoNodesSameOrder: Highest Allowed Order", + nodes: []testNode{ + {order: 1, state: nodeStateAlive}, + {order: 1, state: nodeStateAlive}, + }, + expect: []int{0, 1, 0, 1, 0, 1}, + }, + { + name: "TwoNodesSameOrder: Lowest Allowed Order", + nodes: []testNode{ + {order: 100, state: nodeStateAlive}, + {order: 100, state: nodeStateAlive}, + }, + expect: []int{0, 1, 0, 1, 0, 1}, + }, + { + name: "NoneAvailable", + nodes: []testNode{ + {order: 1, state: nodeStateOutOfSync}, + {order: 1, state: nodeStateUnreachable}, + {order: 1, state: nodeStateUnreachable}, + }, + expect: []int{}, // no nodes should be selected + }, + { + name: "DifferentOrder", + nodes: []testNode{ + {order: 1, state: nodeStateAlive}, + {order: 2, state: nodeStateAlive}, + {order: 3, state: nodeStateAlive}, + }, + expect: []int{0, 0}, // only the highest order node should be selected + }, + } - nodes = append(nodes, n1, n2, n3) - selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) - assert.Same(t, nodes[0], selector.Select()) - assert.Same(t, nodes[0], selector.Select()) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var nodes []Node[types.ID, Head, nodeClient] + for _, tn := range tc.nodes { + node := newMockNode[types.ID, Head, nodeClient](t) + node.On("State").Return(tn.state) + node.On("Order").Return(tn.order) + nodes = append(nodes, node) + } + + selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) + for _, idx := range tc.expect { + if idx >= len(nodes) { + t.Fatalf("Invalid node index %d in test case '%s'", idx, tc.name) + } + assert.Same(t, nodes[idx], selector.Select()) + } + + // Check for nil selection if expected slice is empty + if len(tc.expect) == 0 { + assert.Nil(t, selector.Select()) + } + }) + } } diff --git a/common/client/send_only_node_lifecycle.go b/common/client/send_only_node_lifecycle.go index 4d5b102b5bd..c66d267ed42 100644 --- a/common/client/send_only_node_lifecycle.go +++ b/common/client/send_only_node_lifecycle.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/common/internal/utils" ) // verifyLoop may only be triggered once, on Start, if initial chain ID check diff --git a/common/client/send_only_node_test.go b/common/client/send_only_node_test.go index 459f923cba8..79f4bfd60e3 100644 --- a/common/client/send_only_node_test.go +++ b/common/client/send_only_node_test.go @@ -1,11 +1,11 @@ package client import ( + "errors" "fmt" "net/url" "testing" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" diff --git a/common/config/chaintype.go b/common/config/chaintype.go index 21fb8cd297d..9ef4864b86e 100644 --- a/common/config/chaintype.go +++ b/common/config/chaintype.go @@ -18,16 +18,17 @@ const ( ChainWeMix ChainType = "wemix" ChainKroma ChainType = "kroma" ChainZkSync ChainType = "zksync" + ChainScroll ChainType = "scroll" ) var ErrInvalidChainType = fmt.Errorf("must be one of %s or omitted", strings.Join([]string{ string(ChainArbitrum), string(ChainMetis), string(ChainXDai), string(ChainOptimismBedrock), string(ChainCelo), - string(ChainKroma), string(ChainWeMix), string(ChainZkSync)}, ", ")) + string(ChainKroma), string(ChainWeMix), string(ChainZkSync), string(ChainScroll)}, ", ")) // IsValid returns true if the ChainType value is known or empty. func (c ChainType) IsValid() bool { switch c { - case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo, ChainKroma, ChainWeMix, ChainZkSync: + case "", ChainArbitrum, ChainMetis, ChainOptimismBedrock, ChainXDai, ChainCelo, ChainKroma, ChainWeMix, ChainZkSync, ChainScroll: return true } return false diff --git a/common/fee/models.go b/common/fee/models.go index b843cc3f055..1fe4d2b053b 100644 --- a/common/fee/models.go +++ b/common/fee/models.go @@ -1,10 +1,10 @@ package fee import ( + "errors" + "fmt" "math/big" - "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-common/pkg/logger" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" "github.com/smartcontractkit/chainlink/v2/common/chains/label" @@ -47,15 +47,15 @@ func CalculateBumpedFee( bumpedFeePrice = maxFee(lggr, currentfeePrice, bumpedFeePrice, maxFeePrice, "fee price", toChainUnit) if bumpedFeePrice.Cmp(maxFeePrice) > 0 { - return maxFeePrice, errors.Wrapf(ErrBumpFeeExceedsLimit, "bumped fee price of %s would exceed configured max fee price of %s (original price was %s). %s", - toChainUnit(bumpedFeePrice), toChainUnit(maxFeePrice), toChainUnit(originalfeePrice), label.NodeConnectivityProblemWarning) + return maxFeePrice, fmt.Errorf("bumped fee price of %s would exceed configured max fee price of %s (original price was %s). %s: %w", + toChainUnit(bumpedFeePrice), toChainUnit(maxFeePrice), toChainUnit(originalfeePrice), label.NodeConnectivityProblemWarning, ErrBumpFeeExceedsLimit) } else if bumpedFeePrice.Cmp(originalfeePrice) == 0 { // NOTE: This really shouldn't happen since we enforce minimums for // FeeEstimator.BumpPercent and FeeEstimator.BumpMin in the config validation, // but it's here anyway for a "belts and braces" approach - return bumpedFeePrice, errors.Wrapf(ErrBump, "bumped fee price of %s is equal to original fee price of %s."+ + return bumpedFeePrice, fmt.Errorf("bumped fee price of %s is equal to original fee price of %s."+ " ACTION REQUIRED: This is a configuration error, you must increase either "+ - "FeeEstimator.BumpPercent or FeeEstimator.BumpMin", toChainUnit(bumpedFeePrice), toChainUnit(bumpedFeePrice)) + "FeeEstimator.BumpPercent or FeeEstimator.BumpMin: %w", toChainUnit(bumpedFeePrice), toChainUnit(bumpedFeePrice), ErrBump) } return bumpedFeePrice, nil } diff --git a/common/fee/utils.go b/common/fee/utils.go index 71ababddbe3..eeb2c966719 100644 --- a/common/fee/utils.go +++ b/common/fee/utils.go @@ -1,10 +1,10 @@ package fee import ( + "fmt" "math" "math/big" - "github.com/pkg/errors" "github.com/shopspring/decimal" ) @@ -12,7 +12,7 @@ func ApplyMultiplier(feeLimit uint32, multiplier float32) (uint32, error) { result := decimal.NewFromBigInt(big.NewInt(0).SetUint64(uint64(feeLimit)), 0).Mul(decimal.NewFromFloat32(multiplier)).IntPart() if result > math.MaxUint32 { - return 0, errors.Errorf("integer overflow when applying multiplier of %f to fee limit of %d", multiplier, feeLimit) + return 0, fmt.Errorf("integer overflow when applying multiplier of %f to fee limit of %d", multiplier, feeLimit) } return uint32(result), nil } diff --git a/common/headtracker/head_broadcaster.go b/common/headtracker/head_broadcaster.go index 0e676f864fa..758a7713846 100644 --- a/common/headtracker/head_broadcaster.go +++ b/common/headtracker/head_broadcaster.go @@ -9,9 +9,9 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const TrackableCallbackTimeout = 2 * time.Second @@ -30,7 +30,7 @@ type HeadBroadcaster[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] struct services.StateMachine logger logger.Logger callbacks callbackSet[H, BLOCK_HASH] - mailbox *utils.Mailbox[H] + mailbox *mailbox.Mailbox[H] mutex sync.Mutex chClose services.StopChan wgDone sync.WaitGroup @@ -48,7 +48,7 @@ func NewHeadBroadcaster[ return &HeadBroadcaster[H, BLOCK_HASH]{ logger: logger.Named(lggr, "HeadBroadcaster"), callbacks: make(callbackSet[H, BLOCK_HASH]), - mailbox: utils.NewSingleMailbox[H](), + mailbox: mailbox.NewSingle[H](), chClose: make(chan struct{}), } } diff --git a/common/headtracker/head_listener.go b/common/headtracker/head_listener.go index 2013895d0b8..e7ea4fb51ae 100644 --- a/common/headtracker/head_listener.go +++ b/common/headtracker/head_listener.go @@ -2,10 +2,11 @@ package headtracker import ( "context" + "errors" + "fmt" "sync/atomic" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -13,8 +14,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" + "github.com/smartcontractkit/chainlink/v2/common/internal/utils" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -202,7 +203,7 @@ func (hl *HeadListener[HTH, S, ID, BLOCK_HASH]) subscribeToHead(ctx context.Cont hl.headSubscription, err = hl.client.SubscribeNewHead(ctx, hl.chHeaders) if err != nil { close(hl.chHeaders) - return errors.Wrap(err, "Client#SubscribeNewHead") + return fmt.Errorf("Client#SubscribeNewHead: %w", err) } hl.connected.Store(true) diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index 6e379776c0f..4cc152fb9fe 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -2,20 +2,20 @@ package headtracker import ( "context" + "errors" "fmt" "sync" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -40,17 +40,17 @@ type HeadTracker[ BLOCK_HASH types.Hashable, ] struct { services.StateMachine - log logger.Logger + log logger.SugaredLogger headBroadcaster types.HeadBroadcaster[HTH, BLOCK_HASH] headSaver types.HeadSaver[HTH, BLOCK_HASH] - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor client htrktypes.Client[HTH, S, ID, BLOCK_HASH] chainID ID config htrktypes.Config htConfig htrktypes.HeadTrackerConfig - backfillMB *utils.Mailbox[HTH] - broadcastMB *utils.Mailbox[HTH] + backfillMB *mailbox.Mailbox[HTH] + broadcastMB *mailbox.Mailbox[HTH] headListener types.HeadListener[HTH, BLOCK_HASH] chStop services.StopChan wgDone sync.WaitGroup @@ -70,7 +70,7 @@ func NewHeadTracker[ htConfig htrktypes.HeadTrackerConfig, headBroadcaster types.HeadBroadcaster[HTH, BLOCK_HASH], headSaver types.HeadSaver[HTH, BLOCK_HASH], - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, getNilHead func() HTH, ) types.HeadTracker[HTH, BLOCK_HASH] { chStop := make(chan struct{}) @@ -81,9 +81,9 @@ func NewHeadTracker[ chainID: client.ConfiguredChainID(), config: config, htConfig: htConfig, - log: lggr, - backfillMB: utils.NewSingleMailbox[HTH](), - broadcastMB: utils.NewMailbox[HTH](HeadsBufferSize), + log: logger.Sugared(lggr), + backfillMB: mailbox.NewSingle[HTH](), + broadcastMB: mailbox.New[HTH](HeadsBufferSize), chStop: chStop, headListener: NewHeadListener[HTH, S, ID, BLOCK_HASH](lggr, client, config, chStop), headSaver: headSaver, @@ -123,7 +123,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) Start(ctx context.Context) error ht.log.Errorw("Error getting initial head", "err", err) } else if initialHead.IsValid() { if err := ht.handleNewHead(ctx, initialHead); err != nil { - return errors.Wrap(err, "error handling initial head") + return fmt.Errorf("error handling initial head: %w", err) } } else { ht.log.Debug("Got nil initial head") @@ -179,7 +179,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) LatestChain() HTH { func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) getInitialHead(ctx context.Context) (HTH, error) { head, err := ht.client.HeadByNumber(ctx, nil) if err != nil { - return ht.getNilHead(), errors.Wrap(err, "failed to fetch initial head") + return ht.getNilHead(), fmt.Errorf("failed to fetch initial head: %w", err) } loggerFields := []interface{}{"head", head} if head.IsValid() { @@ -204,7 +204,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context if ctx.Err() != nil { return nil } else if err != nil { - return errors.Wrapf(err, "failed to save head: %#v", head) + return fmt.Errorf("failed to save head: %#v: %w", head, err) } if !prevHead.IsValid() || head.BlockNumber() > prevHead.BlockNumber() { @@ -212,7 +212,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context headWithChain := ht.headSaver.Chain(head.BlockHash()) if !headWithChain.IsValid() { - return errors.Errorf("HeadTracker#handleNewHighestHead headWithChain was unexpectedly nil") + return fmt.Errorf("HeadTracker#handleNewHighestHead headWithChain was unexpectedly nil") } ht.backfillMB.Deliver(headWithChain) ht.broadcastMB.Deliver(headWithChain) @@ -227,7 +227,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context prevUnFinalizedHead := prevHead.BlockNumber() - int64(ht.config.FinalityDepth()) if head.BlockNumber() < prevUnFinalizedHead { promOldHead.WithLabelValues(ht.chainID.String()).Inc() - logger.Criticalf(ht.log, "Got very old block with number %d (highest seen was %d). This is a problem and either means a very deep re-org occurred, one of the RPC nodes has gotten far out of sync, or the chain went backwards in block numbers. This node may not function correctly without manual intervention.", head.BlockNumber(), prevHead.BlockNumber()) + ht.log.Criticalf("Got very old block with number %d (highest seen was %d). This is a problem and either means a very deep re-org occurred, one of the RPC nodes has gotten far out of sync, or the chain went backwards in block numbers. This node may not function correctly without manual intervention.", head.BlockNumber(), prevHead.BlockNumber()) ht.SvcErrBuffer.Append(errors.New("got very old block")) } } @@ -310,7 +310,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) backfill(ctx context.Context, hea } mark := time.Now() fetched := 0 - l := logger.With(ht.log, "blockNumber", headBlockNumber, + l := ht.log.With("blockNumber", headBlockNumber, "n", headBlockNumber-baseHeight, "fromBlockHeight", baseHeight, "toBlockHeight", headBlockNumber-1) @@ -339,7 +339,7 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) backfill(ctx context.Context, hea ht.log.Debugw("context canceled, aborting backfill", "err", err, "ctx.Err", ctx.Err()) break } else if err != nil { - return errors.Wrap(err, "fetchAndSaveHead failed") + return fmt.Errorf("fetchAndSaveHead failed: %w", err) } } return diff --git a/common/headtracker/types/mocks/head.go b/common/headtracker/types/mocks/head.go index 79c483c9978..f86df1d7fce 100644 --- a/common/headtracker/types/mocks/head.go +++ b/common/headtracker/types/mocks/head.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type Head[BLOCK_HASH types.Hashable, CHAIN_ID types.ID] struct { func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockDifficulty() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockDifficulty") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -37,6 +41,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockDifficulty() *big.Int { func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockHash() BLOCK_HASH { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockHash") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func() BLOCK_HASH); ok { r0 = rf() @@ -51,6 +59,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockHash() BLOCK_HASH { func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockNumber() int64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + var r0 int64 if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() @@ -65,6 +77,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) BlockNumber() int64 { func (_m *Head[BLOCK_HASH, CHAIN_ID]) ChainID() CHAIN_ID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 CHAIN_ID if rf, ok := ret.Get(0).(func() CHAIN_ID); ok { r0 = rf() @@ -79,6 +95,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) ChainID() CHAIN_ID { func (_m *Head[BLOCK_HASH, CHAIN_ID]) ChainLength() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainLength") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -93,6 +113,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) ChainLength() uint32 { func (_m *Head[BLOCK_HASH, CHAIN_ID]) EarliestHeadInChain() types.Head[BLOCK_HASH] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EarliestHeadInChain") + } + var r0 types.Head[BLOCK_HASH] if rf, ok := ret.Get(0).(func() types.Head[BLOCK_HASH]); ok { r0 = rf() @@ -109,6 +133,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) EarliestHeadInChain() types.Head[BLOCK_HAS func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParent() types.Head[BLOCK_HASH] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetParent") + } + var r0 types.Head[BLOCK_HASH] if rf, ok := ret.Get(0).(func() types.Head[BLOCK_HASH]); ok { r0 = rf() @@ -125,6 +153,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParent() types.Head[BLOCK_HASH] { func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParentHash() BLOCK_HASH { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetParentHash") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func() BLOCK_HASH); ok { r0 = rf() @@ -139,6 +171,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParentHash() BLOCK_HASH { func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetTimestamp() time.Time { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetTimestamp") + } + var r0 time.Time if rf, ok := ret.Get(0).(func() time.Time); ok { r0 = rf() @@ -153,6 +189,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetTimestamp() time.Time { func (_m *Head[BLOCK_HASH, CHAIN_ID]) HasChainID() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HasChainID") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -167,6 +207,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) HasChainID() bool { func (_m *Head[BLOCK_HASH, CHAIN_ID]) HashAtHeight(blockNum int64) BLOCK_HASH { ret := _m.Called(blockNum) + if len(ret) == 0 { + panic("no return value specified for HashAtHeight") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func(int64) BLOCK_HASH); ok { r0 = rf(blockNum) @@ -181,6 +225,10 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) HashAtHeight(blockNum int64) BLOCK_HASH { func (_m *Head[BLOCK_HASH, CHAIN_ID]) IsValid() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsValid") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() diff --git a/common/internal/utils/utils.go b/common/internal/utils/utils.go new file mode 100644 index 00000000000..1e285868c53 --- /dev/null +++ b/common/internal/utils/utils.go @@ -0,0 +1,36 @@ +package utils + +import ( + "cmp" + "slices" + "time" + + "github.com/jpillora/backoff" + "golang.org/x/exp/constraints" +) + +// NewRedialBackoff is a standard backoff to use for redialling or reconnecting to +// unreachable network endpoints +func NewRedialBackoff() backoff.Backoff { + return backoff.Backoff{ + Min: 1 * time.Second, + Max: 15 * time.Second, + Jitter: true, + } + +} + +// MinFunc returns the minimum value of the given element array with respect +// to the given key function. In the event U is not a compound type (e.g a +// struct) an identity function can be provided. +func MinFunc[U any, T constraints.Ordered](elems []U, f func(U) T) T { + var min T + if len(elems) == 0 { + return min + } + + e := slices.MinFunc(elems, func(a, b U) int { + return cmp.Compare(f(a), f(b)) + }) + return f(e) +} diff --git a/common/mocks/head_broadcaster.go b/common/mocks/head_broadcaster.go index 12036f67843..265fceae91e 100644 --- a/common/mocks/head_broadcaster.go +++ b/common/mocks/head_broadcaster.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -23,6 +23,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) BroadcastNewLongestChain(_a0 H) { func (_m *HeadBroadcaster[H, BLOCK_HASH]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -37,6 +41,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Close() error { func (_m *HeadBroadcaster[H, BLOCK_HASH]) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -53,6 +61,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) HealthReport() map[string]error { func (_m *HeadBroadcaster[H, BLOCK_HASH]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -67,6 +79,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Name() string { func (_m *HeadBroadcaster[H, BLOCK_HASH]) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -81,6 +97,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Ready() error { func (_m *HeadBroadcaster[H, BLOCK_HASH]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -95,6 +115,10 @@ func (_m *HeadBroadcaster[H, BLOCK_HASH]) Start(_a0 context.Context) error { func (_m *HeadBroadcaster[H, BLOCK_HASH]) Subscribe(callback types.HeadTrackable[H, BLOCK_HASH]) (H, func()) { ret := _m.Called(callback) + if len(ret) == 0 { + panic("no return value specified for Subscribe") + } + var r0 H var r1 func() if rf, ok := ret.Get(0).(func(types.HeadTrackable[H, BLOCK_HASH]) (H, func())); ok { diff --git a/common/mocks/head_tracker.go b/common/mocks/head_tracker.go index 2a1f64eeeb7..83ee54b1847 100644 --- a/common/mocks/head_tracker.go +++ b/common/mocks/head_tracker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type HeadTracker[H types.Head[BLOCK_HASH], BLOCK_HASH types.Hashable] struct { func (_m *HeadTracker[H, BLOCK_HASH]) Backfill(ctx context.Context, headWithChain H, depth uint) error { ret := _m.Called(ctx, headWithChain, depth) + if len(ret) == 0 { + panic("no return value specified for Backfill") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, H, uint) error); ok { r0 = rf(ctx, headWithChain, depth) @@ -32,6 +36,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) Backfill(ctx context.Context, headWithChai func (_m *HeadTracker[H, BLOCK_HASH]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -46,6 +54,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) Close() error { func (_m *HeadTracker[H, BLOCK_HASH]) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -62,6 +74,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) HealthReport() map[string]error { func (_m *HeadTracker[H, BLOCK_HASH]) LatestChain() H { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LatestChain") + } + var r0 H if rf, ok := ret.Get(0).(func() H); ok { r0 = rf() @@ -76,6 +92,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) LatestChain() H { func (_m *HeadTracker[H, BLOCK_HASH]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -90,6 +110,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) Name() string { func (_m *HeadTracker[H, BLOCK_HASH]) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -104,6 +128,10 @@ func (_m *HeadTracker[H, BLOCK_HASH]) Ready() error { func (_m *HeadTracker[H, BLOCK_HASH]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/common/txmgr/broadcaster.go b/common/txmgr/broadcaster.go index 54ae653f662..9f2204f37e2 100644 --- a/common/txmgr/broadcaster.go +++ b/common/txmgr/broadcaster.go @@ -3,13 +3,13 @@ package txmgr import ( "context" "database/sql" + "errors" "fmt" "slices" "sync" "time" "github.com/jpillora/backoff" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" @@ -18,12 +18,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/chains/label" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -82,7 +82,7 @@ type TransmitChecker[ // is returned. Errors should only be returned if the checker can confirm that a transaction // should not be sent, other errors (for example connection or other unexpected errors) should // be logged and swallowed. - Check(ctx context.Context, l logger.Logger, tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], a txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error + Check(ctx context.Context, l logger.SugaredLogger, tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], a txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error } // Broadcaster monitors txes for transactions that need to @@ -108,7 +108,7 @@ type Broadcaster[ FEE feetypes.Fee, ] struct { services.StateMachine - lggr logger.Logger + lggr logger.SugaredLogger txStore txmgrtypes.TransactionStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, SEQ, FEE] client txmgrtypes.TransactionClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] @@ -172,7 +172,7 @@ func NewBroadcaster[ ) *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] { lggr = logger.Named(lggr, "Broadcaster") b := &Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]{ - lggr: lggr, + lggr: logger.Sugared(lggr), txStore: txStore, client: client, TxAttemptBuilder: txAttemptBuilder, @@ -210,7 +210,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) star var err error eb.enabledAddresses, err = eb.ks.EnabledAddressesForChain(eb.chainID) if err != nil { - return errors.Wrap(err, "Broadcaster: failed to load EnabledAddressesForChain") + return fmt.Errorf("Broadcaster: failed to load EnabledAddressesForChain: %w", err) } if len(eb.enabledAddresses) > 0 { @@ -246,7 +246,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) clos eb.initSync.Lock() defer eb.initSync.Unlock() if !eb.isStarted { - return errors.Wrap(services.ErrAlreadyStopped, "Broadcaster is not started") + return fmt.Errorf("Broadcaster is not started: %w", services.ErrAlreadyStopped) } close(eb.chStop) eb.wg.Wait() @@ -311,7 +311,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) getS if err == nil { return seq, nil } - logger.Criticalw(eb.lggr, "failed to retrieve next sequence from on-chain for address: ", "address", address.String()) + eb.lggr.Criticalw("failed to retrieve next sequence from on-chain for address: ", "address", address.String()) return seq, err } @@ -399,7 +399,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Sync localSequence, err := eb.GetNextSequence(ctx, addr) // Address not found in map so skip sync if err != nil { - logger.Criticalw(eb.lggr, "Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) + eb.lggr.Criticalw("Failed to retrieve local next sequence for address", "address", addr.String(), "err", err) return } @@ -414,7 +414,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Sync newNextSequence, err := eb.sequenceSyncer.Sync(ctx, addr, localSequence) if err != nil { if attempt > 5 { - logger.Criticalw(eb.lggr, "Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) + eb.lggr.Criticalw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) eb.SvcErrBuffer.Append(err) } else { eb.lggr.Warnw("Failed to sync with on-chain sequence", "address", addr.String(), "attempt", attempt, "err", err) @@ -454,19 +454,19 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc err, retryable = eb.handleAnyInProgressTx(ctx, fromAddress) if err != nil { - return retryable, errors.Wrap(err, "processUnstartedTxs failed on handleAnyInProgressTx") + return retryable, fmt.Errorf("processUnstartedTxs failed on handleAnyInProgressTx: %w", err) } for { maxInFlightTransactions := eb.txConfig.MaxInFlight() if maxInFlightTransactions > 0 { nUnconfirmed, err := eb.txStore.CountUnconfirmedTransactions(ctx, fromAddress, eb.chainID) if err != nil { - return true, errors.Wrap(err, "CountUnconfirmedTransactions failed") + return true, fmt.Errorf("CountUnconfirmedTransactions failed: %w", err) } if nUnconfirmed >= maxInFlightTransactions { nUnstarted, err := eb.txStore.CountUnstartedTransactions(ctx, fromAddress, eb.chainID) if err != nil { - return true, errors.Wrap(err, "CountUnstartedTransactions failed") + return true, fmt.Errorf("CountUnstartedTransactions failed: %w", err) } eb.lggr.Warnw(fmt.Sprintf(`Transaction throttling; %d transactions in-flight and %d unstarted transactions pending (maximum number of in-flight transactions is %d per key). %s`, nUnconfirmed, nUnstarted, maxInFlightTransactions, label.MaxInFlightTransactionsWarning), "maxInFlightTransactions", maxInFlightTransactions, "nUnconfirmed", nUnconfirmed, "nUnstarted", nUnstarted) select { @@ -479,28 +479,15 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc } etx, err := eb.nextUnstartedTransactionWithSequence(fromAddress) if err != nil { - return true, errors.Wrap(err, "processUnstartedTxs failed on nextUnstartedTransactionWithSequence") + return true, fmt.Errorf("processUnstartedTxs failed on nextUnstartedTransactionWithSequence: %w", err) } if etx == nil { return false, nil } n++ - var a txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] - var retryable bool - a, _, _, retryable, err = eb.NewTxAttempt(ctx, *etx, eb.lggr) - if err != nil { - return retryable, errors.Wrap(err, "processUnstartedTxs failed on NewAttempt") - } - - if err := eb.txStore.UpdateTxUnstartedToInProgress(ctx, etx, &a); errors.Is(err, ErrTxRemoved) { - eb.lggr.Debugw("tx removed", "txID", etx.ID, "subject", etx.Subject) - continue - } else if err != nil { - return true, errors.Wrap(err, "processUnstartedTxs failed on UpdateTxUnstartedToInProgress") - } - if err, retryable := eb.handleInProgressTx(ctx, *etx, a, time.Now()); err != nil { - return retryable, errors.Wrap(err, "processUnstartedTxs failed on handleAnyInProgressTx") + if err, retryable := eb.handleUnstartedTx(ctx, etx); err != nil { + return retryable, fmt.Errorf("processUnstartedTxs failed on handleUnstartedTx: %w", err) } } } @@ -510,50 +497,74 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) proc func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleAnyInProgressTx(ctx context.Context, fromAddress ADDR) (err error, retryable bool) { etx, err := eb.txStore.GetTxInProgress(ctx, fromAddress) if err != nil { - return errors.Wrap(err, "handleAnyInProgressTx failed"), true + return fmt.Errorf("handleAnyInProgressTx failed: %w", err), true } if etx != nil { if err, retryable := eb.handleInProgressTx(ctx, *etx, etx.TxAttempts[0], etx.CreatedAt); err != nil { - return errors.Wrap(err, "handleAnyInProgressTx failed"), retryable + return fmt.Errorf("handleAnyInProgressTx failed: %w", err), retryable } } return nil, false } -// There can be at most one in_progress transaction per address. -// Here we complete the job that we didn't finish last time. -func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleInProgressTx(ctx context.Context, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (error, bool) { - if etx.State != TxInProgress { - return errors.Errorf("invariant violation: expected transaction %v to be in_progress, it was %s", etx.ID, etx.State), false +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleUnstartedTx(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) (error, bool) { + if etx.State != TxUnstarted { + return fmt.Errorf("invariant violation: expected transaction %v to be unstarted, it was %s", etx.ID, etx.State), false + } + + attempt, _, _, retryable, err := eb.NewTxAttempt(ctx, *etx, eb.lggr) + if err != nil { + return fmt.Errorf("processUnstartedTxs failed on NewAttempt: %w", err), retryable } checkerSpec, err := etx.GetChecker() if err != nil { - return errors.Wrap(err, "parsing transmit checker"), false + return fmt.Errorf("parsing transmit checker: %w", err), false } checker, err := eb.checkerFactory.BuildChecker(checkerSpec) if err != nil { - return errors.Wrap(err, "building transmit checker"), false + return fmt.Errorf("building transmit checker: %w", err), false } - lgr := etx.GetLogger(logger.With(eb.lggr, "fee", attempt.TxFee)) + lgr := etx.GetLogger(eb.lggr.With("fee", attempt.TxFee)) // If the transmit check does not complete within the timeout, the transaction will be sent // anyway. + // It's intentional that we only run `Check` for unstarted transactions. + // Running it on other states might lead to nonce duplication, as we might mark applied transactions as fatally errored. + checkCtx, cancel := context.WithTimeout(ctx, TransmitCheckTimeout) defer cancel() - err = checker.Check(checkCtx, lgr, etx, attempt) + err = checker.Check(checkCtx, lgr, *etx, attempt) if errors.Is(err, context.Canceled) { lgr.Warn("Transmission checker timed out, sending anyway") } else if err != nil { etx.Error = null.StringFrom(err.Error()) lgr.Warnw("Transmission checker failed, fatally erroring transaction.", "err", err) - return eb.saveFatallyErroredTransaction(lgr, &etx), true + return eb.saveFatallyErroredTransaction(lgr, etx), true } cancel() - lgr.Infow("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "err", err, "meta", etx.Meta, "feeLimit", etx.FeeLimit, "attempt", attempt, "etx", etx) + if err = eb.txStore.UpdateTxUnstartedToInProgress(ctx, etx, &attempt); errors.Is(err, ErrTxRemoved) { + eb.lggr.Debugw("tx removed", "txID", etx.ID, "subject", etx.Subject) + return nil, false + } else if err != nil { + return fmt.Errorf("processUnstartedTxs failed on UpdateTxUnstartedToInProgress: %w", err), true + } + + return eb.handleInProgressTx(ctx, *etx, attempt, time.Now()) +} + +// There can be at most one in_progress transaction per address. +// Here we complete the job that we didn't finish last time. +func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) handleInProgressTx(ctx context.Context, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (error, bool) { + if etx.State != TxInProgress { + return fmt.Errorf("invariant violation: expected transaction %v to be in_progress, it was %s", etx.ID, etx.State), false + } + + lgr := etx.GetLogger(logger.With(eb.lggr, "fee", attempt.TxFee)) + lgr.Infow("Sending transaction", "txAttemptID", attempt.ID, "txHash", attempt.Hash, "meta", etx.Meta, "feeLimit", etx.FeeLimit, "attempt", attempt, "etx", etx) errType, err := eb.client.SendTransactionReturnCode(ctx, etx, attempt, lgr) if errType != client.Fatal { @@ -647,19 +658,19 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // If there is only one RPC node, or all RPC nodes have the same // configured cap, this transaction will get stuck and keep repeating // forever until the issue is resolved. - logger.Criticalw(lgr, `RPC node rejected this tx as outside Fee Cap`) + lgr.Criticalw(`RPC node rejected this tx as outside Fee Cap`, "attempt", attempt) fallthrough default: // Every error that doesn't fall under one of the above categories will be treated as Unknown. fallthrough case client.Unknown: eb.SvcErrBuffer.Append(err) - logger.Criticalw(lgr, `Unknown error occurred while handling tx queue in ProcessUnstartedTxs. This chain/RPC client may not be supported. `+ - `Urgent resolution required, Chainlink is currently operating in a degraded state and may miss transactions`, "err", err, "etx", etx, "attempt", attempt) + lgr.Criticalw(`Unknown error occurred while handling tx queue in ProcessUnstartedTxs. This chain/RPC client may not be supported. `+ + `Urgent resolution required, Chainlink is currently operating in a degraded state and may miss transactions`, "attempt", attempt) nextSequence, e := eb.client.PendingSequenceAt(ctx, etx.FromAddress) if e != nil { err = multierr.Combine(e, err) - return errors.Wrapf(err, "failed to fetch latest pending sequence after encountering unknown RPC error while sending transaction"), true + return fmt.Errorf("failed to fetch latest pending sequence after encountering unknown RPC error while sending transaction: %w", err), true } if nextSequence.Int64() > (*etx.Sequence).Int64() { // Despite the error, the RPC node considers the previously sent @@ -686,7 +697,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) hand // // In all cases, the best thing we can do is go into a retry loop and keep // trying to send the transaction over again. - return errors.Wrapf(err, "retryable error while sending transaction %s (tx ID %d)", attempt.Hash.String(), etx.ID), true + return fmt.Errorf("retryable error while sending transaction %s (tx ID %d): %w", attempt.Hash.String(), etx.ID, err), true } } @@ -702,7 +713,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) next // Finish. No more transactions left to process. Hoorah! return nil, nil } - return nil, errors.Wrap(err, "findNextUnstartedTransactionFromAddress failed") + return nil, fmt.Errorf("findNextUnstartedTransactionFromAddress failed: %w", err) } sequence, err := eb.GetNextSequence(ctx, etx.FromAddress) @@ -726,7 +737,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryA replacementAttempt, bumpedFee, bumpedFeeLimit, retryable, err := eb.NewBumpTxAttempt(ctx, etx, attempt, nil, lgr) if err != nil { - return errors.Wrap(err, "tryAgainBumpFee failed"), retryable + return fmt.Errorf("tryAgainBumpFee failed: %w", err), retryable } return eb.saveTryAgainAttempt(ctx, lgr, etx, attempt, replacementAttempt, initialBroadcastAt, bumpedFee, bumpedFeeLimit) @@ -734,14 +745,14 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryA func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryAgainWithNewEstimation(ctx context.Context, lgr logger.Logger, txError error, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time) (err error, retryable bool) { if attempt.TxType == 0x2 { - err = errors.Errorf("re-estimation is not supported for EIP-1559 transactions. Node returned error: %v. This is a bug", txError.Error()) + err = fmt.Errorf("re-estimation is not supported for EIP-1559 transactions. Node returned error: %v. This is a bug", txError.Error()) logger.Sugared(eb.lggr).AssumptionViolation(err.Error()) return err, false } replacementAttempt, fee, feeLimit, retryable, err := eb.NewTxAttemptWithType(ctx, etx, lgr, attempt.TxType, feetypes.OptForceRefetch) if err != nil { - return errors.Wrap(err, "tryAgainWithNewEstimation failed to build new attempt"), retryable + return fmt.Errorf("tryAgainWithNewEstimation failed to build new attempt: %w", err), retryable } lgr.Warnw("L2 rejected transaction due to incorrect fee, re-estimated and will try again", "etxID", etx.ID, "err", err, "newGasPrice", fee, "newGasLimit", feeLimit) @@ -751,7 +762,7 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) tryA func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) saveTryAgainAttempt(ctx context.Context, lgr logger.Logger, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], initialBroadcastAt time.Time, newFee FEE, newFeeLimit uint32) (err error, retyrable bool) { if err = eb.txStore.SaveReplacementInProgressAttempt(ctx, attempt, &replacementAttempt); err != nil { - return errors.Wrap(err, "tryAgainWithNewFee failed"), true + return fmt.Errorf("tryAgainWithNewFee failed: %w", err), true } lgr.Debugw("Bumped fee on initial send", "oldFee", attempt.TxFee.String(), "newFee", newFee.String(), "newFeeLimit", newFeeLimit) return eb.handleInProgressTx(ctx, etx, replacementAttempt, initialBroadcastAt) @@ -760,8 +771,8 @@ func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) save func (eb *Broadcaster[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) saveFatallyErroredTransaction(lgr logger.Logger, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ctx, cancel := eb.chStop.NewCtx() defer cancel() - if etx.State != TxInProgress { - return errors.Errorf("can only transition to fatal_error from in_progress, transaction is currently %s", etx.State) + if etx.State != TxInProgress && etx.State != TxUnstarted { + return fmt.Errorf("can only transition to fatal_error from in_progress or unstarted, transaction is currently %s", etx.State) } if !etx.Error.Valid { return errors.New("expected error field to be set") @@ -779,11 +790,11 @@ 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, errors.Errorf("fatal error while sending transaction: %s", etx.Error.String)) + err := eb.resumeCallback(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 { - return errors.Wrap(err, "failed to resume pipeline") + return fmt.Errorf("failed to resume pipeline: %w", err) } else { // Mark tx as having completed callback if err := eb.txStore.UpdateTxCallbackCompleted(ctx, etx.PipelineTaskRunID.UUID, eb.chainID); err != nil { diff --git a/common/txmgr/confirmer.go b/common/txmgr/confirmer.go index a56768ce206..d55f982c11f 100644 --- a/common/txmgr/confirmer.go +++ b/common/txmgr/confirmer.go @@ -3,27 +3,30 @@ package txmgr import ( "context" "encoding/hex" + "errors" "fmt" "sort" "strconv" "sync" "time" - "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" + commonhex "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink-common/pkg/chains/label" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" + iutils "github.com/smartcontractkit/chainlink/v2/common/internal/utils" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -116,7 +119,7 @@ type Confirmer[ ] struct { services.StateMachine txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] - lggr logger.Logger + lggr logger.SugaredLogger client txmgrtypes.TxmClient[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] txmgrtypes.TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] resumeCallback ResumeCallback @@ -129,7 +132,7 @@ type Confirmer[ ks txmgrtypes.KeyStore[ADDR, CHAIN_ID, SEQ] enabledAddresses []ADDR - mb *utils.Mailbox[HEAD] + mb *mailbox.Mailbox[HEAD] ctx context.Context ctxCancel context.CancelFunc wg sync.WaitGroup @@ -164,7 +167,7 @@ func NewConfirmer[ lggr = logger.Named(lggr, "Confirmer") return &Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{ txStore: txStore, - lggr: lggr, + lggr: logger.Sugared(lggr), client: client, TxAttemptBuilder: txAttemptBuilder, resumeCallback: nil, @@ -174,7 +177,7 @@ func NewConfirmer[ dbConfig: dbConfig, chainID: client.ConfiguredChainID(), ks: keystore, - mb: utils.NewSingleMailbox[HEAD](), + mb: mailbox.NewSingle[HEAD](), isReceiptNil: isReceiptNil, } } @@ -201,7 +204,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) sta var err error ec.enabledAddresses, err = ec.ks.EnabledAddressesForChain(ec.chainID) if err != nil { - return errors.Wrap(err, "Confirmer: failed to load EnabledAddressesForChain") + return fmt.Errorf("Confirmer: failed to load EnabledAddressesForChain: %w", err) } ec.ctx, ec.ctxCancel = context.WithCancel(context.Background()) @@ -223,7 +226,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) clo ec.initSync.Lock() defer ec.initSync.Unlock() if !ec.isStarted { - return errors.Wrap(utils.ErrAlreadyStopped, "Confirmer is not started") + return fmt.Errorf("Confirmer is not started: %w", services.ErrAlreadyStopped) } ec.ctxCancel() ec.wg.Wait() @@ -281,28 +284,28 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) pro ec.lggr.Debugw("processHead start", "headNum", head.BlockNumber(), "id", "confirmer") if err := ec.txStore.SetBroadcastBeforeBlockNum(ctx, head.BlockNumber(), ec.chainID); err != nil { - return errors.Wrap(err, "SetBroadcastBeforeBlockNum failed") + return fmt.Errorf("SetBroadcastBeforeBlockNum failed: %w", err) } if err := ec.CheckConfirmedMissingReceipt(ctx); err != nil { - return errors.Wrap(err, "CheckConfirmedMissingReceipt failed") + return fmt.Errorf("CheckConfirmedMissingReceipt failed: %w", err) } if err := ec.CheckForReceipts(ctx, head.BlockNumber()); err != nil { - return errors.Wrap(err, "CheckForReceipts failed") + return fmt.Errorf("CheckForReceipts failed: %w", err) } ec.lggr.Debugw("Finished CheckForReceipts", "headNum", head.BlockNumber(), "time", time.Since(mark), "id", "confirmer") mark = time.Now() if err := ec.RebroadcastWhereNecessary(ctx, head.BlockNumber()); err != nil { - return errors.Wrap(err, "RebroadcastWhereNecessary failed") + return fmt.Errorf("RebroadcastWhereNecessary failed: %w", err) } ec.lggr.Debugw("Finished RebroadcastWhereNecessary", "headNum", head.BlockNumber(), "time", time.Since(mark), "id", "confirmer") mark = time.Now() if err := ec.EnsureConfirmedTransactionsInLongestChain(ctx, head); err != nil { - return errors.Wrap(err, "EnsureConfirmedTransactionsInLongestChain failed") + return fmt.Errorf("EnsureConfirmedTransactionsInLongestChain failed: %w", err) } ec.lggr.Debugw("Finished EnsureConfirmedTransactionsInLongestChain", "headNum", head.BlockNumber(), "time", time.Since(mark), "id", "confirmer") @@ -310,7 +313,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) pro if ec.resumeCallback != nil { mark = time.Now() if err := ec.ResumePendingTaskRuns(ctx, head); err != nil { - return errors.Wrap(err, "ResumePendingTaskRuns failed") + return fmt.Errorf("ResumePendingTaskRuns failed: %w", err) } ec.lggr.Debugw("Finished ResumePendingTaskRuns", "headNum", head.BlockNumber(), "time", time.Since(mark), "id", "confirmer") @@ -382,7 +385,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CheckForReceipts(ctx context.Context, blockNum int64) error { attempts, err := ec.txStore.FindTxAttemptsRequiringReceiptFetch(ctx, ec.chainID) if err != nil { - return errors.Wrap(err, "FindTxAttemptsRequiringReceiptFetch failed") + return fmt.Errorf("FindTxAttemptsRequiringReceiptFetch failed: %w", err) } if len(attempts) == 0 { return nil @@ -398,7 +401,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che for from, attempts := range attemptsByAddress { minedSequence, err := ec.getMinedSequenceForAddress(ctx, from) if err != nil { - return errors.Wrapf(err, "unable to fetch pending sequence for address: %v", from) + return fmt.Errorf("unable to fetch pending sequence for address: %v: %w", from, err) } // separateLikelyConfirmedAttempts is used as an optimisation: there is @@ -415,7 +418,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che start := time.Now() err = ec.fetchAndSaveReceipts(ctx, likelyConfirmed, blockNum) if err != nil { - return errors.Wrapf(err, "unable to fetch and save receipts for likely confirmed txs, for address: %v", from) + return fmt.Errorf("unable to fetch and save receipts for likely confirmed txs, for address: %v: %w", from, err) } ec.lggr.Debugw(fmt.Sprintf("Fetching and saving %v likely confirmed receipts done", likelyConfirmedCount), "time", time.Since(start)) @@ -423,11 +426,11 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Che } if err := ec.txStore.MarkAllConfirmedMissingReceipt(ctx, ec.chainID); err != nil { - return errors.Wrap(err, "unable to mark txes as 'confirmed_missing_receipt'") + return fmt.Errorf("unable to mark txes as 'confirmed_missing_receipt': %w", err) } if err := ec.txStore.MarkOldTxesMissingReceiptAsErrored(ctx, blockNum, ec.chainConfig.FinalityDepth(), ec.chainID); err != nil { - return errors.Wrap(err, "unable to confirm buried unconfirmed txes") + return fmt.Errorf("unable to confirm buried unconfirmed txes': %w", err) } return nil } @@ -488,10 +491,10 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) fet receipts, err := ec.batchFetchReceipts(ctx, batch, blockNum) if err != nil { - return errors.Wrap(err, "batchFetchReceipts failed") + return fmt.Errorf("batchFetchReceipts failed: %w", err) } if err := ec.txStore.SaveFetchedReceipts(ctx, receipts, ec.chainID); err != nil { - return errors.Wrap(err, "saveFetchedReceipts failed") + return fmt.Errorf("saveFetchedReceipts failed: %w", err) } promNumConfirmedTxs.WithLabelValues(ec.chainID.String()).Add(float64(len(receipts))) @@ -514,12 +517,11 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat if ec.txConfig.ForwardersEnabled() { err = ec.txStore.PreloadTxes(ctx, attempts) if err != nil { - return nil, errors.Wrap(err, "Confirmer#batchFetchReceipts error loading txs for attempts") + return nil, fmt.Errorf("Confirmer#batchFetchReceipts error loading txs for attempts: %w", err) } } - lggr := logger.Named(ec.lggr, "BatchFetchReceipts") - lggr = logger.With(lggr, "blockNum", blockNum) + lggr := ec.lggr.Named("BatchFetchReceipts").With("blockNum", blockNum) txReceipts, txErrs, err := ec.client.BatchGetReceipts(ctx, attempts) if err != nil { @@ -531,9 +533,9 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat receipt := txReceipts[i] err := txErrs[i] - l := logger.Sugared(logger.With(attempt.Tx.GetLogger(lggr), "txHash", attempt.Hash.String(), "txAttemptID", attempt.ID, + l := attempt.Tx.GetLogger(lggr).With("txHash", attempt.Hash.String(), "txAttemptID", attempt.ID, "txID", attempt.TxID, "err", err, "sequence", attempt.Tx.Sequence, - )) + ) if err != nil { l.Error("FetchReceipt failed") @@ -552,7 +554,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bat continue } - l = logger.Sugared(logger.With(l, "blockHash", receipt.GetBlockHash().String(), "status", receipt.GetStatus(), "transactionIndex", receipt.GetTransactionIndex())) + l = l.With("blockHash", receipt.GetBlockHash().String(), "status", receipt.GetStatus(), "transactionIndex", receipt.GetTransactionIndex()) if receipt.IsUnmined() { l.Debug("Got receipt for transaction but it's still in the mempool and not included in a block yet") @@ -629,7 +631,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reb func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) rebroadcastWhereNecessary(ctx context.Context, address ADDR, blockHeight int64) error { if err := ec.handleAnyInProgressAttempts(ctx, address, blockHeight); err != nil { - return errors.Wrap(err, "handleAnyInProgressAttempts failed") + return fmt.Errorf("handleAnyInProgressAttempts failed: %w", err) } threshold := int64(ec.feeConfig.BumpThreshold()) @@ -637,24 +639,24 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) reb maxInFlightTransactions := ec.txConfig.MaxInFlight() etxs, err := ec.FindTxsRequiringRebroadcast(ctx, ec.lggr, address, blockHeight, threshold, bumpDepth, maxInFlightTransactions, ec.chainID) if err != nil { - return errors.Wrap(err, "FindTxsRequiringRebroadcast failed") + return fmt.Errorf("FindTxsRequiringRebroadcast failed: %w", err) } for _, etx := range etxs { lggr := etx.GetLogger(ec.lggr) attempt, err := ec.attemptForRebroadcast(ctx, lggr, *etx) if err != nil { - return errors.Wrap(err, "attemptForRebroadcast failed") + return fmt.Errorf("attemptForRebroadcast failed: %w", err) } lggr.Debugw("Rebroadcasting transaction", "nPreviousAttempts", len(etx.TxAttempts), "fee", attempt.TxFee) if err := ec.txStore.SaveInProgressAttempt(ctx, &attempt); err != nil { - return errors.Wrap(err, "saveInProgressAttempt failed") + return fmt.Errorf("saveInProgressAttempt failed: %w", err) } if err := ec.handleInProgressAttempt(ctx, lggr, *etx, attempt, blockHeight); err != nil { - return errors.Wrap(err, "handleInProgressAttempt failed") + return fmt.Errorf("handleInProgressAttempt failed: %w", err) } } return nil @@ -670,14 +672,14 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han if ctx.Err() != nil { return nil } else if err != nil { - return errors.Wrap(err, "GetInProgressTxAttempts failed") + return fmt.Errorf("GetInProgressTxAttempts failed: %w", err) } for _, a := range attempts { err := ec.handleInProgressAttempt(ctx, a.Tx.GetLogger(ec.lggr), a.Tx, a, blockHeight) if ctx.Err() != nil { break } else if err != nil { - return errors.Wrap(err, "handleInProgressAttempt failed") + return fmt.Errorf("handleInProgressAttempt failed: %w", err) } } return nil @@ -769,7 +771,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) att } return attempt, err } - return attempt, errors.Errorf("invariant violation: Tx %v was unconfirmed but didn't have any attempts. "+ + return attempt, fmt.Errorf("invariant violation: Tx %v was unconfirmed but didn't have any attempts. "+ "Falling back to default gas price instead."+ "This is a bug! Please report to https://github.com/smartcontractkit/chainlink/issues", etx.ID) } @@ -802,17 +804,17 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) bum return bumpedAttempt, err } - if errors.Is(errors.Cause(err), commonfee.ErrBumpFeeExceedsLimit) { + if errors.Is(err, commonfee.ErrBumpFeeExceedsLimit) { promGasBumpExceedsLimit.WithLabelValues(ec.chainID.String()).Inc() } - return bumpedAttempt, errors.Wrap(err, "error bumping gas") + return bumpedAttempt, fmt.Errorf("error bumping gas: %w", err) } -func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleInProgressAttempt(ctx context.Context, lggr logger.Logger, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], blockHeight int64) error { +func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) handleInProgressAttempt(ctx context.Context, lggr logger.SugaredLogger, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], blockHeight int64) error { if attempt.State != txmgrtypes.TxAttemptInProgress { - return errors.Errorf("invariant violation: expected tx_attempt %v to be in_progress, it was %s", attempt.ID, attempt.State) + return fmt.Errorf("invariant violation: expected tx_attempt %v to be in_progress, it was %s", attempt.ID, attempt.State) } now := time.Now() @@ -823,28 +825,28 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han case client.Underpriced: // This should really not ever happen in normal operation since we // already bumped above the required minimum in broadcaster. - ec.lggr.Warnw("Got terminally underpriced error for gas bump, this should never happen unless the remote RPC node changed its configuration on the fly, or you are using multiple RPC nodes with different minimum gas price requirements. This is not recommended", "err", sendError, "attempt", attempt) + ec.lggr.Warnw("Got terminally underpriced error for gas bump, this should never happen unless the remote RPC node changed its configuration on the fly, or you are using multiple RPC nodes with different minimum gas price requirements. This is not recommended", "attempt", attempt) // "Lazily" load attempts here since the overwhelmingly common case is // that we don't need them unless we enter this path if err := ec.txStore.LoadTxAttempts(ctx, &etx); err != nil { - return errors.Wrap(err, "failed to load TxAttempts while bumping on terminally underpriced error") + return fmt.Errorf("failed to load TxAttempts while bumping on terminally underpriced error: %w", err) } if len(etx.TxAttempts) == 0 { err := errors.New("expected to find at least 1 attempt") - logger.Sugared(ec.lggr).AssumptionViolationw(err.Error(), "err", err, "attempt", attempt) + ec.lggr.AssumptionViolationw(err.Error(), "err", err, "attempt", attempt) return err } if attempt.ID != etx.TxAttempts[0].ID { err := errors.New("expected highest priced attempt to be the current in_progress attempt") - logger.Sugared(ec.lggr).AssumptionViolationw(err.Error(), "err", err, "attempt", attempt, "txAttempts", etx.TxAttempts) + ec.lggr.AssumptionViolationw(err.Error(), "err", err, "attempt", attempt, "txAttempts", etx.TxAttempts) return err } replacementAttempt, err := ec.bumpGas(ctx, etx, etx.TxAttempts) if err != nil { - return errors.Wrap(err, "could not bump gas for terminally underpriced transaction") + return fmt.Errorf("could not bump gas for terminally underpriced transaction: %w", err) } promNumGasBumps.WithLabelValues(ec.chainID.String()).Inc() - logger.With(lggr, + lggr.With( "sendError", sendError, "maxGasPriceConfig", ec.feeConfig.MaxFeePrice(), "previousAttempt", attempt, @@ -852,7 +854,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han ).Errorf("gas price was rejected by the node for being too low. Node returned: '%s'", sendError.Error()) if err := ec.txStore.SaveReplacementInProgressAttempt(ctx, attempt, &replacementAttempt); err != nil { - return errors.Wrap(err, "saveReplacementInProgressAttempt failed") + return fmt.Errorf("saveReplacementInProgressAttempt failed: %w", err) } return ec.handleInProgressAttempt(ctx, lggr, etx, replacementAttempt, blockHeight) case client.ExceedsMaxFee: @@ -865,11 +867,10 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han // Should NEVER be fatal this is an invariant violation. The // Broadcaster can never create a TxAttempt that will // fatally error. - logger.Criticalw(lggr, "Invariant violation: fatal error while re-attempting transaction", - "err", sendError, + lggr.Criticalw("Invariant violation: fatal error while re-attempting transaction", "fee", attempt.TxFee, "feeLimit", etx.FeeLimit, - "signedRawTx", utils.AddHexPrefix(hex.EncodeToString(attempt.SignedRawTx)), + "signedRawTx", commonhex.EnsurePrefix(hex.EncodeToString(attempt.SignedRawTx)), "blockHeight", blockHeight, ) ec.SvcErrBuffer.Append(sendError) @@ -878,7 +879,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han case client.TransactionAlreadyKnown: // Sequence too low indicated that a transaction at this sequence was confirmed already. // Mark confirmed_missing_receipt and wait for the next cycle to try to get a receipt - lggr.Debugw("Sequence already used", "txAttemptID", attempt.ID, "txHash", attempt.Hash.String(), "err", sendError) + lggr.Debugw("Sequence already used", "txAttemptID", attempt.ID, "txHash", attempt.Hash.String()) timeout := ec.dbConfig.DefaultQueryTimeout() return ec.txStore.SaveConfirmedMissingReceiptAttempt(ctx, timeout, &attempt, now) case client.InsufficientFunds: @@ -896,7 +897,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) han // node operator. The node may have it in the mempool so we must keep the // attempt (leave it in_progress). Safest thing to do is bail out and wait // for the next head. - return errors.Wrapf(sendError, "unexpected error sending tx %v with hash %s", etx.ID, attempt.Hash.String()) + return fmt.Errorf("unexpected error sending tx %v with hash %s: %w", etx.ID, attempt.Hash.String(), sendError) } } @@ -924,13 +925,13 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Ens } etxs, err := ec.txStore.FindTransactionsConfirmedInBlockRange(ctx, head.BlockNumber(), head.EarliestHeadInChain().BlockNumber(), ec.chainID) if err != nil { - return errors.Wrap(err, "findTransactionsConfirmedInBlockRange failed") + return fmt.Errorf("findTransactionsConfirmedInBlockRange failed: %w", err) } for _, etx := range etxs { if !hasReceiptInLongestChain(*etx, head) { if err := ec.markForRebroadcast(*etx, head); err != nil { - return errors.Wrapf(err, "markForRebroadcast failed for etx %v", etx.ID) + return fmt.Errorf("markForRebroadcast failed for etx %v: %w", etx.ID, err) } } } @@ -983,7 +984,7 @@ func hasReceiptInLongestChain[ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) markForRebroadcast(etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], head types.Head[BLOCK_HASH]) error { if len(etx.TxAttempts) == 0 { - return errors.Errorf("invariant violation: expected tx %v to have at least one attempt", etx.ID) + return fmt.Errorf("invariant violation: expected tx %v to have at least one attempt", etx.ID) } // Rebroadcast the one with the highest gas price @@ -1016,8 +1017,11 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) mar ec.lggr.Infow(fmt.Sprintf("Re-org detected. Rebroadcasting transaction %s which may have been re-org'd out of the main chain", attempt.Hash.String()), logValues...) // Put it back in progress and delete all receipts (they do not apply to the new chain) - err := ec.txStore.UpdateTxForRebroadcast(ec.ctx, etx, attempt) - return errors.Wrap(err, "markForRebroadcast failed") + if err := ec.txStore.UpdateTxForRebroadcast(ec.ctx, etx, attempt); err != nil { + return fmt.Errorf("markForRebroadcast failed: %w", err) + } + + return nil } // ForceRebroadcast sends a transaction for every sequence in the given sequence range at the given gas price. @@ -1037,7 +1041,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) For etx, err := ec.txStore.FindTxWithSequence(ctx, address, seq) if err != nil { - return errors.Wrap(err, "ForceRebroadcast failed") + return fmt.Errorf("ForceRebroadcast failed: %w", err) } if etx == nil { ec.lggr.Debugf("ForceRebroadcast: no tx found with sequence %s, will rebroadcast empty transaction", seq) @@ -1076,7 +1080,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) sen } txhash, err := ec.client.SendEmptyTransaction(ctx, ec.TxAttemptBuilder.NewEmptyTxAttempt, seq, gasLimit, fee, fromAddress) if err != nil { - return "", errors.Wrap(err, "(Confirmer).sendEmptyTransaction failed") + return "", fmt.Errorf("(Confirmer).sendEmptyTransaction failed: %w", err) } return txhash, nil } @@ -1099,7 +1103,7 @@ func (ec *Confirmer[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Res var taskErr error var output interface{} if data.FailOnRevert && data.Receipt.GetStatus() == 0 { - taskErr = errors.Errorf("transaction %s reverted on-chain", data.Receipt.GetTxHash()) + taskErr = fmt.Errorf("transaction %s reverted on-chain", data.Receipt.GetTxHash()) } else { output = data.Receipt } @@ -1144,7 +1148,7 @@ func observeUntilTxConfirmed[ // Since a tx can have many attempts, we take the number of blocks to confirm as the block number // of the receipt minus the block number of the first ever broadcast for this transaction. - broadcastBefore := utils.MinKey(attempt.Tx.TxAttempts, func(attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) int64 { + broadcastBefore := iutils.MinFunc(attempt.Tx.TxAttempts, func(attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) int64 { if attempt.BroadcastBeforeBlockNum != nil { return *attempt.BroadcastBeforeBlockNum } diff --git a/common/txmgr/mocks/tx_manager.go b/common/txmgr/mocks/tx_manager.go index 27077218f6e..45a3675aced 100644 --- a/common/txmgr/mocks/tx_manager.go +++ b/common/txmgr/mocks/tx_manager.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ type TxManager[CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], ADDR types.Hashab func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -41,6 +45,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Close( func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState) (uint32, error) { ret := _m.Called(ctx, state) + if len(ret) == 0 { + panic("no return value specified for CountTransactionsByState") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxState) (uint32, error)); ok { @@ -65,6 +73,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CountT func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH]) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, txRequest) + if len(ret) == 0 { + panic("no return value specified for CreateTransaction") + } + 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, txmgrtypes.TxRequest[ADDR, TX_HASH]) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -89,6 +101,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Create func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEarliestUnconfirmedBroadcastTime(ctx context.Context) (null.Time, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedBroadcastTime") + } + var r0 null.Time var r1 error if rf, ok := ret.Get(0).(func(context.Context) (null.Time, error)); ok { @@ -113,6 +129,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEa func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context) (null.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedTxAttemptBlock") + } + var r0 null.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (null.Int, error)); ok { @@ -137,6 +157,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindEa func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, metaValue, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesByMetaFieldAndStates") + } + 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, string, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -163,6 +187,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx 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) { ret := _m.Called(ctx, ids, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithAttemptsAndReceiptsByIdsAndState") + } + 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 { @@ -189,6 +217,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByReceiptBlockNum") + } + 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, string, int64, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -215,6 +247,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByStates") + } + 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, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -241,6 +277,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) FindTx func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetForwarderForEOA(eoa ADDR) (ADDR, error) { ret := _m.Called(eoa) + if len(ret) == 0 { + panic("no return value specified for GetForwarderForEOA") + } + var r0 ADDR var r1 error if rf, ok := ret.Get(0).(func(ADDR) (ADDR, error)); ok { @@ -265,6 +305,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetFor func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -281,6 +325,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Health func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -300,6 +348,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) OnNewL func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -319,6 +371,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Regist func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset(addr ADDR, abandon bool) error { ret := _m.Called(addr, abandon) + if len(ret) == 0 { + panic("no return value specified for Reset") + } + var r0 error if rf, ok := ret.Get(0).(func(ADDR, bool) error); ok { r0 = rf(addr, abandon) @@ -333,6 +389,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Reset( func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNativeToken(ctx context.Context, chainID CHAIN_ID, from ADDR, to ADDR, value big.Int, gasLimit uint32) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, chainID, from, to, value, gasLimit) + if len(ret) == 0 { + panic("no return value specified for SendNativeToken") + } + 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, CHAIN_ID, ADDR, ADDR, big.Int, uint32) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -357,6 +417,10 @@ func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) SendNa func (_m *TxManager[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/common/txmgr/reaper.go b/common/txmgr/reaper.go index 385a9a17c3d..3ed05b2caee 100644 --- a/common/txmgr/reaper.go +++ b/common/txmgr/reaper.go @@ -7,10 +7,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Reaper handles periodic database cleanup for Txm diff --git a/common/txmgr/resender.go b/common/txmgr/resender.go index d93f20095f1..384c0c7a2c0 100644 --- a/common/txmgr/resender.go +++ b/common/txmgr/resender.go @@ -8,12 +8,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/chains/label" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/common/client" feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -53,7 +53,7 @@ type Resender[ interval time.Duration config txmgrtypes.ResenderChainConfig txConfig txmgrtypes.ResenderTransactionsConfig - logger logger.Logger + logger logger.SugaredLogger lastAlertTimestamps map[string]time.Time ctx context.Context @@ -93,7 +93,7 @@ func NewResender[ pollInterval, config, txConfig, - logger.Named(lggr, "Resender"), + logger.Sugared(logger.Named(lggr, "Resender")), make(map[string]time.Time), ctx, cancel, diff --git a/common/txmgr/strategies.go b/common/txmgr/strategies.go index b986d0d9b80..faba2ba97bc 100644 --- a/common/txmgr/strategies.go +++ b/common/txmgr/strategies.go @@ -2,10 +2,10 @@ package txmgr import ( "context" + "fmt" "time" "github.com/google/uuid" - "github.com/pkg/errors" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" ) @@ -63,7 +63,7 @@ func (s DropOldestStrategy) PruneQueue(ctx context.Context, pruneService txmgrty n, err = pruneService.PruneUnstartedTxQueue(ctx, s.queueSize, s.subject) if err != nil { - return 0, errors.Wrap(err, "DropOldestStrategy#PruneQueue failed") + return 0, fmt.Errorf("DropOldestStrategy#PruneQueue failed: %w", err) } return } diff --git a/common/txmgr/tracker.go b/common/txmgr/tracker.go index f143f639aa8..8b66668c41e 100644 --- a/common/txmgr/tracker.go +++ b/common/txmgr/tracker.go @@ -8,11 +8,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -56,7 +56,7 @@ type Tracker[ txCache map[int64]AbandonedTx[ADDR] ttl time.Duration lock sync.Mutex - mb *utils.Mailbox[int64] + mb *mailbox.Mailbox[int64] wg sync.WaitGroup isStarted bool ctx context.Context @@ -85,7 +85,7 @@ func NewTracker[ enabledAddrs: map[ADDR]bool{}, txCache: map[int64]AbandonedTx[ADDR]{}, ttl: defaultTTL, - mb: utils.NewSingleMailbox[int64](), + mb: mailbox.NewSingle[int64](), lock: sync.Mutex{}, wg: sync.WaitGroup{}, } diff --git a/common/txmgr/txmgr.go b/common/txmgr/txmgr.go index de96ca0ff05..c6676674fbf 100644 --- a/common/txmgr/txmgr.go +++ b/common/txmgr/txmgr.go @@ -14,10 +14,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" + iutils "github.com/smartcontractkit/chainlink/v2/common/internal/utils" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/common/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // For more information about the Txm architecture, see the design doc: @@ -80,7 +82,7 @@ type Txm[ FEE feetypes.Fee, ] struct { services.StateMachine - logger logger.Logger + logger logger.SugaredLogger txStore txmgrtypes.TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE] config txmgrtypes.TransactionManagerChainConfig txConfig txmgrtypes.TransactionManagerTransactionsConfig @@ -140,7 +142,7 @@ func NewTxm[ tracker *Tracker[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE], ) *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE] { b := Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]{ - logger: lggr, + logger: logger.Sugared(lggr), txStore: txStore, config: cfg, txConfig: txCfg, @@ -242,7 +244,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Reset(addr // - marks all pending and inflight transactions fatally errored (note: at this point all transactions are either confirmed or fatally errored) // this must not be run while Broadcaster or Confirmer are running func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) abandon(addr ADDR) (err error) { - ctx, cancel := services.StopChan(b.chStop).NewCtx() + ctx, cancel := b.chStop.NewCtx() defer cancel() if err = b.txStore.Abandon(ctx, b.chainID, addr); err != nil { return fmt.Errorf("abandon failed to update txes for key %s: %w", addr.String(), err) @@ -348,12 +350,12 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() ctx, cancel := b.chStop.NewCtx() defer cancel() // Retry indefinitely on failure - backoff := utils.NewRedialBackoff() + backoff := iutils.NewRedialBackoff() for { select { case <-time.After(backoff.Duration()): if err := b.broadcaster.startInternal(ctx); err != nil { - logger.Criticalw(b.logger, "Failed to start Broadcaster", "err", err) + b.logger.Criticalw("Failed to start Broadcaster", "err", err) b.SvcErrBuffer.Append(err) continue } @@ -367,12 +369,12 @@ 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 := utils.NewRedialBackoff() + backoff := iutils.NewRedialBackoff() for { select { case <-time.After(backoff.Duration()): if err := b.confirmer.startInternal(); err != nil { - logger.Criticalw(b.logger, "Failed to start Confirmer", "err", err) + b.logger.Criticalw("Failed to start Confirmer", "err", err) b.SvcErrBuffer.Append(err) continue } @@ -440,7 +442,7 @@ func (b *Txm[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) runLoop() } enabledAddresses, err := b.keyStore.EnabledAddressesForChain(b.chainID) if err != nil { - logger.Criticalf(b.logger, "Failed to reload key states after key change") + b.logger.Critical("Failed to reload key states after key change") b.SvcErrBuffer.Append(err) continue } diff --git a/common/txmgr/types/client.go b/common/txmgr/types/client.go index b44c41e4176..0db50e97ad3 100644 --- a/common/txmgr/types/client.go +++ b/common/txmgr/types/client.go @@ -47,7 +47,7 @@ type TransactionClient[ ctx context.Context, attempts []TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], bathSize int, - lggr logger.Logger, + lggr logger.SugaredLogger, ) ( txCodes []client.SendTxReturnCode, txErrs []error, @@ -58,7 +58,7 @@ type TransactionClient[ ctx context.Context, tx Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], - lggr logger.Logger, + lggr logger.SugaredLogger, ) (client.SendTxReturnCode, error) SendEmptyTransaction( ctx context.Context, diff --git a/common/txmgr/types/mocks/forwarder_manager.go b/common/txmgr/types/mocks/forwarder_manager.go index abf176550b2..bf61d0c3d27 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type ForwarderManager[ADDR types.Hashable] struct { func (_m *ForwarderManager[ADDR]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -33,6 +37,10 @@ func (_m *ForwarderManager[ADDR]) Close() error { func (_m *ForwarderManager[ADDR]) ConvertPayload(dest ADDR, origPayload []byte) ([]byte, error) { ret := _m.Called(dest, origPayload) + if len(ret) == 0 { + panic("no return value specified for ConvertPayload") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(ADDR, []byte) ([]byte, error)); ok { @@ -59,6 +67,10 @@ func (_m *ForwarderManager[ADDR]) ConvertPayload(dest ADDR, origPayload []byte) func (_m *ForwarderManager[ADDR]) ForwarderFor(addr ADDR) (ADDR, error) { ret := _m.Called(addr) + if len(ret) == 0 { + panic("no return value specified for ForwarderFor") + } + var r0 ADDR var r1 error if rf, ok := ret.Get(0).(func(ADDR) (ADDR, error)); ok { @@ -83,6 +95,10 @@ func (_m *ForwarderManager[ADDR]) ForwarderFor(addr ADDR) (ADDR, error) { func (_m *ForwarderManager[ADDR]) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -99,6 +115,10 @@ func (_m *ForwarderManager[ADDR]) HealthReport() map[string]error { func (_m *ForwarderManager[ADDR]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -113,6 +133,10 @@ func (_m *ForwarderManager[ADDR]) Name() string { func (_m *ForwarderManager[ADDR]) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -127,6 +151,10 @@ func (_m *ForwarderManager[ADDR]) Ready() error { func (_m *ForwarderManager[ADDR]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/common/txmgr/types/mocks/key_store.go b/common/txmgr/types/mocks/key_store.go index ad5178c09d1..d440528a41d 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type KeyStore[ADDR types.Hashable, CHAIN_ID types.ID, SEQ types.Sequence] struct func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) CheckEnabled(address ADDR, chainID CHAIN_ID) error { ret := _m.Called(address, chainID) + if len(ret) == 0 { + panic("no return value specified for CheckEnabled") + } + var r0 error if rf, ok := ret.Get(0).(func(ADDR, CHAIN_ID) error); ok { r0 = rf(address, chainID) @@ -31,6 +35,10 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) CheckEnabled(address ADDR, chainID CHAI func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(chainId CHAIN_ID) ([]ADDR, error) { ret := _m.Called(chainId) + if len(ret) == 0 { + panic("no return value specified for EnabledAddressesForChain") + } + var r0 []ADDR var r1 error if rf, ok := ret.Get(0).(func(CHAIN_ID) ([]ADDR, error)); ok { @@ -57,6 +65,10 @@ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) EnabledAddressesForChain(chainId CHAIN_ func (_m *KeyStore[ADDR, CHAIN_ID, SEQ]) SubscribeToKeyChanges() (chan struct{}, func()) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribeToKeyChanges") + } + var r0 chan struct{} var r1 func() if rf, ok := ret.Get(0).(func() (chan struct{}, func())); ok { diff --git a/common/txmgr/types/mocks/reaper_chain_config.go b/common/txmgr/types/mocks/reaper_chain_config.go index a733b223701..041214b80c6 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -13,6 +13,10 @@ type ReaperConfig struct { func (_m *ReaperConfig) FinalityDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() diff --git a/common/txmgr/types/mocks/tx_attempt_builder.go b/common/txmgr/types/mocks/tx_attempt_builder.go index 0f3d3e3fba1..b3b6ff761fb 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ type TxAttemptBuilder[CHAIN_ID types.ID, HEAD types.Head[BLOCK_HASH], ADDR types func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -38,6 +42,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -54,6 +62,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -68,6 +80,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) NewBumpTxAttempt(ctx context.Context, tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], previousAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], priorAttempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], lggr logger.Logger) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], FEE, uint32, bool, error) { ret := _m.Called(ctx, tx, previousAttempt, priorAttempts, lggr) + if len(ret) == 0 { + panic("no return value specified for NewBumpTxAttempt") + } + var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 FEE var r2 uint32 @@ -113,6 +129,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) NewCustomTxAttempt(tx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fee FEE, gasLimit uint32, txType int, lggr logger.Logger) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], bool, error) { ret := _m.Called(tx, fee, gasLimit, txType, lggr) + if len(ret) == 0 { + panic("no return value specified for NewCustomTxAttempt") + } + var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 bool var r2 error @@ -144,6 +164,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) NewEmptyTxAttempt(seq SEQ, feeLimit uint32, fee FEE, fromAddress ADDR) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(seq, feeLimit, fee, fromAddress) + if len(ret) == 0 { + panic("no return value specified for NewEmptyTxAttempt") + } + var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 error if rf, ok := ret.Get(0).(func(SEQ, uint32, FEE, ADDR) (txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -175,6 +199,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for NewTxAttempt") + } + var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 FEE var r2 uint32 @@ -227,6 +255,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for NewTxAttemptWithType") + } + var r0 txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE] var r1 FEE var r2 uint32 @@ -277,6 +309,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -291,6 +327,10 @@ func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) func (_m *TxAttemptBuilder[CHAIN_ID, HEAD, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/common/txmgr/types/mocks/tx_store.go b/common/txmgr/types/mocks/tx_store.go index df1528a4c24..16c20df31d7 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -29,6 +29,10 @@ type TxStore[ADDR types.Hashable, CHAIN_ID types.ID, TX_HASH types.Hashable, BLO func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Abandon(ctx context.Context, id CHAIN_ID, addr ADDR) error { ret := _m.Called(ctx, id, addr) + if len(ret) == 0 { + panic("no return value specified for Abandon") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID, ADDR) error); ok { r0 = rf(ctx, id, addr) @@ -43,6 +47,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Abandon(ctx func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CheckTxQueueCapacity(ctx context.Context, fromAddress ADDR, maxQueuedTransactions uint64, chainID CHAIN_ID) error { ret := _m.Called(ctx, fromAddress, maxQueuedTransactions, chainID) + if len(ret) == 0 { + panic("no return value specified for CheckTxQueueCapacity") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, uint64, CHAIN_ID) error); ok { r0 = rf(ctx, fromAddress, maxQueuedTransactions, chainID) @@ -62,6 +70,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) Close() { func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState, chainID CHAIN_ID) (uint32, error) { ret := _m.Called(ctx, state, chainID) + if len(ret) == 0 { + panic("no return value specified for CountTransactionsByState") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxState, CHAIN_ID) (uint32, error)); ok { @@ -86,6 +98,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountTransa func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnconfirmedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (uint32, error) { ret := _m.Called(ctx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for CountUnconfirmedTransactions") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (uint32, error)); ok { @@ -110,6 +126,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnconf func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnstartedTransactions(ctx context.Context, fromAddress ADDR, chainID CHAIN_ID) (uint32, error) { ret := _m.Called(ctx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for CountUnstartedTransactions") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (uint32, error)); ok { @@ -134,6 +154,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CountUnstar func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTransaction(ctx context.Context, txRequest txmgrtypes.TxRequest[ADDR, TX_HASH], chainID CHAIN_ID) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, txRequest, chainID) + if len(ret) == 0 { + panic("no return value specified for CreateTransaction") + } + 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, txmgrtypes.TxRequest[ADDR, TX_HASH], CHAIN_ID) (txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -158,6 +182,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) CreateTrans func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) DeleteInProgressAttempt(ctx context.Context, attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, attempt) + if len(ret) == 0 { + panic("no return value specified for DeleteInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, attempt) @@ -172,6 +200,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) DeleteInPro func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, chainID CHAIN_ID) (null.Time, error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedBroadcastTime") + } + var r0 null.Time var r1 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) (null.Time, error)); ok { @@ -196,6 +228,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarlies func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, chainID CHAIN_ID) (null.Int, error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedTxAttemptBlock") + } + var r0 null.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) (null.Int, error)); ok { @@ -220,6 +256,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindEarlies func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindLatestSequence(ctx context.Context, fromAddress ADDR, chainId CHAIN_ID) (SEQ, error) { ret := _m.Called(ctx, fromAddress, chainId) + if len(ret) == 0 { + panic("no return value specified for FindLatestSequence") + } + var r0 SEQ var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (SEQ, error)); ok { @@ -244,6 +284,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindLatestS func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], fromAddress ADDR, chainID CHAIN_ID) error { ret := _m.Called(ctx, etx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for FindNextUnstartedTransactionFromAddress") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], ADDR, CHAIN_ID) error); ok { r0 = rf(ctx, etx, fromAddress, chainID) @@ -258,6 +302,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindNextUns func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber int64, lowBlockNumber int64, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, highBlockNumber, lowBlockNumber, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTransactionsConfirmedInBlockRange") + } + 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, int64, int64, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -284,6 +332,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTransac func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsConfirmedMissingReceipt") + } + 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.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -310,6 +362,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttem func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsRequiringReceiptFetch(ctx context.Context, chainID CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsRequiringReceiptFetch") + } + 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.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -336,6 +392,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttem func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttemptsRequiringResend(ctx context.Context, olderThan time.Time, maxInFlightTransactions uint32, chainID CHAIN_ID, address ADDR) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, olderThan, maxInFlightTransactions, chainID, address) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsRequiringResend") + } + 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, time.Time, uint32, CHAIN_ID, ADDR) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -362,6 +422,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxAttem func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithIdempotencyKey(ctx context.Context, idempotencyKey string, chainID CHAIN_ID) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, idempotencyKey, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxWithIdempotencyKey") + } + 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, string, CHAIN_ID) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -388,6 +452,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithI func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithSequence(ctx context.Context, fromAddress ADDR, seq SEQ) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, fromAddress, seq) + if len(ret) == 0 { + panic("no return value specified for FindTxWithSequence") + } + 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, SEQ) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -414,6 +482,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxWithS func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, metaValue, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesByMetaFieldAndStates") + } + 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, string, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -440,6 +512,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesByM func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesPendingCallback(ctx context.Context, blockNum int64, chainID CHAIN_ID) ([]txmgrtypes.ReceiptPlus[R], error) { ret := _m.Called(ctx, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesPendingCallback") + } + var r0 []txmgrtypes.ReceiptPlus[R] var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, CHAIN_ID) ([]txmgrtypes.ReceiptPlus[R], error)); ok { @@ -466,6 +542,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesPen 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) { ret := _m.Called(ctx, ids, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithAttemptsAndReceiptsByIdsAndState") + } + 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 { @@ -492,6 +572,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWit func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByReceiptBlockNum") + } + 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, string, int64, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -518,6 +602,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWit func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, states []txmgrtypes.TxState, chainID *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, metaField, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByStates") + } + 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, string, []txmgrtypes.TxState, *big.Int) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -544,6 +632,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxesWit func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequiringGasBump(ctx context.Context, address ADDR, blockNum int64, gasBumpThreshold int64, depth int64, chainID CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, address, blockNum, gasBumpThreshold, depth, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxsRequiringGasBump") + } + 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, int64, int64, int64, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -570,6 +662,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx context.Context, address ADDR, chainID CHAIN_ID) ([]*txmgrtypes.Tx[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 FindTxsRequiringResubmissionDueToInsufficientFunds") + } + 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.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -596,6 +692,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) FindTxsRequ 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 GetInProgressTxAttempts") + } + 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, ADDR, CHAIN_ID) ([]txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -622,6 +722,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetInProgre 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) + if len(ret) == 0 { + panic("no return value specified for GetNonFatalTransactions") + } + 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, CHAIN_ID) ([]*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -648,6 +752,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetNonFatal func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxByID(ctx context.Context, id int64) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for GetTxByID") + } + 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, int64) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -674,6 +782,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxByID(c func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxInProgress(ctx context.Context, fromAddress ADDR) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error) { ret := _m.Called(ctx, fromAddress) + if len(ret) == 0 { + panic("no return value specified for GetTxInProgress") + } + 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) (*txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], error)); ok { @@ -700,6 +812,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) GetTxInProg func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HasInProgressTransaction(ctx context.Context, account ADDR, chainID CHAIN_ID) (bool, error) { ret := _m.Called(ctx, account, chainID) + if len(ret) == 0 { + panic("no return value specified for HasInProgressTransaction") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) (bool, error)); ok { @@ -724,6 +840,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) HasInProgre func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID CHAIN_ID) (bool, error) { ret := _m.Called(ctx, blockHeight, txID, chainID) + if len(ret) == 0 { + panic("no return value specified for IsTxFinalized") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, int64, CHAIN_ID) (bool, error)); ok { @@ -748,6 +868,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) IsTxFinaliz func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) LoadTxAttempts(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, etx) + if len(ret) == 0 { + panic("no return value specified for LoadTxAttempts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, etx) @@ -762,6 +886,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) LoadTxAttem func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkAllConfirmedMissingReceipt(ctx context.Context, chainID CHAIN_ID) error { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for MarkAllConfirmedMissingReceipt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) error); ok { r0 = rf(ctx, chainID) @@ -776,6 +904,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkAllConf func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID CHAIN_ID) error { ret := _m.Called(ctx, blockNum, finalityDepth, chainID) + if len(ret) == 0 { + panic("no return value specified for MarkOldTxesMissingReceiptAsErrored") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, uint32, CHAIN_ID) error); ok { r0 = rf(ctx, blockNum, finalityDepth, chainID) @@ -790,6 +922,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) MarkOldTxes func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PreloadTxes(ctx context.Context, attempts []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, attempts) + if len(ret) == 0 { + panic("no return value specified for PreloadTxes") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, attempts) @@ -804,6 +940,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PreloadTxes func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PruneUnstartedTxQueue(ctx context.Context, queueSize uint32, subject uuid.UUID) (int64, error) { ret := _m.Called(ctx, queueSize, subject) + if len(ret) == 0 { + panic("no return value specified for PruneUnstartedTxQueue") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint32, uuid.UUID) (int64, error)); ok { @@ -828,6 +968,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) PruneUnstar func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID CHAIN_ID) error { ret := _m.Called(ctx, minBlockNumberToKeep, timeThreshold, chainID) + if len(ret) == 0 { + panic("no return value specified for ReapTxHistory") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, time.Time, CHAIN_ID) error); ok { r0 = rf(ctx, minBlockNumberToKeep, timeThreshold, chainID) @@ -842,6 +986,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) ReapTxHisto func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveConfirmedMissingReceiptAttempt(ctx context.Context, timeout time.Duration, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveConfirmedMissingReceiptAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -856,6 +1004,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveConfirm func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveFetchedReceipts(ctx context.Context, receipts []R, chainID CHAIN_ID) error { ret := _m.Called(ctx, receipts, chainID) + if len(ret) == 0 { + panic("no return value specified for SaveFetchedReceipts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []R, CHAIN_ID) error); ok { r0 = rf(ctx, receipts, chainID) @@ -870,6 +1022,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveFetched func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInProgressAttempt(ctx context.Context, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, attempt) + if len(ret) == 0 { + panic("no return value specified for SaveInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, attempt) @@ -884,6 +1040,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInProgr func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInsufficientFundsAttempt(ctx context.Context, timeout time.Duration, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveInsufficientFundsAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -898,6 +1058,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveInsuffi func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveReplacementInProgressAttempt(ctx context.Context, oldAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], replacementAttempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, oldAttempt, replacementAttempt) + if len(ret) == 0 { + panic("no return value specified for SaveReplacementInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, oldAttempt, replacementAttempt) @@ -912,6 +1076,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveReplace func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveSentAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -926,6 +1094,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SaveSentAtt func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum int64, chainID CHAIN_ID) error { ret := _m.Called(ctx, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for SetBroadcastBeforeBlockNum") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, CHAIN_ID) error); ok { r0 = rf(ctx, blockNum, chainID) @@ -940,6 +1112,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) SetBroadcas func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateBroadcastAts(ctx context.Context, now time.Time, etxIDs []int64) error { ret := _m.Called(ctx, now, etxIDs) + if len(ret) == 0 { + panic("no return value specified for UpdateBroadcastAts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Time, []int64) error); ok { r0 = rf(ctx, now, etxIDs) @@ -954,6 +1130,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateBroad func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], NewAttemptState txmgrtypes.TxAttemptState) error { ret := _m.Called(ctx, etx, attempt, NewAttemptState) + if len(ret) == 0 { + panic("no return value specified for UpdateTxAttemptInProgressToBroadcast") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttemptState) error); ok { r0 = rf(ctx, etx, attempt, NewAttemptState) @@ -968,6 +1148,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxAtt func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxCallbackCompleted(ctx context.Context, pipelineTaskRunRid uuid.UUID, chainId CHAIN_ID) error { ret := _m.Called(ctx, pipelineTaskRunRid, chainId) + if len(ret) == 0 { + panic("no return value specified for UpdateTxCallbackCompleted") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, CHAIN_ID) error); ok { r0 = rf(ctx, pipelineTaskRunRid, chainId) @@ -982,6 +1166,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxCal func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFatalError(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, etx) + if len(ret) == 0 { + panic("no return value specified for UpdateTxFatalError") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, etx) @@ -996,6 +1184,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFat func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxForRebroadcast(ctx context.Context, etx txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], etxAttempt txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, etx, etxAttempt) + if len(ret) == 0 { + panic("no return value specified for UpdateTxForRebroadcast") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, etx, etxAttempt) @@ -1010,6 +1202,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxFor func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxUnstartedToInProgress(ctx context.Context, etx *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], attempt *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error { ret := _m.Called(ctx, etx, attempt) + if len(ret) == 0 { + panic("no return value specified for UpdateTxUnstartedToInProgress") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *txmgrtypes.Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE], *txmgrtypes.TxAttempt[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) error); ok { r0 = rf(ctx, etx, attempt) @@ -1024,6 +1220,10 @@ func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxUns func (_m *TxStore[ADDR, CHAIN_ID, TX_HASH, BLOCK_HASH, R, SEQ, FEE]) UpdateTxsUnconfirmed(ctx context.Context, ids []int64) error { ret := _m.Called(ctx, ids) + if len(ret) == 0 { + panic("no return value specified for UpdateTxsUnconfirmed") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []int64) error); ok { r0 = rf(ctx, ids) diff --git a/common/txmgr/types/mocks/tx_strategy.go b/common/txmgr/types/mocks/tx_strategy.go index f4ec9bef49a..7992c3fe05f 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type TxStrategy struct { func (_m *TxStrategy) PruneQueue(ctx context.Context, pruneService types.UnstartedTxQueuePruner) (int64, error) { ret := _m.Called(ctx, pruneService) + if len(ret) == 0 { + panic("no return value specified for PruneQueue") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, types.UnstartedTxQueuePruner) (int64, error)); ok { @@ -44,6 +48,10 @@ func (_m *TxStrategy) PruneQueue(ctx context.Context, pruneService types.Unstart func (_m *TxStrategy) Subject() uuid.NullUUID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Subject") + } + var r0 uuid.NullUUID if rf, ok := ret.Get(0).(func() uuid.NullUUID); ok { r0 = rf() diff --git a/common/txmgr/types/tx.go b/common/txmgr/types/tx.go index b8a16561d88..0f5d651ae29 100644 --- a/common/txmgr/types/tx.go +++ b/common/txmgr/types/tx.go @@ -3,6 +3,7 @@ package types import ( "context" "encoding/json" + "errors" "fmt" "math/big" "slices" @@ -10,14 +11,14 @@ import ( "time" "github.com/google/uuid" - "github.com/pkg/errors" "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + clnull "github.com/smartcontractkit/chainlink-common/pkg/utils/null" + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" "github.com/smartcontractkit/chainlink/v2/common/types" - clnull "github.com/smartcontractkit/chainlink/v2/core/null" ) // TxStrategy controls how txes are queued and sent @@ -245,11 +246,15 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetMeta() (*TxMeta[A return nil, nil } var m TxMeta[ADDR, TX_HASH] - return &m, errors.Wrap(json.Unmarshal(*e.Meta, &m), "unmarshalling meta") + if err := json.Unmarshal(*e.Meta, &m); err != nil { + return nil, fmt.Errorf("unmarshalling meta: %w", err) + } + + return &m, nil } // GetLogger returns a new logger with metadata fields. -func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger.Logger) logger.Logger { +func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger.Logger) logger.SugaredLogger { lgr = logger.With(lgr, "txID", e.ID, "sequence", e.Sequence, @@ -260,7 +265,7 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger meta, err := e.GetMeta() if err != nil { lgr.Errorw("failed to get meta of the transaction", "err", err) - return lgr + return logger.Sugared(lgr) } if meta != nil { @@ -310,7 +315,7 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetLogger(lgr logger } } - return lgr + return logger.Sugared(lgr) } // GetChecker returns an Tx's transmit checker spec in struct form, unmarshalling it from JSON @@ -320,5 +325,9 @@ func (e *Tx[CHAIN_ID, ADDR, TX_HASH, BLOCK_HASH, SEQ, FEE]) GetChecker() (Transm return TransmitCheckerSpec[ADDR]{}, nil } var t TransmitCheckerSpec[ADDR] - return t, errors.Wrap(json.Unmarshal(*e.TransmitChecker, &t), "unmarshalling transmit checker") + if err := json.Unmarshal(*e.TransmitChecker, &t); err != nil { + return t, fmt.Errorf("unmarshalling transmit checker: %w", err) + } + + return t, nil } diff --git a/common/types/mocks/head.go b/common/types/mocks/head.go index 99d2a265b44..29b6d073656 100644 --- a/common/types/mocks/head.go +++ b/common/types/mocks/head.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type Head[BLOCK_HASH types.Hashable] struct { func (_m *Head[BLOCK_HASH]) BlockDifficulty() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockDifficulty") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -36,6 +40,10 @@ func (_m *Head[BLOCK_HASH]) BlockDifficulty() *big.Int { func (_m *Head[BLOCK_HASH]) BlockHash() BLOCK_HASH { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockHash") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func() BLOCK_HASH); ok { r0 = rf() @@ -50,6 +58,10 @@ func (_m *Head[BLOCK_HASH]) BlockHash() BLOCK_HASH { func (_m *Head[BLOCK_HASH]) BlockNumber() int64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + var r0 int64 if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() @@ -64,6 +76,10 @@ func (_m *Head[BLOCK_HASH]) BlockNumber() int64 { func (_m *Head[BLOCK_HASH]) ChainLength() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainLength") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -78,6 +94,10 @@ func (_m *Head[BLOCK_HASH]) ChainLength() uint32 { func (_m *Head[BLOCK_HASH]) EarliestHeadInChain() types.Head[BLOCK_HASH] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EarliestHeadInChain") + } + var r0 types.Head[BLOCK_HASH] if rf, ok := ret.Get(0).(func() types.Head[BLOCK_HASH]); ok { r0 = rf() @@ -94,6 +114,10 @@ func (_m *Head[BLOCK_HASH]) EarliestHeadInChain() types.Head[BLOCK_HASH] { func (_m *Head[BLOCK_HASH]) GetParent() types.Head[BLOCK_HASH] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetParent") + } + var r0 types.Head[BLOCK_HASH] if rf, ok := ret.Get(0).(func() types.Head[BLOCK_HASH]); ok { r0 = rf() @@ -110,6 +134,10 @@ func (_m *Head[BLOCK_HASH]) GetParent() types.Head[BLOCK_HASH] { func (_m *Head[BLOCK_HASH]) GetParentHash() BLOCK_HASH { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetParentHash") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func() BLOCK_HASH); ok { r0 = rf() @@ -124,6 +152,10 @@ func (_m *Head[BLOCK_HASH]) GetParentHash() BLOCK_HASH { func (_m *Head[BLOCK_HASH]) GetTimestamp() time.Time { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetTimestamp") + } + var r0 time.Time if rf, ok := ret.Get(0).(func() time.Time); ok { r0 = rf() @@ -138,6 +170,10 @@ func (_m *Head[BLOCK_HASH]) GetTimestamp() time.Time { func (_m *Head[BLOCK_HASH]) HashAtHeight(blockNum int64) BLOCK_HASH { ret := _m.Called(blockNum) + if len(ret) == 0 { + panic("no return value specified for HashAtHeight") + } + var r0 BLOCK_HASH if rf, ok := ret.Get(0).(func(int64) BLOCK_HASH); ok { r0 = rf(blockNum) diff --git a/common/types/mocks/head_trackable.go b/common/types/mocks/head_trackable.go index e63e9ca2497..55f0ebd288e 100644 --- a/common/types/mocks/head_trackable.go +++ b/common/types/mocks/head_trackable.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/common/types/mocks/subscription.go b/common/types/mocks/subscription.go index 5577ee4a62a..32db6dfa769 100644 --- a/common/types/mocks/subscription.go +++ b/common/types/mocks/subscription.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -13,6 +13,10 @@ type Subscription struct { func (_m *Subscription) Err() <-chan error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Err") + } + var r0 <-chan error if rf, ok := ret.Get(0).(func() <-chan error); ok { r0 = rf() diff --git a/contracts/.solhint.json b/contracts/.solhint.json index e66b915d679..ea220d0a030 100644 --- a/contracts/.solhint.json +++ b/contracts/.solhint.json @@ -9,6 +9,7 @@ "func-named-parameters": "off", "immutable-vars-naming": "off", "no-inline-assembly": "off", + "contract-name-camelcase": "off", "no-unused-import": "error", "func-visibility": [ "error", diff --git a/contracts/.solhintignore b/contracts/.solhintignore index ba2aac1fb3a..4246bbd77ca 100644 --- a/contracts/.solhintignore +++ b/contracts/.solhintignore @@ -1,6 +1,29 @@ # 344 warnings #./src/v0.8/automation +# Ignore frozen Automation code +./src/v0.8/automation/v1_2 +./src/v0.8/automation/v1_3 +./src/v0.8/automation/v2_0 +./src/v0.8/automation/v2_1 +./src/v0.8/automation/interfaces/v2_1/ +./src/v0.8/automation/interfaces/MigratableKeeperRegistryInterface.sol +./src/v0.8/automation/upkeeps/UpkeepBalanceMonitor.sol +./src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol +./src/v0.8/automation/upkeeps/EthBalanceMonitor.sol +./src/v0.8/automation/upkeeps/ERC20BalanceMonitor.sol +./src/v0.8/automation/upkeeps/CronUpkeepFactory.sol +./src/v0.8/automation/upkeeps/CronUpkeepDelegate.sol +./src/v0.8/automation/upkeeps/CronUpkeep.sol +./src/v0.8/automation/libraries/internal/Cron.sol +./src/v0.8/automation/AutomationForwarder.sol +./src/v0.8/automation/AutomationForwarderLogic.sol + + +# Ignore tests / test helpers (for now) +./src/v0.8/automation/mocks +./src/v0.8/automation/testhelpers + # Ignore Functions v1.0.0 code that was frozen after audit ./src/v0.8/functions/v1_0_0 @@ -14,4 +37,4 @@ # Always ignore vendor ./src/v0.8/vendor -./node_modules/ \ No newline at end of file +./node_modules/ diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index f5be193249c..f666014c48f 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -1,6 +1,6 @@ # ALL_FOUNDRY_PRODUCTS contains a list of all products that have a foundry # profile defined and use the Foundry snapshots. -ALL_FOUNDRY_PRODUCTS = llo-feeds functions shared +ALL_FOUNDRY_PRODUCTS = l2ep llo-feeds functions shared # To make a snapshot for a specific product, either set the `FOUNDRY_PROFILE` env var # or call the target with `FOUNDRY_PROFILE=product` @@ -43,7 +43,7 @@ mockery: $(mockery) ## Install mockery. .PHONY: foundry foundry: ## Install foundry. - foundryup --version nightly-09fe3e041369a816365a020f715ad6f94dbce9f2 + foundryup --version nightly-5b7e4cb3c882b28f3c32ba580de27ce7381f415a .PHONY: foundry-refresh foundry-refresh: foundry diff --git a/contracts/foundry.toml b/contracts/foundry.toml index cf27c0f2a8b..003c836b1f3 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -37,7 +37,7 @@ test = 'src/v0.8/automation/test' optimizer_runs = 1000000 src = 'src/v0.8/l2ep' test = 'src/v0.8/l2ep/test' - +solc_version = '0.8.19' [profile.llo-feeds] optimizer_runs = 1000000 diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index 4e6cf83cd1a..39efc0d10ea 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,12 +1,12 @@ -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14578318) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14578296) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14578312) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14589732) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14589709) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14589681) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14589632) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14589621) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14589665) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14805978) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14805956) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14805972) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14817392) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14817369) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14817341) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14817292) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14817281) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14817325) FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14812) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13282) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15897) @@ -28,7 +28,7 @@ FunctionsBilling_UpdateConfig:test_UpdateConfig_Success() (gas: 38251) FunctionsBilling__DisperseFeePool:test__DisperseFeePool_RevertIfNotSet() (gas: 8810) FunctionsBilling__FulfillAndBill:test__FulfillAndBill_RevertIfInvalidCommitment() (gas: 13302) FunctionsBilling__FulfillAndBill:test__FulfillAndBill_Success() (gas: 180763) -FunctionsBilling__StartBilling:test__FulfillAndBill_HasUniqueGlobalRequestId() (gas: 398312) +FunctionsBilling__StartBilling:test__FulfillAndBill_HasUniqueGlobalRequestId() (gas: 398400) FunctionsClient_Constructor:test_Constructor_Success() (gas: 7573) FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 497786) FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 198990) @@ -61,7 +61,7 @@ FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 280 FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 151496) FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 321059) FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 334680) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2509962) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2510006) FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 540441) FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 17983) FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12904) @@ -82,17 +82,17 @@ FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfLengt FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotNewContract() (gas: 19048) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotOwner() (gas: 23392) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_Success() (gas: 118479) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59347) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59391) FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 193436) FunctionsRouter_SendRequest:test_SendRequest_RevertIfEmptyData() (gas: 29426) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57925) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 186932) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57904) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 187020) FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 50947) FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidDonId() (gas: 25082) FunctionsRouter_SendRequest:test_SendRequest_RevertIfNoSubscription() (gas: 29132) FunctionsRouter_SendRequest:test_SendRequest_RevertIfPaused() (gas: 34291) FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 286243) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65843) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65887) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfEmptyData() (gas: 36012) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfIncorrectDonId() (gas: 29896) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidCallbackGasLimit() (gas: 57533) @@ -100,7 +100,7 @@ FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalid FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfNoSubscription() (gas: 35717) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfPaused() (gas: 40810) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 292812) -FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 193424) +FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 193512) FunctionsRouter_SetAllowListId:test_SetAllowListId_Success() (gas: 30688) FunctionsRouter_SetAllowListId:test_UpdateConfig_RevertIfNotOwner() (gas: 13403) FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13293) @@ -109,30 +109,30 @@ FunctionsRouter_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 24437) FunctionsRouter_UpdateConfig:test_UpdateConfig_Success() (gas: 60676) FunctionsRouter_UpdateContracts:test_UpdateContracts_RevertIfNotOwner() (gas: 13336) FunctionsRouter_UpdateContracts:test_UpdateContracts_Success() (gas: 38732) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60326) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 60987) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 94677) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62693) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 215197) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 137893) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164837) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 60414) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 61031) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 139404) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62781) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 215285) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 138025) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164969) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12946) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 57809) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87162) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotAllowedSender() (gas: 102448) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNotSubscriptionOwner() (gas: 87199) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfPaused() (gas: 18094) -FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95480) +FunctionsSubscriptions_AddConsumer:test_AddConsumer_Success() (gas: 95524) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubscription() (gas: 15041) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 57885) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89272) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 102524) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89309) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20148) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 194325) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114506) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125832) -FunctionsSubscriptions_CancelSubscription_ReceiveDeposit:test_CancelSubscription_SuccessRecieveDeposit() (gas: 74973) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 194369) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114541) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125867) +FunctionsSubscriptions_CancelSubscription_ReceiveDeposit:test_CancelSubscription_SuccessRecieveDeposit() (gas: 75017) FunctionsSubscriptions_Constructor:test_Constructor_Success() (gas: 7654) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28660) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfNotAllowedSender() (gas: 28704) FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_RevertIfPaused() (gas: 17994) -FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 351726) +FunctionsSubscriptions_CreateSubscriptionWithConsumer:test_CreateSubscriptionWithConsumer_Success() (gas: 351858) FunctionsSubscriptions_GetConsumer:test_GetConsumer_Success() (gas: 16226) FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessInvalidSubscription() (gas: 13101) FunctionsSubscriptions_GetFlags:test_GetFlags_SuccessValidSubscription() (gas: 40903) @@ -142,11 +142,11 @@ FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Reve FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 13459) FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Success() (gas: 59592) FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 15010) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 43508, ~: 45548) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46020, ~: 48060) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14295, ~: 14295) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51089, ~: 53040) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 86057, ~: 89604) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata() (gas: 39939) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription() (gas: 42404) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink() (gas: 13441) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused() (gas: 47347) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 81598, ~: 81598) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) @@ -168,23 +168,23 @@ FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() ( FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessSetsBalanceToZero() (gas: 37790) FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 14981) FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 176494) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27611) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57709) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27655) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57797) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15001) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 75131) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotAllowedSender() (gas: 119770) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNotSubscriptionOwner() (gas: 17960) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfPaused() (gas: 20128) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68196) -FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() (gas: 82749) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_Success() (gas: 68240) +FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_SuccessChangeProposedOwner() (gas: 82837) FunctionsSubscriptions_RecoverFunds:test_OwnerCancelSubscription_RevertIfNotOwner() (gas: 15554) -FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success(uint64) (runs: 256, μ: 41717, ~: 41721) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30260) +FunctionsSubscriptions_RecoverFunds:test_RecoverFunds_Success() (gas: 41111) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfInvalidConsumer() (gas: 30304) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription() (gas: 15019) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 57800) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87208) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 102439) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87245) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPaused() (gas: 18049) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 191858) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 41979) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 191902) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 42023) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNoSubscription() (gas: 12891) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNotOwner() (gas: 15684) FunctionsSubscriptions_SetFlags:test_SetFlags_Success() (gas: 35594) @@ -192,34 +192,44 @@ FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfPaused() (ga FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertIfTimeoutNotExceeded() (gas: 25261) FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_RevertInvalidRequest() (gas: 28242) FunctionsSubscriptions_TimeoutRequests:test_TimeoutRequests_Success() (gas: 57754) -FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26390) +FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfNotAllowedSender() (gas: 26434) FunctionsSubscriptions_createSubscription:test_CreateSubscription_RevertIfPaused() (gas: 15759) -FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152576) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:testAcceptTermsOfService_InvalidSigner_vuln() (gas: 94815) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() (gas: 25837) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfBlockedSender() (gas: 44348) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfInvalidSigner() (gas: 23597) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1866530) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26003) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946547) -FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 104851) -FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15469) -FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 51794) -FunctionsTermsOfServiceAllowList_Constructor:test_Constructor_Success() (gas: 12187) -FunctionsTermsOfServiceAllowList_GetAllAllowedSenders:test_GetAllAllowedSenders_Success() (gas: 19243) -FunctionsTermsOfServiceAllowList_GetConfig:test_GetConfig_Success() (gas: 15773) -FunctionsTermsOfServiceAllowList_GetMessage:test_GetMessage_Success() (gas: 11583) -FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_FalseWhenEnabled() (gas: 15925) -FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_TrueWhenDisabled() (gas: 23430) -FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessFalse() (gas: 15354) -FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessTrue() (gas: 41957) -FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_RevertIfNotOwner() (gas: 13525) -FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_Success() (gas: 95184) -FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13727) +FunctionsSubscriptions_createSubscription:test_CreateSubscription_Success() (gas: 152708) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:testAcceptTermsOfService_InvalidSigner_vuln() (gas: 94864) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfAcceptorIsNotSender() (gas: 25859) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfBlockedSender() (gas: 88990) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfInvalidSigner() (gas: 23619) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientContractIsNotSender() (gas: 1866552) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_RevertIfRecipientIsNotSender() (gas: 26025) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForContract() (gas: 1946628) +FunctionsTermsOfServiceAllowList_AcceptTermsOfService:test_AcceptTermsOfService_SuccessIfAcceptingForSelf() (gas: 103533) +FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_RevertIfNotOwner() (gas: 15491) +FunctionsTermsOfServiceAllowList_BlockSender:test_BlockSender_Success() (gas: 96662) +FunctionsTermsOfServiceAllowList_Constructor:test_Constructor_Success() (gas: 12253) +FunctionsTermsOfServiceAllowList_GetAllAllowedSenders:test_GetAllAllowedSenders_Success() (gas: 19199) +FunctionsTermsOfServiceAllowList_GetAllowedSendersCount:test_GetAllowedSendersCount_Success() (gas: 12995) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfAllowedSendersIsEmpty() (gas: 12184656) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfEndIsAfterLastAllowedSender() (gas: 16571) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_RevertIfStartIsAfterEnd() (gas: 13301) +FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange:test_GetAllowedSendersInRange_Success() (gas: 20448) +FunctionsTermsOfServiceAllowList_GetBlockedSendersCount:test_GetBlockedSendersCount_Success() (gas: 12931) +FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_RevertIfAllowedSendersIsEmpty() (gas: 12184660) +FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_RevertIfEndIsAfterLastAllowedSender() (gas: 16549) +FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_RevertIfStartIsAfterEnd() (gas: 13367) +FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange:test_GetBlockedSendersInRange_Success() (gas: 18493) +FunctionsTermsOfServiceAllowList_GetConfig:test_GetConfig_Success() (gas: 15751) +FunctionsTermsOfServiceAllowList_GetMessage:test_GetMessage_Success() (gas: 11593) +FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_FalseWhenEnabled() (gas: 15969) +FunctionsTermsOfServiceAllowList_HasAccess:test_HasAccess_TrueWhenDisabled() (gas: 23496) +FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessFalse() (gas: 15445) +FunctionsTermsOfServiceAllowList_IsBlockedSender:test_IsBlockedSender_SuccessTrue() (gas: 86643) +FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_RevertIfNotOwner() (gas: 13502) +FunctionsTermsOfServiceAllowList_UnblockSender:test_UnblockSender_Success() (gas: 96216) +FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 13749) FunctionsTermsOfServiceAllowList_UpdateConfig:test_UpdateConfig_Success() (gas: 22073) -Gas_AcceptTermsOfService:test_AcceptTermsOfService_Gas() (gas: 84675) -Gas_AddConsumer:test_AddConsumer_Gas() (gas: 79087) -Gas_CreateSubscription:test_CreateSubscription_Gas() (gas: 73375) +Gas_AcceptTermsOfService:test_AcceptTermsOfService_Gas() (gas: 84702) +Gas_AddConsumer:test_AddConsumer_Gas() (gas: 79131) +Gas_CreateSubscription:test_CreateSubscription_Gas() (gas: 73419) Gas_FundSubscription:test_FundSubscription_Gas() (gas: 38546) Gas_SendRequest:test_SendRequest_MaximumGas() (gas: 979631) Gas_SendRequest:test_SendRequest_MinimumGas() (gas: 157578) \ No newline at end of file diff --git a/contracts/gas-snapshots/l2ep.gas-snapshot b/contracts/gas-snapshots/l2ep.gas-snapshot new file mode 100644 index 00000000000..1f229f7d1d9 --- /dev/null +++ b/contracts/gas-snapshots/l2ep.gas-snapshot @@ -0,0 +1,146 @@ +ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37312) +ArbitrumCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 12963) +ArbitrumCrossDomainForwarder_Constructor:test_InitialState() (gas: 18431) +ArbitrumCrossDomainForwarder_Forward:test_Forward() (gas: 47601) +ArbitrumCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 22151) +ArbitrumCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 16048) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 41408) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19312) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18323) +ArbitrumCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13200) +ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 37312) +ArbitrumCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 12963) +ArbitrumCrossDomainGovernor_Constructor:test_InitialState() (gas: 18454) +ArbitrumCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 49720) +ArbitrumCrossDomainGovernor_Forward:test_Forward() (gas: 47658) +ArbitrumCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 24348) +ArbitrumCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 18247) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 19386) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 60617) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 62723) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 18237) +ArbitrumCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 64110) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 41408) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 19312) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 18323) +ArbitrumCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 13200) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 92118) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 92673) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 92039) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 89813) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 89705) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 90246) +ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 89690) +ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 98825) +ArbitrumSequencerUptimeFeed_AggregatorV3Interface:test_Return0WhenRoundDoesNotExistYet() (gas: 18309) +ArbitrumSequencerUptimeFeed_Constants:test_InitialState() (gas: 5684) +ArbitrumSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 97495) +ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 602711) +ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 573802) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 98976) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 15416) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 113269) +ArbitrumSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 113329) +ArbitrumValidator_Validate:test_PostSequencerOffline() (gas: 69068) +OptimismCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46888) +OptimismCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22155) +OptimismCrossDomainForwarder_Constructor:test_InitialState() (gas: 18266) +OptimismCrossDomainForwarder_Forward:test_Forward() (gas: 58025) +OptimismCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32546) +OptimismCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13859) +OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48886) +OptimismCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28767) +OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) +OptimismCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) +OptimismCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46888) +OptimismCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22155) +OptimismCrossDomainGovernor_Constructor:test_InitialState() (gas: 18289) +OptimismCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47557) +OptimismCrossDomainGovernor_Forward:test_Forward() (gas: 58096) +OptimismCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32627) +OptimismCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16061) +OptimismCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29181) +OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 72695) +OptimismCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72685) +OptimismCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16051) +OptimismCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 75908) +OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48886) +OptimismCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28767) +OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) +OptimismCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 59095) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 59635) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 58950) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 56887) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 56773) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 57309) +OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 56740) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 65617) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17679) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17897) +OptimismSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17603) +OptimismSequencerUptimeFeed_Constructor:test_InitialState() (gas: 21078) +OptimismSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 67197) +OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 597640) +OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 573807) +OptimismSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 66532) +OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13200) +OptimismSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23607) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 74035) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 96155) +OptimismSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 96215) +OptimismValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 15503) +OptimismValidator_Validate:test_PostSequencerOffline() (gas: 74813) +OptimismValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 74869) +OptimismValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15563) +ScrollCrossDomainForwarder_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46988) +ScrollCrossDomainForwarder_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22207) +ScrollCrossDomainForwarder_Constructor:test_InitialState() (gas: 17930) +ScrollCrossDomainForwarder_Forward:test_Forward() (gas: 58092) +ScrollCrossDomainForwarder_Forward:test_ForwardRevert() (gas: 32619) +ScrollCrossDomainForwarder_Forward:test_NotCallableByUnknownAddress() (gas: 13859) +ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1Owner() (gas: 48952) +ScrollCrossDomainForwarder_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28833) +ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) +ScrollCrossDomainForwarder_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) +ScrollCrossDomainGovernor_AcceptL1Ownership:test_CallableByPendingL1Owner() (gas: 46988) +ScrollCrossDomainGovernor_AcceptL1Ownership:test_NotCallableByNonPendingOwners() (gas: 22207) +ScrollCrossDomainGovernor_Constructor:test_InitialState() (gas: 17953) +ScrollCrossDomainGovernor_Forward:test_CallableByL2Owner() (gas: 47552) +ScrollCrossDomainGovernor_Forward:test_Forward() (gas: 58158) +ScrollCrossDomainGovernor_Forward:test_ForwardRevert() (gas: 32697) +ScrollCrossDomainGovernor_Forward:test_NotCallableByUnknownAddress() (gas: 16058) +ScrollCrossDomainGovernor_ForwardDelegate:test_BubbleUpRevert() (gas: 29248) +ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByCrossDomainMessengerAddressOrL1Owner() (gas: 72756) +ScrollCrossDomainGovernor_ForwardDelegate:test_CallableByL2Owner() (gas: 72746) +ScrollCrossDomainGovernor_ForwardDelegate:test_NotCallableByUnknownAddress() (gas: 16048) +ScrollCrossDomainGovernor_ForwardDelegate:test_RevertsBatchWhenOneCallFails() (gas: 75970) +ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1Owner() (gas: 48952) +ScrollCrossDomainGovernor_TransferL1Ownership:test_CallableByL1OwnerOrZeroAddress() (gas: 28833) +ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByL2Owner() (gas: 16134) +ScrollCrossDomainGovernor_TransferL1Ownership:test_NotCallableByNonOwners() (gas: 11011) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetAnswer() (gas: 57250) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetRoundData() (gas: 57780) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForGetTimestamp() (gas: 57105) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestAnswer() (gas: 54888) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRound() (gas: 54768) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestRoundData() (gas: 55473) +ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts:test_GasUsageForLatestTimestamp() (gas: 54758) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_AggregatorV3Interface() (gas: 63903) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetAnswerWhenRoundDoesNotExistYet() (gas: 17675) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetRoundDataWhenRoundDoesNotExistYet() (gas: 17893) +ScrollSequencerUptimeFeed_AggregatorV3Interface:test_RevertGetTimestampWhenRoundDoesNotExistYet() (gas: 17599) +ScrollSequencerUptimeFeed_Constructor:test_InitialState() (gas: 102485) +ScrollSequencerUptimeFeed_GasCosts:test_GasCosts() (gas: 64888) +ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() (gas: 597491) +ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions:test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() (gas: 573807) +ScrollSequencerUptimeFeed_UpdateStatus:test_IgnoreOutOfOrderUpdates() (gas: 64417) +ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddr() (gas: 13200) +ScrollSequencerUptimeFeed_UpdateStatus:test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() (gas: 23607) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenNoChange() (gas: 71618) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndNoTimeChange() (gas: 92018) +ScrollSequencerUptimeFeed_UpdateStatus:test_UpdateStatusWhenStatusChangeAndTimeChange() (gas: 92078) +ScrollValidator_SetGasLimit:test_CorrectlyUpdatesTheGasLimit() (gas: 15503) +ScrollValidator_Validate:test_PostSequencerOffline() (gas: 75094) +ScrollValidator_Validate:test_PostSequencerStatusWhenThereIsNotStatusChange() (gas: 75156) +ScrollValidator_Validate:test_RevertsIfCalledByAnAccountWithNoAccess() (gas: 15563) \ No newline at end of file diff --git a/contracts/package.json b/contracts/package.json index 1503c822ea4..5d4b6324eee 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "pnpm compile && ./scripts/prepublish_generate_abi_folder", "publish-beta": "pnpm publish --tag beta", "publish-prod": "npm dist-tag add @chainlink/contracts@0.8.0 latest", - "solhint": "solhint --max-warnings 376 \"./src/v0.8/**/*.sol\"" + "solhint": "solhint --max-warnings 33 \"./src/v0.8/**/*.sol\"" }, "files": [ "src/v0.8", @@ -47,44 +47,45 @@ "@typechain/ethers-v5": "^7.2.0", "@typechain/hardhat": "^7.0.0", "@types/cbor": "5.0.1", - "@types/chai": "^4.3.10", + "@types/chai": "^4.3.11", "@types/debug": "^4.1.12", "@types/deep-equal-in-any-order": "^1.0.3", - "@types/mocha": "^10.0.4", - "@types/node": "^16.18.61", - "@typescript-eslint/eslint-plugin": "^6.11.0", - "@typescript-eslint/parser": "^6.11.0", + "@types/mocha": "^10.0.6", + "@types/node": "^16.18.68", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", "abi-to-sol": "^0.6.6", "cbor": "^5.2.0", "chai": "^4.3.10", "debug": "^4.3.4", - "eslint": "^8.53.0", - "eslint-config-prettier": "^9.0.0", + "eslint": "^8.55.0", + "eslint-config-prettier": "^9.1.0", "deep-equal-in-any-order": "^2.0.6", "eslint-plugin-prettier": "^5.0.1", "ethereum-waffle": "^3.4.4", "ethers": "~5.7.2", - "hardhat": "~2.19.1", + "hardhat": "~2.19.2", "hardhat-abi-exporter": "^2.10.1", "hardhat-contract-sizer": "^2.10.0", "hardhat-gas-reporter": "^1.0.9", "hardhat-ignore-warnings": "^0.2.6", "istanbul": "^0.4.5", "moment": "^2.29.4", - "prettier": "^3.1.0", + "prettier": "^3.1.1", "prettier-plugin-solidity": "1.2.0", "rlp": "^2.2.7", "solhint": "^4.0.0", "solhint-plugin-chainlink-solidity": "git+https://github.com/smartcontractkit/chainlink-solhint-rules.git#v1.2.0", "solhint-plugin-prettier": "^0.1.0", "solidity-coverage": "^0.8.5", - "ts-node": "^10.9.1", + "ts-node": "^10.9.2", "tslib": "^2.6.2", "typechain": "^8.2.1", - "typescript": "^5.2.2" + "typescript": "^5.3.3" }, "dependencies": { - "@eth-optimism/contracts": "0.5.37", + "@eth-optimism/contracts": "0.6.0", + "@scroll-tech/contracts": "0.1.0", "@openzeppelin/contracts": "4.9.3", "@openzeppelin/contracts-upgradeable": "4.9.3" } diff --git a/contracts/pnpm-lock.yaml b/contracts/pnpm-lock.yaml index fbae71fb3d4..1b18835dc2e 100644 --- a/contracts/pnpm-lock.yaml +++ b/contracts/pnpm-lock.yaml @@ -9,14 +9,17 @@ overrides: dependencies: '@eth-optimism/contracts': - specifier: 0.5.37 - version: 0.5.37(ethers@5.7.2) + specifier: 0.6.0 + version: 0.6.0(ethers@5.7.2) '@openzeppelin/contracts': specifier: 4.9.3 version: 4.9.3 '@openzeppelin/contracts-upgradeable': specifier: 4.9.3 version: 4.9.3 + '@scroll-tech/contracts': + specifier: 0.1.0 + version: 0.1.0 devDependencies: '@ethereum-waffle/mock-contract': @@ -39,34 +42,34 @@ devDependencies: version: 5.7.0 '@nomicfoundation/hardhat-network-helpers': specifier: ^1.0.9 - version: 1.0.9(hardhat@2.19.1) + version: 1.0.9(hardhat@2.19.2) '@nomiclabs/hardhat-ethers': specifier: ^2.2.3 - version: 2.2.3(ethers@5.7.2)(hardhat@2.19.1) + version: 2.2.3(ethers@5.7.2)(hardhat@2.19.2) '@nomiclabs/hardhat-etherscan': specifier: ^3.1.7 - version: 3.1.7(hardhat@2.19.1) + version: 3.1.7(hardhat@2.19.2) '@nomiclabs/hardhat-waffle': specifier: 2.0.6 - version: 2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.19.1) + version: 2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.19.2) '@openzeppelin/hardhat-upgrades': specifier: 1.28.0 - version: 1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(ethers@5.7.2)(hardhat@2.19.1) + version: 1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(ethers@5.7.2)(hardhat@2.19.2) '@openzeppelin/test-helpers': specifier: ^0.5.16 version: 0.5.16(bn.js@4.12.0) '@typechain/ethers-v5': specifier: ^7.2.0 - version: 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.2.2) + version: 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.3.3) '@typechain/hardhat': specifier: ^7.0.0 - version: 7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.19.1)(typechain@8.3.2) + version: 7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.19.2)(typechain@8.3.2) '@types/cbor': specifier: 5.0.1 version: 5.0.1 '@types/chai': - specifier: ^4.3.10 - version: 4.3.10 + specifier: ^4.3.11 + version: 4.3.11 '@types/debug': specifier: ^4.1.12 version: 4.1.12 @@ -74,17 +77,17 @@ devDependencies: specifier: ^1.0.3 version: 1.0.3 '@types/mocha': - specifier: ^10.0.4 - version: 10.0.4 + specifier: ^10.0.6 + version: 10.0.6 '@types/node': - specifier: ^16.18.61 - version: 16.18.61 + specifier: ^16.18.68 + version: 16.18.68 '@typescript-eslint/eslint-plugin': - specifier: ^6.11.0 - version: 6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2) + specifier: ^6.14.0 + version: 6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3) '@typescript-eslint/parser': - specifier: ^6.11.0 - version: 6.11.0(eslint@8.53.0)(typescript@5.2.2) + specifier: ^6.14.0 + version: 6.14.0(eslint@8.55.0)(typescript@5.3.3) abi-to-sol: specifier: ^0.6.6 version: 0.6.6 @@ -101,32 +104,32 @@ devDependencies: specifier: ^2.0.6 version: 2.0.6 eslint: - specifier: ^8.53.0 - version: 8.53.0 + specifier: ^8.55.0 + version: 8.55.0 eslint-config-prettier: - specifier: ^9.0.0 - version: 9.0.0(eslint@8.53.0) + specifier: ^9.1.0 + version: 9.1.0(eslint@8.55.0) eslint-plugin-prettier: specifier: ^5.0.1 - version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0) + version: 5.0.1(eslint-config-prettier@9.1.0)(eslint@8.55.0)(prettier@3.1.1) ethereum-waffle: specifier: ^3.4.4 - version: 3.4.4(typescript@5.2.2) + version: 3.4.4(typescript@5.3.3) ethers: specifier: ~5.7.2 version: 5.7.2 hardhat: - specifier: ~2.19.1 - version: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + specifier: ~2.19.2 + version: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) hardhat-abi-exporter: specifier: ^2.10.1 - version: 2.10.1(hardhat@2.19.1) + version: 2.10.1(hardhat@2.19.2) hardhat-contract-sizer: specifier: ^2.10.0 - version: 2.10.0(hardhat@2.19.1) + version: 2.10.0(hardhat@2.19.2) hardhat-gas-reporter: specifier: ^1.0.9 - version: 1.0.9(debug@4.3.4)(hardhat@2.19.1) + version: 1.0.9(debug@4.3.4)(hardhat@2.19.2) hardhat-ignore-warnings: specifier: ^0.2.6 version: 0.2.9 @@ -137,11 +140,11 @@ devDependencies: specifier: ^2.29.4 version: 2.29.4 prettier: - specifier: ^3.1.0 - version: 3.1.0 + specifier: ^3.1.1 + version: 3.1.1 prettier-plugin-solidity: specifier: 1.2.0 - version: 1.2.0(prettier@3.1.0) + version: 1.2.0(prettier@3.1.1) rlp: specifier: ^2.2.7 version: 2.2.7 @@ -153,22 +156,22 @@ devDependencies: version: github.com/smartcontractkit/chainlink-solhint-rules/cfc50b32f95b730304a50deb2e27e88d87115874 solhint-plugin-prettier: specifier: ^0.1.0 - version: 0.1.0(prettier-plugin-solidity@1.2.0)(prettier@3.1.0) + version: 0.1.0(prettier-plugin-solidity@1.2.0)(prettier@3.1.1) solidity-coverage: specifier: ^0.8.5 - version: 0.8.5(hardhat@2.19.1) + version: 0.8.5(hardhat@2.19.2) ts-node: - specifier: ^10.9.1 - version: 10.9.1(@types/node@16.18.61)(typescript@5.2.2) + specifier: ^10.9.2 + version: 10.9.2(@types/node@16.18.68)(typescript@5.3.3) tslib: specifier: ^2.6.2 version: 2.6.2 typechain: specifier: ^8.2.1 - version: 8.3.2(typescript@5.2.2) + version: 8.3.2(typescript@5.3.3) typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 packages: @@ -324,13 +327,13 @@ packages: deprecated: Please use @ensdomains/ens-contracts dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.53.0): + /@eslint-community/eslint-utils@4.4.0(eslint@8.55.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.53.0 + eslint: 8.55.0 eslint-visitor-keys: 3.4.3 dev: true @@ -339,8 +342,8 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dev: true - /@eslint/eslintrc@2.1.3: - resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==} + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 @@ -356,17 +359,17 @@ packages: - supports-color dev: true - /@eslint/js@8.53.0: - resolution: {integrity: sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==} + /@eslint/js@8.55.0: + resolution: {integrity: sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@eth-optimism/contracts@0.5.37(ethers@5.7.2): - resolution: {integrity: sha512-HbNUUDIM1dUAM0hWPfGp3l9/Zte40zi8QhVbUSIwdYRA7jG7cZgbteqavrjW8wwFqxkWX9IrtA0KAR7pNlSAIQ==} + /@eth-optimism/contracts@0.6.0(ethers@5.7.2): + resolution: {integrity: sha512-vQ04wfG9kMf1Fwy3FEMqH2QZbgS0gldKhcBeBUPfO8zu68L61VI97UDXmsMQXzTsEAxK8HnokW3/gosl4/NW3w==} peerDependencies: ethers: ^5 dependencies: - '@eth-optimism/core-utils': 0.10.1 + '@eth-optimism/core-utils': 0.12.0 '@ethersproject/abstract-provider': 5.7.0 '@ethersproject/abstract-signer': 5.7.0 ethers: 5.7.2 @@ -375,8 +378,8 @@ packages: - utf-8-validate dev: false - /@eth-optimism/core-utils@0.10.1: - resolution: {integrity: sha512-IJvG5UtYvyz6An9QdohlCLoeB3NBFxx2lRJKlPzvYYlfugUNNCHsajRIWIwJTcPRRma0WPd46JUsKACLJDdNrA==} + /@eth-optimism/core-utils@0.12.0: + resolution: {integrity: sha512-qW+7LZYCz7i8dRa7SRlUKIo1VBU8lvN0HeXCxJR+z+xtMzMQpPds20XJNCMclszxYQHkXY00fOT6GvFw9ZL6nw==} dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/abstract-provider': 5.7.0 @@ -412,7 +415,7 @@ packages: - utf-8-validate dev: true - /@ethereum-waffle/compiler@3.4.4(typescript@5.2.2): + /@ethereum-waffle/compiler@3.4.4(typescript@5.3.3): resolution: {integrity: sha512-RUK3axJ8IkD5xpWjWoJgyHclOeEzDLQFga6gKpeGxiS/zBu+HB0W2FvsrrLalTFIaPw/CGYACRBSIxqiCqwqTQ==} engines: {node: '>=10.0'} dependencies: @@ -426,7 +429,7 @@ packages: node-fetch: 2.6.7 solc: 0.6.12 ts-generator: 0.1.1 - typechain: 3.0.0(typescript@5.2.2) + typechain: 3.0.0(typescript@5.3.3) transitivePeerDependencies: - bufferutil - encoding @@ -1037,13 +1040,13 @@ packages: - utf-8-validate dev: true - /@nomicfoundation/hardhat-network-helpers@1.0.9(hardhat@2.19.1): + /@nomicfoundation/hardhat-network-helpers@1.0.9(hardhat@2.19.2): resolution: {integrity: sha512-OXWCv0cHpwLUO2u7bFxBna6dQtCC2Gg/aN/KtJLO7gmuuA28vgmVKYFRCDUqrbjujzgfwQ2aKyZ9Y3vSmDqS7Q==} peerDependencies: hardhat: ^2.9.5 dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) dev: true /@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.0: @@ -1152,17 +1155,17 @@ packages: '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.0 dev: true - /@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.19.1): + /@nomiclabs/hardhat-ethers@2.2.3(ethers@5.7.2)(hardhat@2.19.2): resolution: {integrity: sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==} peerDependencies: ethers: ^5.0.0 hardhat: ^2.0.0 dependencies: ethers: 5.7.2 - hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) dev: true - /@nomiclabs/hardhat-etherscan@3.1.7(hardhat@2.19.1): + /@nomiclabs/hardhat-etherscan@3.1.7(hardhat@2.19.2): resolution: {integrity: sha512-tZ3TvSgpvsQ6B6OGmo1/Au6u8BrAkvs1mIC/eURA3xgIfznUZBhmpne8hv7BXUzw9xNL3fXdpOYgOQlVMTcoHQ==} peerDependencies: hardhat: ^2.0.4 @@ -1173,7 +1176,7 @@ packages: chalk: 2.4.2 debug: 4.3.4(supports-color@8.1.1) fs-extra: 7.0.1 - hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) lodash: 4.17.21 semver: 6.3.0 table: 6.8.1 @@ -1182,7 +1185,7 @@ packages: - supports-color dev: true - /@nomiclabs/hardhat-waffle@2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.19.1): + /@nomiclabs/hardhat-waffle@2.0.6(@nomiclabs/hardhat-ethers@2.2.3)(@types/sinon-chai@3.2.8)(ethereum-waffle@3.4.4)(ethers@5.7.2)(hardhat@2.19.2): resolution: {integrity: sha512-+Wz0hwmJGSI17B+BhU/qFRZ1l6/xMW82QGXE/Gi+WTmwgJrQefuBs1lIf7hzQ1hLk6hpkvb/zwcNkpVKRYTQYg==} peerDependencies: '@nomiclabs/hardhat-ethers': ^2.0.0 @@ -1191,11 +1194,11 @@ packages: ethers: ^5.0.0 hardhat: ^2.0.0 dependencies: - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.19.1) + '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.19.2) '@types/sinon-chai': 3.2.8 - ethereum-waffle: 3.4.4(typescript@5.2.2) + ethereum-waffle: 3.4.4(typescript@5.3.3) ethers: 5.7.2 - hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) dev: true /@openzeppelin/contract-loader@0.6.3: @@ -1226,7 +1229,7 @@ packages: - encoding dev: true - /@openzeppelin/hardhat-upgrades@1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(ethers@5.7.2)(hardhat@2.19.1): + /@openzeppelin/hardhat-upgrades@1.28.0(@nomiclabs/hardhat-ethers@2.2.3)(@nomiclabs/hardhat-etherscan@3.1.7)(ethers@5.7.2)(hardhat@2.19.2): resolution: {integrity: sha512-7sb/Jf+X+uIufOBnmHR0FJVWuxEs2lpxjJnLNN6eCJCP8nD0v+Ot5lTOW2Qb/GFnh+fLvJtEkhkowz4ZQ57+zQ==} hasBin: true peerDependencies: @@ -1239,15 +1242,15 @@ packages: '@nomiclabs/harhdat-etherscan': optional: true dependencies: - '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.19.1) - '@nomiclabs/hardhat-etherscan': 3.1.7(hardhat@2.19.1) + '@nomiclabs/hardhat-ethers': 2.2.3(ethers@5.7.2)(hardhat@2.19.2) + '@nomiclabs/hardhat-etherscan': 3.1.7(hardhat@2.19.2) '@openzeppelin/defender-base-client': 1.49.0(debug@4.3.4) '@openzeppelin/platform-deploy-client': 0.8.0(debug@4.3.4) '@openzeppelin/upgrades-core': 1.30.1 chalk: 4.1.2 debug: 4.3.4(supports-color@8.1.1) ethers: 5.7.2 - hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) proper-lockfile: 4.1.2 transitivePeerDependencies: - encoding @@ -1338,12 +1341,12 @@ packages: config-chain: 1.1.13 dev: true - /@prettier/sync@0.3.0(prettier@3.1.0): + /@prettier/sync@0.3.0(prettier@3.1.1): resolution: {integrity: sha512-3dcmCyAxIcxy036h1I7MQU/uEEBq8oLwf1CE3xeze+MPlgkdlb/+w6rGR/1dhp6Hqi17fRS6nvwnOzkESxEkOw==} peerDependencies: prettier: ^3.0.0 dependencies: - prettier: 3.1.0 + prettier: 3.1.1 dev: true /@resolver-engine/core@0.3.3: @@ -1387,6 +1390,10 @@ packages: - supports-color dev: true + /@scroll-tech/contracts@0.1.0: + resolution: {integrity: sha512-aBbDOc3WB/WveZdpJYcrfvMYMz7ZTEiW8M9XMJLba8p9FAR5KGYB/cV+8+EUsq3MKt7C1BfR+WnXoTVdvwIY6w==} + dev: false + /@scure/base@1.1.1: resolution: {integrity: sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==} dev: true @@ -1660,10 +1667,10 @@ packages: typechain: ^3.0.0 dependencies: ethers: 5.7.2 - typechain: 3.0.0(typescript@5.2.2) + typechain: 3.0.0(typescript@5.3.3) dev: true - /@typechain/ethers-v5@7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.2.2): + /@typechain/ethers-v5@7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.3.3): resolution: {integrity: sha512-jfcmlTvaaJjng63QsT49MT6R1HFhtO/TBMWbyzPFSzMmVIqb2tL6prnKBs4ZJrSvmgIXWy+ttSjpaxCTq8D/Tw==} peerDependencies: '@ethersproject/abi': ^5.0.0 @@ -1678,12 +1685,12 @@ packages: '@ethersproject/providers': 5.7.2 ethers: 5.7.2 lodash: 4.17.21 - ts-essentials: 7.0.3(typescript@5.2.2) - typechain: 8.3.2(typescript@5.2.2) - typescript: 5.2.2 + ts-essentials: 7.0.3(typescript@5.3.3) + typechain: 8.3.2(typescript@5.3.3) + typescript: 5.3.3 dev: true - /@typechain/hardhat@7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.19.1)(typechain@8.3.2): + /@typechain/hardhat@7.0.0(@ethersproject/abi@5.7.0)(@ethersproject/providers@5.7.2)(@typechain/ethers-v5@7.2.0)(ethers@5.7.2)(hardhat@2.19.2)(typechain@8.3.2): resolution: {integrity: sha512-XB79i5ewg9Met7gMVGfgVkmypicbnI25T5clJBEooMoW2161p4zvKFpoS2O+lBppQyMrPIZkdvl2M3LMDayVcA==} peerDependencies: '@ethersproject/abi': ^5.4.7 @@ -1695,23 +1702,23 @@ packages: dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/providers': 5.7.2 - '@typechain/ethers-v5': 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.2.2) + '@typechain/ethers-v5': 7.2.0(@ethersproject/abi@5.7.0)(@ethersproject/bytes@5.7.0)(@ethersproject/providers@5.7.2)(ethers@5.7.2)(typechain@8.3.2)(typescript@5.3.3) ethers: 5.7.2 fs-extra: 9.1.0 - hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) - typechain: 8.3.2(typescript@5.2.2) + hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) + typechain: 8.3.2(typescript@5.3.3) dev: true /@types/bn.js@4.11.6: resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true /@types/bn.js@5.1.1: resolution: {integrity: sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true /@types/cacheable-request@6.0.2: @@ -1719,24 +1726,24 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 16.18.61 + '@types/node': 16.18.68 '@types/responselike': 1.0.0 dev: true /@types/cbor@5.0.1: resolution: {integrity: sha512-zVqJy2KzusZPLOgyGJDnOIbu3DxIGGqxYbEwtEEe4Z+la8jwIhOyb+GMrlHafs5tvKruwf8f8qOYP6zTvse/pw==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true - /@types/chai@4.3.10: - resolution: {integrity: sha512-of+ICnbqjmFCiixUnqRulbylyXQrPqIGf/B3Jax1wIF3DvSheysQxAWvqHhZiW3IQrycvokcLcFQlveGp+vyNg==} + /@types/chai@4.3.11: + resolution: {integrity: sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==} dev: true /@types/concat-stream@1.6.1: resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true /@types/debug@4.1.12: @@ -1756,7 +1763,7 @@ packages: /@types/form-data@0.0.33: resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true /@types/glob@7.1.1: @@ -1764,7 +1771,7 @@ packages: dependencies: '@types/events': 3.0.0 '@types/minimatch': 3.0.3 - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true /@types/http-cache-semantics@4.0.1: @@ -1778,7 +1785,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true /@types/lru-cache@5.1.1: @@ -1792,11 +1799,11 @@ packages: /@types/mkdirp@0.5.2: resolution: {integrity: sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true - /@types/mocha@10.0.4: - resolution: {integrity: sha512-xKU7bUjiFTIttpWaIZ9qvgg+22O1nmbA+HRxdlR+u6TWsGfmFdXrheJoK4fFxrHNVIOBDvDNKZG+LYBpMHpX3w==} + /@types/mocha@10.0.6: + resolution: {integrity: sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==} dev: true /@types/ms@0.7.31: @@ -1806,7 +1813,7 @@ packages: /@types/node-fetch@2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 form-data: 3.0.1 dev: true @@ -1818,8 +1825,8 @@ packages: resolution: {integrity: sha512-7xHmXm/QJ7cbK2laF+YYD7gb5MggHIIQwqyjin3bpEGiSuvScMQ5JZZXPvRipi1MwckTQbJZROMns/JxdnIL1Q==} dev: true - /@types/node@16.18.61: - resolution: {integrity: sha512-k0N7BqGhJoJzdh6MuQg1V1ragJiXTh8VUBAZTWjJ9cUq23SG0F0xavOwZbhiP4J3y20xd6jxKx+xNUhkMAi76Q==} + /@types/node@16.18.68: + resolution: {integrity: sha512-sG3hPIQwJLoewrN7cr0dwEy+yF5nD4D/4FxtQpFciRD/xwUzgD+G05uxZHv5mhfXo4F9Jkp13jjn0CC2q325sg==} dev: true /@types/node@8.10.66: @@ -1829,7 +1836,7 @@ packages: /@types/pbkdf2@3.1.0: resolution: {integrity: sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true /@types/prettier@2.7.1: @@ -1843,26 +1850,26 @@ packages: /@types/readable-stream@2.3.15: resolution: {integrity: sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 safe-buffer: 5.1.2 dev: true /@types/resolve@0.0.8: resolution: {integrity: sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true /@types/secp256k1@4.0.3: resolution: {integrity: sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==} dependencies: - '@types/node': 16.18.61 + '@types/node': 16.18.68 dev: true /@types/semver@7.5.0: @@ -1872,7 +1879,7 @@ packages: /@types/sinon-chai@3.2.8: resolution: {integrity: sha512-d4ImIQbT/rKMG8+AXpmcan5T2/PNeSjrYhvkwet6z0p8kzYtfgA32xzOBlbU0yqJfq+/0Ml805iFoODO0LP5/g==} dependencies: - '@types/chai': 4.3.10 + '@types/chai': 4.3.11 '@types/sinon': 10.0.13 dev: true @@ -1886,8 +1893,8 @@ packages: resolution: {integrity: sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==} dev: true - /@typescript-eslint/eslint-plugin@6.11.0(@typescript-eslint/parser@6.11.0)(eslint@8.53.0)(typescript@5.2.2): - resolution: {integrity: sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==} + /@typescript-eslint/eslint-plugin@6.14.0(@typescript-eslint/parser@6.14.0)(eslint@8.55.0)(typescript@5.3.3): + resolution: {integrity: sha512-1ZJBykBCXaSHG94vMMKmiHoL0MhNHKSVlcHVYZNw+BKxufhqQVTOawNpwwI1P5nIFZ/4jLVop0mcY6mJJDFNaw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha @@ -1898,25 +1905,25 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.8.0 - '@typescript-eslint/parser': 6.11.0(eslint@8.53.0)(typescript@5.2.2) - '@typescript-eslint/scope-manager': 6.11.0 - '@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) - '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.11.0 + '@typescript-eslint/parser': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/scope-manager': 6.14.0 + '@typescript-eslint/type-utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.14.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.53.0 + eslint: 8.55.0 graphemer: 1.4.0 ignore: 5.2.4 natural-compare: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.2.2) - typescript: 5.2.2 + ts-api-utils: 1.0.3(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser@6.11.0(eslint@8.53.0)(typescript@5.2.2): - resolution: {integrity: sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==} + /@typescript-eslint/parser@6.14.0(eslint@8.55.0)(typescript@5.3.3): + resolution: {integrity: sha512-QjToC14CKacd4Pa7JK4GeB/vHmWFJckec49FR4hmIRf97+KXole0T97xxu9IFiPxVQ1DBWrQ5wreLwAGwWAVQA==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -1925,27 +1932,27 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 6.11.0 - '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) - '@typescript-eslint/visitor-keys': 6.11.0 + '@typescript-eslint/scope-manager': 6.14.0 + '@typescript-eslint/types': 6.14.0 + '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) + '@typescript-eslint/visitor-keys': 6.14.0 debug: 4.3.4(supports-color@8.1.1) - eslint: 8.53.0 - typescript: 5.2.2 + eslint: 8.55.0 + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@6.11.0: - resolution: {integrity: sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A==} + /@typescript-eslint/scope-manager@6.14.0: + resolution: {integrity: sha512-VT7CFWHbZipPncAZtuALr9y3EuzY1b1t1AEkIq2bTXUPKw+pHoXflGNG5L+Gv6nKul1cz1VH8fz16IThIU0tdg==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/visitor-keys': 6.11.0 + '@typescript-eslint/types': 6.14.0 + '@typescript-eslint/visitor-keys': 6.14.0 dev: true - /@typescript-eslint/type-utils@6.11.0(eslint@8.53.0)(typescript@5.2.2): - resolution: {integrity: sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==} + /@typescript-eslint/type-utils@6.14.0(eslint@8.55.0)(typescript@5.3.3): + resolution: {integrity: sha512-x6OC9Q7HfYKqjnuNu5a7kffIYs3No30isapRBJl1iCHLitD8O0lFbRcVGiOcuyN837fqXzPZ1NS10maQzZMKqw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 @@ -1954,23 +1961,23 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) - '@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.2.2) + '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) + '@typescript-eslint/utils': 6.14.0(eslint@8.55.0)(typescript@5.3.3) debug: 4.3.4(supports-color@8.1.1) - eslint: 8.53.0 - ts-api-utils: 1.0.3(typescript@5.2.2) - typescript: 5.2.2 + eslint: 8.55.0 + ts-api-utils: 1.0.3(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types@6.11.0: - resolution: {integrity: sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA==} + /@typescript-eslint/types@6.14.0: + resolution: {integrity: sha512-uty9H2K4Xs8E47z3SnXEPRNDfsis8JO27amp2GNCnzGETEW3yTqEIVg5+AI7U276oGF/tw6ZA+UesxeQ104ceA==} engines: {node: ^16.0.0 || >=18.0.0} dev: true - /@typescript-eslint/typescript-estree@6.11.0(typescript@5.2.2): - resolution: {integrity: sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==} + /@typescript-eslint/typescript-estree@6.14.0(typescript@5.3.3): + resolution: {integrity: sha512-yPkaLwK0yH2mZKFE/bXkPAkkFgOv15GJAUzgUVonAbv0Hr4PK/N2yaA/4XQbTZQdygiDkpt5DkxPELqHguNvyw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: typescript: '*' @@ -1978,42 +1985,42 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/visitor-keys': 6.11.0 + '@typescript-eslint/types': 6.14.0 + '@typescript-eslint/visitor-keys': 6.14.0 debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.3(typescript@5.2.2) - typescript: 5.2.2 + ts-api-utils: 1.0.3(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@6.11.0(eslint@8.53.0)(typescript@5.2.2): - resolution: {integrity: sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==} + /@typescript-eslint/utils@6.14.0(eslint@8.55.0)(typescript@5.3.3): + resolution: {integrity: sha512-XwRTnbvRr7Ey9a1NT6jqdKX8y/atWG+8fAIu3z73HSP8h06i3r/ClMhmaF/RGWGW1tHJEwij1uEg2GbEmPYvYg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) '@types/json-schema': 7.0.12 '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 6.11.0 - '@typescript-eslint/types': 6.11.0 - '@typescript-eslint/typescript-estree': 6.11.0(typescript@5.2.2) - eslint: 8.53.0 + '@typescript-eslint/scope-manager': 6.14.0 + '@typescript-eslint/types': 6.14.0 + '@typescript-eslint/typescript-estree': 6.14.0(typescript@5.3.3) + eslint: 8.55.0 semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys@6.11.0: - resolution: {integrity: sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ==} + /@typescript-eslint/visitor-keys@6.14.0: + resolution: {integrity: sha512-fB5cw6GRhJUz03MrROVuj5Zm/Q+XWlVdIsFj+Zb1Hvqouc8t+XP2H5y53QYU/MGtd2dPg6/vJJlhoX3xc2ehfw==} engines: {node: ^16.0.0 || >=18.0.0} dependencies: - '@typescript-eslint/types': 6.11.0 + '@typescript-eslint/types': 6.14.0 eslint-visitor-keys: 3.4.3 dev: true @@ -4707,16 +4714,16 @@ packages: source-map: 0.2.0 dev: true - /eslint-config-prettier@9.0.0(eslint@8.53.0): - resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} + /eslint-config-prettier@9.1.0(eslint@8.55.0): + resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.53.0 + eslint: 8.55.0 dev: true - /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0): + /eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.1.0)(eslint@8.55.0)(prettier@3.1.1): resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -4730,9 +4737,9 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.53.0 - eslint-config-prettier: 9.0.0(eslint@8.53.0) - prettier: 3.1.0 + eslint: 8.55.0 + eslint-config-prettier: 9.1.0(eslint@8.55.0) + prettier: 3.1.1 prettier-linter-helpers: 1.0.0 synckit: 0.8.5 dev: true @@ -4750,15 +4757,15 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.53.0: - resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==} + /eslint@8.55.0: + resolution: {integrity: sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.53.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@8.55.0) '@eslint-community/regexpp': 4.8.0 - '@eslint/eslintrc': 2.1.3 - '@eslint/js': 8.53.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.55.0 '@humanwhocodes/config-array': 0.11.13 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 @@ -5053,13 +5060,13 @@ packages: '@scure/bip39': 1.1.0 dev: true - /ethereum-waffle@3.4.4(typescript@5.2.2): + /ethereum-waffle@3.4.4(typescript@5.3.3): resolution: {integrity: sha512-PA9+jCjw4WC3Oc5ocSMBj5sXvueWQeAbvCA+hUlb6oFgwwKyq5ka3bWQ7QZcjzIX+TdFkxP4IbFmoY2D8Dkj9Q==} engines: {node: '>=10.0'} hasBin: true dependencies: '@ethereum-waffle/chai': 3.4.4 - '@ethereum-waffle/compiler': 3.4.4(typescript@5.2.2) + '@ethereum-waffle/compiler': 3.4.4(typescript@5.3.3) '@ethereum-waffle/mock-contract': 3.4.4 '@ethereum-waffle/provider': 3.4.4 ethers: 5.7.2 @@ -5861,7 +5868,7 @@ packages: heap: 0.2.6 level-sublevel: 6.6.4 levelup: 3.1.1 - lodash: 4.17.21 + lodash: 4.17.20 lru-cache: 5.1.1 merkle-patricia-tree: 3.0.0 patch-package: 6.2.2 @@ -6211,7 +6218,7 @@ packages: har-schema: 2.0.0 dev: true - /hardhat-abi-exporter@2.10.1(hardhat@2.19.1): + /hardhat-abi-exporter@2.10.1(hardhat@2.19.2): resolution: {integrity: sha512-X8GRxUTtebMAd2k4fcPyVnCdPa6dYK4lBsrwzKP5yiSq4i+WadWPIumaLfce53TUf/o2TnLpLOduyO1ylE2NHQ==} engines: {node: '>=14.14.0'} peerDependencies: @@ -6219,28 +6226,28 @@ packages: dependencies: '@ethersproject/abi': 5.7.0 delete-empty: 3.0.0 - hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) dev: true - /hardhat-contract-sizer@2.10.0(hardhat@2.19.1): + /hardhat-contract-sizer@2.10.0(hardhat@2.19.2): resolution: {integrity: sha512-QiinUgBD5MqJZJh1hl1jc9dNnpJg7eE/w4/4GEnrcmZJJTDbVFNe3+/3Ep24XqISSkYxRz36czcPHKHd/a0dwA==} peerDependencies: hardhat: ^2.0.0 dependencies: chalk: 4.1.2 cli-table3: 0.6.3 - hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) strip-ansi: 6.0.1 dev: true - /hardhat-gas-reporter@1.0.9(debug@4.3.4)(hardhat@2.19.1): + /hardhat-gas-reporter@1.0.9(debug@4.3.4)(hardhat@2.19.2): resolution: {integrity: sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==} peerDependencies: hardhat: ^2.0.2 dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.27(debug@4.3.4) - hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' @@ -6257,8 +6264,8 @@ packages: solidity-comments: 0.0.2 dev: true - /hardhat@2.19.1(ts-node@10.9.1)(typescript@5.2.2): - resolution: {integrity: sha512-bsWa63g1GB78ZyMN08WLhFElLPA+J+pShuKD1BFO2+88g3l+BL3R07vj9deIi9dMbssxgE714Gof1dBEDGqnCw==} + /hardhat@2.19.2(ts-node@10.9.2)(typescript@5.3.3): + resolution: {integrity: sha512-CRU3+0Cc8Qh9UpxKd8cLADDPes7ZDtKj4dTK+ERtLBomEzhRPLWklJn4VKOwjre9/k8GNd/e9DYxpfuzcxbXPQ==} hasBin: true peerDependencies: ts-node: '*' @@ -6313,9 +6320,9 @@ packages: solc: 0.7.3(debug@4.3.4) source-map-support: 0.5.21 stacktrace-parser: 0.1.10 - ts-node: 10.9.1(@types/node@16.18.61)(typescript@5.2.2) + ts-node: 10.9.2(@types/node@16.18.68)(typescript@5.3.3) tsort: 0.0.1 - typescript: 5.2.2 + typescript: 5.3.3 undici: 5.19.1 uuid: 8.3.2 ws: 7.5.9 @@ -7919,6 +7926,12 @@ packages: /minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + /minimatch@3.0.4: + resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} + dependencies: + brace-expansion: 1.1.11 + dev: true + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -8896,14 +8909,14 @@ packages: dev: true optional: true - /prettier-plugin-solidity@1.2.0(prettier@3.1.0): + /prettier-plugin-solidity@1.2.0(prettier@3.1.1): resolution: {integrity: sha512-fgxcUZpVAP+LlRfy5JI5oaAkXGkmsje2VJ5krv/YMm+rcTZbIUwFguSw5f+WFuttMjpDm6wB4UL7WVkArEfiVA==} engines: {node: '>=16'} peerDependencies: prettier: '>=2.3.0' dependencies: '@solidity-parser/parser': 0.16.2 - prettier: 3.1.0 + prettier: 3.1.1 semver: 7.5.4 solidity-comments-extractor: 0.0.7 dev: true @@ -8914,8 +8927,8 @@ packages: hasBin: true dev: true - /prettier@3.1.0: - resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==} + /prettier@3.1.1: + resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==} engines: {node: '>=14'} hasBin: true dev: true @@ -9232,7 +9245,7 @@ packages: resolution: {integrity: sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==} engines: {node: '>=0.10.0'} dependencies: - minimatch: 3.1.2 + minimatch: 3.0.4 dev: true /reduce-flatten@2.0.0: @@ -9947,16 +9960,16 @@ packages: - debug dev: true - /solhint-plugin-prettier@0.1.0(prettier-plugin-solidity@1.2.0)(prettier@3.1.0): + /solhint-plugin-prettier@0.1.0(prettier-plugin-solidity@1.2.0)(prettier@3.1.1): resolution: {integrity: sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw==} peerDependencies: prettier: ^3.0.0 prettier-plugin-solidity: ^1.0.0 dependencies: - '@prettier/sync': 0.3.0(prettier@3.1.0) - prettier: 3.1.0 + '@prettier/sync': 0.3.0(prettier@3.1.1) + prettier: 3.1.1 prettier-linter-helpers: 1.0.0 - prettier-plugin-solidity: 1.2.0(prettier@3.1.0) + prettier-plugin-solidity: 1.2.0(prettier@3.1.1) dev: true /solhint@4.0.0: @@ -10101,7 +10114,7 @@ packages: solidity-comments-win32-x64-msvc: 0.0.2 dev: true - /solidity-coverage@0.8.5(hardhat@2.19.1): + /solidity-coverage@0.8.5(hardhat@2.19.2): resolution: {integrity: sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ==} hasBin: true peerDependencies: @@ -10117,7 +10130,7 @@ packages: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.19.1(ts-node@10.9.1)(typescript@5.2.2) + hardhat: 2.19.2(ts-node@10.9.2)(typescript@5.3.3) jsonschema: 1.4.0 lodash: 4.17.21 mocha: 10.2.0 @@ -10706,13 +10719,13 @@ packages: engines: {node: '>=0.10.0'} dev: true - /ts-api-utils@1.0.3(typescript@5.2.2): + /ts-api-utils@1.0.3(typescript@5.3.3): resolution: {integrity: sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==} engines: {node: '>=16.13.0'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.2.2 + typescript: 5.3.3 dev: true /ts-command-line-args@2.5.1: @@ -10729,20 +10742,20 @@ packages: resolution: {integrity: sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ==} dev: true - /ts-essentials@6.0.7(typescript@5.2.2): + /ts-essentials@6.0.7(typescript@5.3.3): resolution: {integrity: sha512-2E4HIIj4tQJlIHuATRHayv0EfMGK3ris/GRk1E3CFnsZzeNV+hUmelbaTZHLtXaZppM5oLhHRtO04gINC4Jusw==} peerDependencies: typescript: '>=3.7.0' dependencies: - typescript: 5.2.2 + typescript: 5.3.3 dev: true - /ts-essentials@7.0.3(typescript@5.2.2): + /ts-essentials@7.0.3(typescript@5.3.3): resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} peerDependencies: typescript: '>=3.7.0' dependencies: - typescript: 5.2.2 + typescript: 5.3.3 dev: true /ts-generator@0.1.1: @@ -10760,8 +10773,8 @@ packages: ts-essentials: 1.0.4 dev: true - /ts-node@10.9.1(@types/node@16.18.61)(typescript@5.2.2): - resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + /ts-node@10.9.2(@types/node@16.18.68)(typescript@5.3.3): + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: '@swc/core': '>=1.2.50' @@ -10779,14 +10792,14 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 - '@types/node': 16.18.61 + '@types/node': 16.18.68 acorn: 8.10.0 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.2.2 + typescript: 5.3.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 dev: true @@ -10871,7 +10884,7 @@ packages: resolution: {integrity: sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==} dev: true - /typechain@3.0.0(typescript@5.2.2): + /typechain@3.0.0(typescript@5.3.3): resolution: {integrity: sha512-ft4KVmiN3zH4JUFu2WJBrwfHeDf772Tt2d8bssDTo/YcckKW2D+OwFrHXRC6hJvO3mHjFQTihoMV6fJOi0Hngg==} hasBin: true dependencies: @@ -10880,14 +10893,14 @@ packages: fs-extra: 7.0.1 js-sha3: 0.8.0 lodash: 4.17.21 - ts-essentials: 6.0.7(typescript@5.2.2) + ts-essentials: 6.0.7(typescript@5.3.3) ts-generator: 0.1.1 transitivePeerDependencies: - supports-color - typescript dev: true - /typechain@8.3.2(typescript@5.2.2): + /typechain@8.3.2(typescript@5.3.3): resolution: {integrity: sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==} hasBin: true peerDependencies: @@ -10902,8 +10915,8 @@ packages: mkdirp: 1.0.4 prettier: 2.8.8 ts-command-line-args: 2.5.1 - ts-essentials: 7.0.3(typescript@5.2.2) - typescript: 5.2.2 + ts-essentials: 7.0.3(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - supports-color dev: true @@ -10956,8 +10969,8 @@ packages: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} dev: true - /typescript@5.2.2: - resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + /typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} hasBin: true dev: true diff --git a/contracts/remappings.txt b/contracts/remappings.txt index f0ac4993c2c..a9d24257659 100644 --- a/contracts/remappings.txt +++ b/contracts/remappings.txt @@ -1,6 +1,7 @@ -ds-test/=foundry-lib/forge-std/lib/ds-test/src -forge-std/=foundry-lib/forge-std/src +ds-test/=foundry-lib/forge-std/lib/ds-test/src/ +forge-std/=foundry-lib/forge-std/src/ @openzeppelin/=node_modules/@openzeppelin/ hardhat/=node_modules/hardhat/ -@eth-optimism/=node_modules/@eth-optimism +@eth-optimism/=node_modules/@eth-optimism/ +@scroll-tech/=node_modules/@scroll-tech/ diff --git a/contracts/scripts/generate-automation-master-interface.ts b/contracts/scripts/generate-automation-master-interface.ts index de71c56806b..78c09cf2836 100644 --- a/contracts/scripts/generate-automation-master-interface.ts +++ b/contracts/scripts/generate-automation-master-interface.ts @@ -2,24 +2,20 @@ * @description this script generates a master interface for interacting with the automation registry * @notice run this script with pnpm ts-node ./scripts/generate-automation-master-interface.ts */ -import { KeeperRegistry2_1__factory as KeeperRegistry } from '../typechain/factories/KeeperRegistry2_1__factory' -import { KeeperRegistryLogicA2_1__factory as KeeperRegistryLogicA } from '../typechain/factories/KeeperRegistryLogicA2_1__factory' -import { KeeperRegistryLogicB2_1__factory as KeeperRegistryLogicB } from '../typechain/factories/KeeperRegistryLogicB2_1__factory' +import { AutomationRegistry2_2__factory as Registry } from '../typechain/factories/AutomationRegistry2_2__factory' +import { AutomationRegistryLogicA2_2__factory as RegistryLogicA } from '../typechain/factories/AutomationRegistryLogicA2_2__factory' +import { AutomationRegistryLogicB2_2__factory as RegistryLogicB } from '../typechain/factories/AutomationRegistryLogicB2_2__factory' import { utils } from 'ethers' import fs from 'fs' import { exec } from 'child_process' -const dest = 'src/v0.8/automation/interfaces/v2_1' -const srcDest = `${dest}/IKeeperRegistryMaster.sol` +const dest = 'src/v0.8/automation/dev/interfaces/v2_2' +const srcDest = `${dest}/IAutomationRegistryMaster.sol` const tmpDest = `${dest}/tmp.txt` const combinedABI = [] const abiSet = new Set() -const abis = [ - KeeperRegistry.abi, - KeeperRegistryLogicA.abi, - KeeperRegistryLogicB.abi, -] +const abis = [Registry.abi, RegistryLogicA.abi, RegistryLogicB.abi] for (const abi of abis) { for (const entry of abi) { @@ -44,7 +40,7 @@ const checksum = utils.id(abis.join('')) fs.writeFileSync(`${tmpDest}`, JSON.stringify(combinedABI)) const cmd = ` -cat ${tmpDest} | pnpm abi-to-sol --solidity-version ^0.8.4 --license MIT > ${srcDest} IKeeperRegistryMaster; +cat ${tmpDest} | pnpm abi-to-sol --solidity-version ^0.8.4 --license MIT > ${srcDest} IAutomationRegistryMaster; echo "// abi-checksum: ${checksum}" | cat - ${srcDest} > ${tmpDest} && mv ${tmpDest} ${srcDest}; pnpm prettier --write ${srcDest}; ` diff --git a/contracts/scripts/native_solc_compile_all_automation b/contracts/scripts/native_solc_compile_all_automation index ddf6c2c8bfa..379b647ffe5 100755 --- a/contracts/scripts/native_solc_compile_all_automation +++ b/contracts/scripts/native_solc_compile_all_automation @@ -57,10 +57,18 @@ compileContract automation/v2_1/AutomationRegistrar2_1.sol compileContract automation/v2_1/KeeperRegistry2_1.sol compileContract automation/v2_1/KeeperRegistryLogicA2_1.sol compileContract automation/v2_1/KeeperRegistryLogicB2_1.sol +compileContract automation/v2_1/AutomationUtils2_1.sol compileContract automation/interfaces/v2_1/IKeeperRegistryMaster.sol + +compileContract automation/dev/v2_2/AutomationRegistrar2_2.sol +compileContract automation/dev/v2_2/AutomationRegistry2_2.sol +compileContract automation/dev/v2_2/AutomationRegistryLogicA2_2.sol +compileContract automation/dev/v2_2/AutomationRegistryLogicB2_2.sol +compileContract automation/dev/v2_2/AutomationUtils2_2.sol +compileContract automation/dev/interfaces/v2_2/IAutomationRegistryMaster.sol + compileContract automation/interfaces/ILogAutomation.sol -compileContract automation/v2_1/AutomationUtils2_1.sol -compileContract automation/v2_1/AutomationForwarderLogic.sol +compileContract automation/AutomationForwarderLogic.sol compileContract automation/testhelpers/LogTriggeredStreamsLookup.sol compileContract automation/testhelpers/DummyProtocol.sol diff --git a/contracts/scripts/native_solc_compile_all_l2ep b/contracts/scripts/native_solc_compile_all_l2ep new file mode 100755 index 00000000000..1b9f5fb611d --- /dev/null +++ b/contracts/scripts/native_solc_compile_all_l2ep @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +########### +# Logging # +########### + +set -e + +echo " ┌──────────────────────────────────────────────┐" +echo " │ Compiling L2EP contracts... │" +echo " └──────────────────────────────────────────────┘" + +###################### +# Helper Variable(s) # +###################### + +export SOLC_VERSION="0.8.19" + +SCRIPTPATH="$( + cd "$(dirname "$0")" >/dev/null 2>&1 + pwd -P +)" + +ROOT="$( + cd "$(dirname "$0")" >/dev/null 2>&1 + cd ../ && pwd -P +)" + +###################### +# Helper Function(s) # +###################### + +compileContract() { + local optimize_runs=1000000 + local version="$1" + local srcpath="$2" + solc \ + @openzeppelin/=$ROOT/node_modules/@openzeppelin/ \ + @eth-optimism/=$ROOT/node_modules/@eth-optimism/ \ + @scroll-tech/=$ROOT/node_modules/@scroll-tech/ \ + --overwrite --optimize --optimize-runs $optimize_runs --metadata-hash none \ + -o $ROOT/solc/v$SOLC_VERSION/l2ep/"$version" \ + --abi --bin \ + --allow-paths $ROOT/src/v0.8,$ROOT/node_modules \ + $ROOT/src/v0.8/l2ep/"$srcpath" +} + +################# +# Version 1.0.0 # +################# + +python3 -m pip install --require-hashes -r $SCRIPTPATH/requirements.txt + +solc-select install $SOLC_VERSION +solc-select use $SOLC_VERSION + +compileContract v1_0_0 dev/arbitrum/ArbitrumValidator.sol +compileContract v1_0_0 dev/arbitrum/ArbitrumSequencerUptimeFeed.sol +compileContract v1_0_0 dev/arbitrum/ArbitrumCrossDomainForwarder.sol +compileContract v1_0_0 dev/arbitrum/ArbitrumCrossDomainGovernor.sol + +compileContract v1_0_0 dev/optimism/OptimismValidator.sol +compileContract v1_0_0 dev/optimism/OptimismSequencerUptimeFeed.sol +compileContract v1_0_0 dev/optimism/OptimismCrossDomainForwarder.sol +compileContract v1_0_0 dev/optimism/OptimismCrossDomainGovernor.sol + +compileContract v1_0_0 dev/scroll/ScrollValidator.sol +compileContract v1_0_0 dev/scroll/ScrollSequencerUptimeFeed.sol +compileContract v1_0_0 dev/scroll/ScrollCrossDomainForwarder.sol +compileContract v1_0_0 dev/scroll/ScrollCrossDomainGovernor.sol diff --git a/contracts/scripts/native_solc_compile_all_logpoller b/contracts/scripts/native_solc_compile_all_logpoller index b6ac51ecedb..e8ea2a2be80 100755 --- a/contracts/scripts/native_solc_compile_all_logpoller +++ b/contracts/scripts/native_solc_compile_all_logpoller @@ -29,4 +29,5 @@ compileContract () { } -compileContract tests/LogEmitter.sol \ No newline at end of file +compileContract tests/LogEmitter.sol +compileContract tests/VRFLogEmitter.sol \ No newline at end of file diff --git a/contracts/scripts/native_solc_compile_all_shared b/contracts/scripts/native_solc_compile_all_shared index 9178237b8a5..eeaa9902346 100755 --- a/contracts/scripts/native_solc_compile_all_shared +++ b/contracts/scripts/native_solc_compile_all_shared @@ -32,3 +32,4 @@ compileContract shared/token/ERC677/BurnMintERC677.sol compileContract shared/token/ERC677/LinkToken.sol compileContract shared/mocks/WERC20Mock.sol compileContract vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/ERC20.sol +compileContract shared/test/helpers/ChainReaderTestContract.sol diff --git a/contracts/scripts/native_solc_compile_all_vrf b/contracts/scripts/native_solc_compile_all_vrf index 4eed35cf5bc..3b6b96d2f50 100755 --- a/contracts/scripts/native_solc_compile_all_vrf +++ b/contracts/scripts/native_solc_compile_all_vrf @@ -90,6 +90,7 @@ compileContract vrf/VRFV2Wrapper.sol compileContract vrf/interfaces/VRFV2WrapperInterface.sol compileContract vrf/VRFV2WrapperConsumerBase.sol compileContract vrf/testhelpers/VRFV2WrapperConsumerExample.sol +compileContract vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol compileContract vrf/testhelpers/VRFv2Consumer.sol # VRF Consumers and Mocks @@ -100,6 +101,8 @@ compileContract vrf/testhelpers/VRFLoadTestOwnerlessConsumer.sol compileContract vrf/testhelpers/VRFLoadTestExternalSubOwner.sol compileContract vrf/testhelpers/VRFV2LoadTestWithMetrics.sol compileContract vrf/testhelpers/VRFV2OwnerTestConsumer.sol +compileContractAltOpts vrf/testhelpers/VRFCoordinatorTestV2.sol 10000 +compileContract vrf/testhelpers/VRFMockETHLINKAggregator.sol # Helper contracts compileContract vrf/interfaces/IAuthorizedReceiver.sol diff --git a/contracts/src/v0.8/ChainlinkClient.sol b/contracts/src/v0.8/ChainlinkClient.sol index 2d9302faef7..ef7f7943452 100644 --- a/contracts/src/v0.8/ChainlinkClient.sol +++ b/contracts/src/v0.8/ChainlinkClient.sol @@ -171,6 +171,7 @@ abstract contract ChainlinkClient { s_pendingRequests[requestId] = oracleAddress; emit ChainlinkRequested(requestId); require(s_link.transferAndCall(oracleAddress, payment, encodedRequest), "unable to transferAndCall to oracle"); + return requestId; } /** diff --git a/contracts/src/v0.8/ValidatorProxy.sol b/contracts/src/v0.8/ValidatorProxy.sol index 627af73b395..4584bb02559 100644 --- a/contracts/src/v0.8/ValidatorProxy.sol +++ b/contracts/src/v0.8/ValidatorProxy.sol @@ -167,6 +167,7 @@ contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface current = s_currentAggregator.target; hasProposal = s_currentAggregator.hasNewProposal; proposed = s_proposedAggregator; + return (current, hasProposal, proposed); } /** VALIDATOR CONFIGURATION FUNCTIONS **/ @@ -216,6 +217,7 @@ contract ValidatorProxy is AggregatorValidatorInterface, TypeAndVersionInterface current = s_currentValidator.target; hasProposal = s_currentValidator.hasNewProposal; proposed = s_proposedValidator; + return (current, hasProposal, proposed); } /** diff --git a/contracts/src/v0.8/automation/v2_1/AutomationForwarder.sol b/contracts/src/v0.8/automation/AutomationForwarder.sol similarity index 97% rename from contracts/src/v0.8/automation/v2_1/AutomationForwarder.sol rename to contracts/src/v0.8/automation/AutomationForwarder.sol index e5a80ce3252..f4088ed07fd 100644 --- a/contracts/src/v0.8/automation/v2_1/AutomationForwarder.sol +++ b/contracts/src/v0.8/automation/AutomationForwarder.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol"; +import {IAutomationRegistryConsumer} from "./interfaces/IAutomationRegistryConsumer.sol"; uint256 constant PERFORM_GAS_CUSHION = 5_000; diff --git a/contracts/src/v0.8/automation/v2_1/AutomationForwarderLogic.sol b/contracts/src/v0.8/automation/AutomationForwarderLogic.sol similarity index 80% rename from contracts/src/v0.8/automation/v2_1/AutomationForwarderLogic.sol rename to contracts/src/v0.8/automation/AutomationForwarderLogic.sol index a7903c379df..76da5f68cb9 100644 --- a/contracts/src/v0.8/automation/v2_1/AutomationForwarderLogic.sol +++ b/contracts/src/v0.8/automation/AutomationForwarderLogic.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol"; -import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; +import {IAutomationRegistryConsumer} from "./interfaces/IAutomationRegistryConsumer.sol"; +import {ITypeAndVersion} from "../shared/interfaces/ITypeAndVersion.sol"; contract AutomationForwarderLogic is ITypeAndVersion { IAutomationRegistryConsumer private s_registry; diff --git a/contracts/src/v0.8/automation/dev/MercuryRegistry.sol b/contracts/src/v0.8/automation/dev/MercuryRegistry.sol index 9c14ce69f48..6a5dafc196d 100644 --- a/contracts/src/v0.8/automation/dev/MercuryRegistry.sol +++ b/contracts/src/v0.8/automation/dev/MercuryRegistry.sol @@ -1,9 +1,9 @@ pragma solidity 0.8.6; -import "../../shared/access/ConfirmedOwner.sol"; -import "../interfaces/AutomationCompatibleInterface.sol"; -import "../interfaces/StreamsLookupCompatibleInterface.sol"; -import "../../ChainSpecificUtil.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {AutomationCompatibleInterface} from "../interfaces/AutomationCompatibleInterface.sol"; +import {StreamsLookupCompatibleInterface} from "../interfaces/StreamsLookupCompatibleInterface.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; /*--------------------------------------------------------------------------------------------------------------------+ | Mercury + Automation | diff --git a/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol b/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol index 416b68f3a79..8fa32c8a68e 100644 --- a/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol +++ b/contracts/src/v0.8/automation/dev/MercuryRegistryBatchUpkeep.sol @@ -1,20 +1,20 @@ pragma solidity 0.8.6; -import "../../shared/access/ConfirmedOwner.sol"; -import "../interfaces/AutomationCompatibleInterface.sol"; -import "../interfaces/StreamsLookupCompatibleInterface.sol"; -import "./MercuryRegistry.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {AutomationCompatibleInterface} from "../interfaces/AutomationCompatibleInterface.sol"; +import {StreamsLookupCompatibleInterface} from "../interfaces/StreamsLookupCompatibleInterface.sol"; +import {MercuryRegistry} from "./MercuryRegistry.sol"; contract MercuryRegistryBatchUpkeep is ConfirmedOwner, AutomationCompatibleInterface, StreamsLookupCompatibleInterface { error BatchSizeTooLarge(uint256 batchsize, uint256 maxBatchSize); // Use a reasonable maximum batch size. Every Mercury report is ~750 bytes, too many reports // passed into a single batch could exceed the calldata or transaction size limit for some blockchains. - uint256 constant MAX_BATCH_SIZE = 50; + uint256 public constant MAX_BATCH_SIZE = 50; - MercuryRegistry immutable i_registry; // master registry, where feed data is stored + MercuryRegistry public immutable i_registry; // master registry, where feed data is stored - uint256 s_batchStart; // starting index of upkeep batch on the MercuryRegistry's s_feeds array, inclusive - uint256 s_batchEnd; // ending index of upkeep batch on the MercuryRegistry's s_feeds array, exclusive + uint256 public s_batchStart; // starting index of upkeep batch on the MercuryRegistry's s_feeds array, inclusive + uint256 public s_batchEnd; // ending index of upkeep batch on the MercuryRegistry's s_feeds array, exclusive constructor(address mercuryRegistry, uint256 batchStart, uint256 batchEnd) ConfirmedOwner(msg.sender) { i_registry = MercuryRegistry(mercuryRegistry); diff --git a/contracts/src/v0.8/automation/dev/interfaces/v2_2/IAutomationRegistryMaster.sol b/contracts/src/v0.8/automation/dev/interfaces/v2_2/IAutomationRegistryMaster.sol new file mode 100644 index 00000000000..e67622a3779 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/interfaces/v2_2/IAutomationRegistryMaster.sol @@ -0,0 +1,317 @@ +// abi-checksum: 0x0ed34e4b36bd7b4a5447152c2d61491e6ba7ed944b11e4dfef4fea184708975e +// SPDX-License-Identifier: MIT +// !! THIS FILE WAS AUTOGENERATED BY abi-to-sol v0.6.6. SEE SOURCE BELOW. !! +pragma solidity ^0.8.4; + +interface IAutomationRegistryMaster { + error ArrayHasNoEntries(); + error CannotCancel(); + error CheckDataExceedsLimit(); + error ConfigDigestMismatch(); + error DuplicateEntry(); + error DuplicateSigners(); + error GasLimitCanOnlyIncrease(); + error GasLimitOutsideRange(); + error IncorrectNumberOfFaultyOracles(); + error IncorrectNumberOfSignatures(); + error IncorrectNumberOfSigners(); + error IndexOutOfRange(); + error InsufficientFunds(); + error InvalidDataLength(); + error InvalidPayee(); + error InvalidRecipient(); + error InvalidReport(); + error InvalidSigner(); + error InvalidTransmitter(); + error InvalidTrigger(); + error InvalidTriggerType(); + error MaxCheckDataSizeCanOnlyIncrease(); + error MaxPerformDataSizeCanOnlyIncrease(); + error MigrationNotPermitted(); + error NotAContract(); + error OnlyActiveSigners(); + error OnlyActiveTransmitters(); + error OnlyCallableByAdmin(); + error OnlyCallableByLINKToken(); + error OnlyCallableByOwnerOrAdmin(); + error OnlyCallableByOwnerOrRegistrar(); + error OnlyCallableByPayee(); + error OnlyCallableByProposedAdmin(); + error OnlyCallableByProposedPayee(); + error OnlyCallableByUpkeepPrivilegeManager(); + error OnlyPausedUpkeep(); + error OnlySimulatedBackend(); + error OnlyUnpausedUpkeep(); + error ParameterLengthError(); + error PaymentGreaterThanAllLINK(); + error ReentrantCall(); + error RegistryPaused(); + error RepeatedSigner(); + error RepeatedTransmitter(); + error TargetCheckReverted(bytes reason); + error TooManyOracles(); + error TranscoderNotSet(); + error UpkeepAlreadyExists(); + error UpkeepCancelled(); + error UpkeepNotCanceled(); + error UpkeepNotNeeded(); + error ValueNotChanged(); + event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig); + event CancelledUpkeepReport(uint256 indexed id, bytes trigger); + event ConfigSet( + uint32 previousConfigBlockNumber, + bytes32 configDigest, + uint64 configCount, + address[] signers, + address[] transmitters, + uint8 f, + bytes onchainConfig, + uint64 offchainConfigVersion, + bytes offchainConfig + ); + event DedupKeyAdded(bytes32 indexed dedupKey); + event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); + event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); + event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger); + event OwnerFundsWithdrawn(uint96 amount); + event OwnershipTransferRequested(address indexed from, address indexed to); + event OwnershipTransferred(address indexed from, address indexed to); + event Paused(address account); + event PayeesUpdated(address[] transmitters, address[] payees); + event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to); + event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to); + event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee); + event ReorgedUpkeepReport(uint256 indexed id, bytes trigger); + event StaleUpkeepReport(uint256 indexed id, bytes trigger); + event Transmitted(bytes32 configDigest, uint32 epoch); + event Unpaused(address account); + event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to); + event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to); + event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight); + event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData); + event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit); + event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination); + event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig); + event UpkeepPaused(uint256 indexed id); + event UpkeepPerformed( + uint256 indexed id, + bool indexed success, + uint96 totalPayment, + uint256 gasUsed, + uint256 gasOverhead, + bytes trigger + ); + event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig); + event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom); + event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin); + event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig); + event UpkeepUnpaused(uint256 indexed id); + + fallback() external; + function acceptOwnership() external; + function fallbackTo() external view returns (address); + function latestConfigDetails() external view returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest); + function latestConfigDigestAndEpoch() external view returns (bool scanLogs, bytes32 configDigest, uint32 epoch); + function onTokenTransfer(address sender, uint256 amount, bytes memory data) external; + function owner() external view returns (address); + function setConfig( + address[] memory signers, + address[] memory transmitters, + uint8 f, + bytes memory onchainConfigBytes, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) external; + function setConfigTypeSafe( + address[] memory signers, + address[] memory transmitters, + uint8 f, + AutomationRegistryBase2_2.OnchainConfig memory onchainConfig, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) external; + function simulatePerformUpkeep( + uint256 id, + bytes memory performData + ) external view returns (bool success, uint256 gasUsed); + function transferOwnership(address to) external; + function transmit( + bytes32[3] memory reportContext, + bytes memory rawReport, + bytes32[] memory rs, + bytes32[] memory ss, + bytes32 rawVs + ) external; + function typeAndVersion() external view returns (string memory); + + function addFunds(uint256 id, uint96 amount) external; + function cancelUpkeep(uint256 id) external; + function checkCallback( + uint256 id, + bytes[] memory values, + bytes memory extraData + ) external view returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed); + function checkUpkeep( + uint256 id, + bytes memory triggerData + ) + external + view + returns ( + bool upkeepNeeded, + bytes memory performData, + uint8 upkeepFailureReason, + uint256 gasUsed, + uint256 gasLimit, + uint256 fastGasWei, + uint256 linkNative + ); + function checkUpkeep( + uint256 id + ) + external + view + returns ( + bool upkeepNeeded, + bytes memory performData, + uint8 upkeepFailureReason, + uint256 gasUsed, + uint256 gasLimit, + uint256 fastGasWei, + uint256 linkNative + ); + function executeCallback( + uint256 id, + bytes memory payload + ) external returns (bool upkeepNeeded, bytes memory performData, uint8 upkeepFailureReason, uint256 gasUsed); + function migrateUpkeeps(uint256[] memory ids, address destination) external; + function receiveUpkeeps(bytes memory encodedUpkeeps) external; + function registerUpkeep( + address target, + uint32 gasLimit, + address admin, + uint8 triggerType, + bytes memory checkData, + bytes memory triggerConfig, + bytes memory offchainConfig + ) external returns (uint256 id); + function registerUpkeep( + address target, + uint32 gasLimit, + address admin, + bytes memory checkData, + bytes memory offchainConfig + ) external returns (uint256 id); + function setUpkeepTriggerConfig(uint256 id, bytes memory triggerConfig) external; + + function acceptPayeeship(address transmitter) external; + function acceptUpkeepAdmin(uint256 id) external; + function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory); + function getAdminPrivilegeConfig(address admin) external view returns (bytes memory); + function getAutomationForwarderLogic() external view returns (address); + function getBalance(uint256 id) external view returns (uint96 balance); + function getCancellationDelay() external pure returns (uint256); + function getConditionalGasOverhead() external pure returns (uint256); + function getFastGasFeedAddress() external view returns (address); + function getForwarder(uint256 upkeepID) external view returns (address); + function getLinkAddress() external view returns (address); + function getLinkNativeFeedAddress() external view returns (address); + function getLogGasOverhead() external pure returns (uint256); + function getMaxPaymentForGas(uint8 triggerType, uint32 gasLimit) external view returns (uint96 maxPayment); + function getMinBalance(uint256 id) external view returns (uint96); + function getMinBalanceForUpkeep(uint256 id) external view returns (uint96 minBalance); + function getMode() external view returns (uint8); + function getPeerRegistryMigrationPermission(address peer) external view returns (uint8); + function getPerPerformByteGasOverhead() external pure returns (uint256); + function getPerSignerGasOverhead() external pure returns (uint256); + function getSignerInfo(address query) external view returns (bool active, uint8 index); + function getState() + external + view + returns ( + AutomationRegistryBase2_2.State memory state, + AutomationRegistryBase2_2.OnchainConfig memory config, + address[] memory signers, + address[] memory transmitters, + uint8 f + ); + function getTransmitterInfo( + address query + ) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee); + function getTriggerType(uint256 upkeepId) external pure returns (uint8); + function getUpkeep(uint256 id) external view returns (AutomationRegistryBase2_2.UpkeepInfo memory upkeepInfo); + function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory); + function getUpkeepTriggerConfig(uint256 upkeepId) external view returns (bytes memory); + function hasDedupKey(bytes32 dedupKey) external view returns (bool); + function pause() external; + function pauseUpkeep(uint256 id) external; + function recoverFunds() external; + function setAdminPrivilegeConfig(address admin, bytes memory newPrivilegeConfig) external; + function setPayees(address[] memory payees) external; + function setPeerRegistryMigrationPermission(address peer, uint8 permission) external; + function setUpkeepCheckData(uint256 id, bytes memory newCheckData) external; + function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external; + function setUpkeepOffchainConfig(uint256 id, bytes memory config) external; + function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes memory newPrivilegeConfig) external; + function transferPayeeship(address transmitter, address proposed) external; + function transferUpkeepAdmin(uint256 id, address proposed) external; + function unpause() external; + function unpauseUpkeep(uint256 id) external; + function upkeepTranscoderVersion() external pure returns (uint8); + function upkeepVersion() external pure returns (uint8); + function withdrawFunds(uint256 id, address to) external; + function withdrawOwnerFunds() external; + function withdrawPayment(address from, address to) external; +} + +interface AutomationRegistryBase2_2 { + struct OnchainConfig { + uint32 paymentPremiumPPB; + uint32 flatFeeMicroLink; + uint32 checkGasLimit; + uint24 stalenessSeconds; + uint16 gasCeilingMultiplier; + uint96 minUpkeepSpend; + uint32 maxPerformGas; + uint32 maxCheckDataSize; + uint32 maxPerformDataSize; + uint32 maxRevertDataSize; + uint256 fallbackGasPrice; + uint256 fallbackLinkPrice; + address transcoder; + address[] registrars; + address upkeepPrivilegeManager; + bool reorgProtectionEnabled; + } + + struct State { + uint32 nonce; + uint96 ownerLinkBalance; + uint256 expectedLinkBalance; + uint96 totalPremium; + uint256 numUpkeeps; + uint32 configCount; + uint32 latestConfigBlockNumber; + bytes32 latestConfigDigest; + uint32 latestEpoch; + bool paused; + } + + struct UpkeepInfo { + address target; + uint32 performGas; + bytes checkData; + uint96 balance; + address admin; + uint64 maxValidBlocknumber; + uint32 lastPerformedBlockNumber; + uint96 amountSpent; + bool paused; + bytes offchainConfig; + } +} + +// THIS FILE WAS AUTOGENERATED FROM THE FOLLOWING ABI JSON: +/* +[{"inputs":[{"internalType":"contract AutomationRegistryLogicB2_2","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":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidDataLength","type":"error"},{"inputs":[],"name":"InvalidPayee","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidReport","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidTransmitter","type":"error"},{"inputs":[],"name":"InvalidTrigger","type":"error"},{"inputs":[],"name":"InvalidTriggerType","type":"error"},{"inputs":[],"name":"MaxCheckDataSizeCanOnlyIncrease","type":"error"},{"inputs":[],"name":"MaxPerformDataSizeCanOnlyIncrease","type":"error"},{"inputs":[],"name":"MigrationNotPermitted","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":"OnlyPausedUpkeep","type":"error"},{"inputs":[],"name":"OnlySimulatedBackend","type":"error"},{"inputs":[],"name":"OnlyUnpausedUpkeep","type":"error"},{"inputs":[],"name":"ParameterLengthError","type":"error"},{"inputs":[],"name":"PaymentGreaterThanAllLINK","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":"UpkeepAlreadyExists","type":"error"},{"inputs":[],"name":"UpkeepCancelled","type":"error"},{"inputs":[],"name":"UpkeepNotCanceled","type":"error"},{"inputs":[],"name":"UpkeepNotNeeded","type":"error"},{"inputs":[],"name":"ValueNotChanged","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"},{"indexed":false,"internalType":"bytes","name":"trigger","type":"bytes"}],"name":"CancelledUpkeepReport","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":"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":"uint96","name":"amount","type":"uint96"}],"name":"OwnerFundsWithdrawn","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":"nonpayable","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":"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":"bool","name":"reorgProtectionEnabled","type":"bool"}],"internalType":"struct AutomationRegistryBase2_2.OnchainConfig","name":"onchainConfig","type":"tuple"},{"internalType":"uint64","name":"offchainConfigVersion","type":"uint64"},{"internalType":"bytes","name":"offchainConfig","type":"bytes"}],"name":"setConfigTypeSafe","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":"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_2","name":"logicB","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint96","name":"amount","type":"uint96"}],"name":"addFunds","outputs":[],"stateMutability":"nonpayable","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":"enum AutomationRegistryBase2_2.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_2.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":"linkNative","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_2.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":"linkNative","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_2.UpkeepFailureReason","name":"upkeepFailureReason","type":"uint8"},{"internalType":"uint256","name":"gasUsed","type":"uint256"}],"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_2.Trigger","name":"triggerType","type":"uint8"},{"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":"target","type":"address"},{"internalType":"uint32","name":"gasLimit","type":"uint32"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"bytes","name":"checkData","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"},{"internalType":"bytes","name":"triggerConfig","type":"bytes"}],"name":"setUpkeepTriggerConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum AutomationRegistryBase2_2.Mode","name":"mode","type":"uint8"},{"internalType":"address","name":"link","type":"address"},{"internalType":"address","name":"linkNativeFeed","type":"address"},{"internalType":"address","name":"fastGasFeed","type":"address"},{"internalType":"address","name":"automationForwarderLogic","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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":"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":"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":[],"name":"getCancellationDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getConditionalGasOverhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","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":"getLinkAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLinkNativeFeedAddress","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":"enum AutomationRegistryBase2_2.Trigger","name":"triggerType","type":"uint8"},{"internalType":"uint32","name":"gasLimit","type":"uint32"}],"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":"getMode","outputs":[{"internalType":"enum AutomationRegistryBase2_2.Mode","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"peer","type":"address"}],"name":"getPeerRegistryMigrationPermission","outputs":[{"internalType":"enum AutomationRegistryBase2_2.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":[{"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 AutomationRegistryBase2_2.State","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":"bool","name":"reorgProtectionEnabled","type":"bool"}],"internalType":"struct AutomationRegistryBase2_2.OnchainConfig","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":[{"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_2.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 AutomationRegistryBase2_2.UpkeepInfo","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":[{"internalType":"bytes32","name":"dedupKey","type":"bytes32"}],"name":"hasDedupKey","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[],"name":"recoverFunds","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_2.MigrationPermission","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":"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":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unpauseUpkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upkeepTranscoderVersion","outputs":[{"internalType":"enum UpkeepFormat","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"upkeepVersion","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawOwnerFunds","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"}] +*/ diff --git a/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_2.t.sol b/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_2.t.sol new file mode 100644 index 00000000000..e6087ce6acd --- /dev/null +++ b/contracts/src/v0.8/automation/dev/test/AutomationRegistry2_2.t.sol @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.16; + +import {AutomationForwarderLogic} from "../../AutomationForwarderLogic.sol"; +import {BaseTest} from "./BaseTest.t.sol"; +import {AutomationRegistry2_2} from "../v2_2/AutomationRegistry2_2.sol"; +import {AutomationRegistryBase2_2} from "../v2_2/AutomationRegistryBase2_2.sol"; +import {AutomationRegistryLogicA2_2} from "../v2_2/AutomationRegistryLogicA2_2.sol"; +import {AutomationRegistryLogicB2_2} from "../v2_2/AutomationRegistryLogicB2_2.sol"; +import {IAutomationRegistryMaster} from "../interfaces/v2_2/IAutomationRegistryMaster.sol"; + +contract AutomationRegistry2_2_SetUp is BaseTest { + address internal constant LINK_ETH_FEED = 0x1111111111111111111111111111111111111110; + address internal constant FAST_GAS_FEED = 0x1111111111111111111111111111111111111112; + address internal constant LINK_TOKEN = 0x1111111111111111111111111111111111111113; + + // Signer private keys used for these test + uint256 internal constant PRIVATE0 = 0x7b2e97fe057e6de99d6872a2ef2abf52c9b4469bc848c2465ac3fcd8d336e81d; + uint256 internal constant PRIVATE1 = 0xab56160806b05ef1796789248e1d7f34a6465c5280899159d645218cd216cee6; + uint256 internal constant PRIVATE2 = 0x6ec7caa8406a49b76736602810e0a2871959fbbb675e23a8590839e4717f1f7f; + uint256 internal constant PRIVATE3 = 0x80f14b11da94ae7f29d9a7713ea13dc838e31960a5c0f2baf45ed458947b730a; + + uint64 internal constant OFFCHAIN_CONFIG_VERSION = 30; // 2 for OCR2 + uint8 internal constant F = 1; + + address[] internal s_valid_signers; + address[] internal s_valid_transmitters; + address[] internal s_registrars; + + function setUp() public override { + s_valid_transmitters = new address[](4); + for (uint160 i = 0; i < 4; ++i) { + s_valid_transmitters[i] = address(4 + i); + } + + s_valid_signers = new address[](4); + s_valid_signers[0] = vm.addr(PRIVATE0); //0xc110458BE52CaA6bB68E66969C3218A4D9Db0211 + s_valid_signers[1] = vm.addr(PRIVATE1); //0xc110a19c08f1da7F5FfB281dc93630923F8E3719 + s_valid_signers[2] = vm.addr(PRIVATE2); //0xc110fdF6e8fD679C7Cc11602d1cd829211A18e9b + s_valid_signers[3] = vm.addr(PRIVATE3); //0xc11028017c9b445B6bF8aE7da951B5cC28B326C0 + + s_registrars = new address[](1); + s_registrars[0] = 0x3a0eDE26aa188BFE00b9A0C9A431A1a0CA5f7966; + } + + function deployRegistry2_2(AutomationRegistryBase2_2.Mode mode) public returns (IAutomationRegistryMaster) { + AutomationForwarderLogic forwarderLogic = new AutomationForwarderLogic(); + AutomationRegistryLogicB2_2 logicB2_2 = new AutomationRegistryLogicB2_2( + mode, + LINK_TOKEN, + LINK_ETH_FEED, + FAST_GAS_FEED, + address(forwarderLogic) + ); + AutomationRegistryLogicA2_2 logicA2_2 = new AutomationRegistryLogicA2_2(logicB2_2); + IAutomationRegistryMaster registry2_2 = IAutomationRegistryMaster( + address(new AutomationRegistry2_2(AutomationRegistryLogicB2_2(address(logicA2_2)))) + ); + return registry2_2; + } +} + +contract AutomationRegistry2_2_LatestConfigDetails is AutomationRegistry2_2_SetUp { + function testGet() public { + IAutomationRegistryMaster registry = IAutomationRegistryMaster( + address(deployRegistry2_2(AutomationRegistryBase2_2.Mode(0))) + ); + (uint32 configCount, uint32 blockNumber, bytes32 configDigest) = registry.latestConfigDetails(); + assertEq(configCount, 0); + assertEq(blockNumber, 0); + assertEq(configDigest, ""); + } +} + +contract AutomationRegistry2_2_SetConfig is AutomationRegistry2_2_SetUp { + event ConfigSet( + uint32 previousConfigBlockNumber, + bytes32 configDigest, + uint64 configCount, + address[] signers, + address[] transmitters, + uint8 f, + bytes onchainConfig, + uint64 offchainConfigVersion, + bytes offchainConfig + ); + + function testSetConfigSuccess() public { + IAutomationRegistryMaster registry = IAutomationRegistryMaster( + address(deployRegistry2_2(AutomationRegistryBase2_2.Mode(0))) + ); + (uint32 configCount, , ) = registry.latestConfigDetails(); + assertEq(configCount, 0); + + AutomationRegistryBase2_2.OnchainConfig memory cfg = AutomationRegistryBase2_2.OnchainConfig({ + paymentPremiumPPB: 10_000, + flatFeeMicroLink: 40_000, + checkGasLimit: 5_000_000, + stalenessSeconds: 90_000, + gasCeilingMultiplier: 0, + minUpkeepSpend: 0, + maxPerformGas: 10_000_000, + maxCheckDataSize: 5_000, + maxPerformDataSize: 5_000, + maxRevertDataSize: 5_000, + fallbackGasPrice: 20_000_000_000, + fallbackLinkPrice: 200_000_000_000, + transcoder: 0xB1e66855FD67f6e85F0f0fA38cd6fBABdf00923c, + registrars: s_registrars, + upkeepPrivilegeManager: 0xD9c855F08A7e460691F41bBDDe6eC310bc0593D8, + reorgProtectionEnabled: true + }); + bytes memory onchainConfigBytes = abi.encode(cfg); + + uint256 a = 1234; + address b = address(0); + bytes memory offchainConfigBytes = abi.encode(a, b); + bytes32 configDigest = _configDigestFromConfigData( + block.chainid, + address(registry), + ++configCount, + s_valid_signers, + s_valid_transmitters, + F, + onchainConfigBytes, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes + ); + + vm.expectEmit(); + emit ConfigSet( + 0, + configDigest, + configCount, + s_valid_signers, + s_valid_transmitters, + F, + onchainConfigBytes, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes + ); + + registry.setConfig( + s_valid_signers, + s_valid_transmitters, + F, + onchainConfigBytes, + OFFCHAIN_CONFIG_VERSION, + offchainConfigBytes + ); + + (, , address[] memory signers, address[] memory transmitters, uint8 f) = registry.getState(); + + assertEq(signers, s_valid_signers); + assertEq(transmitters, s_valid_transmitters); + assertEq(f, F); + } + + function _configDigestFromConfigData( + uint256 chainId, + address contractAddress, + uint64 configCount, + address[] memory signers, + address[] memory transmitters, + uint8 f, + bytes memory onchainConfig, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) internal pure returns (bytes32) { + uint256 h = uint256( + keccak256( + abi.encode( + chainId, + contractAddress, + configCount, + signers, + transmitters, + f, + onchainConfig, + offchainConfigVersion, + offchainConfig + ) + ) + ); + uint256 prefixMask = type(uint256).max << (256 - 16); // 0xFFFF00..00 + uint256 prefix = 0x0001 << (256 - 16); // 0x000100..00 + return bytes32((prefix & prefixMask) | (h & ~prefixMask)); + } +} diff --git a/contracts/src/v0.8/automation/v2_1/test/BaseTest.t.sol b/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol similarity index 52% rename from contracts/src/v0.8/automation/v2_1/test/BaseTest.t.sol rename to contracts/src/v0.8/automation/dev/test/BaseTest.t.sol index f5bc74286a4..3d28c4c35b2 100644 --- a/contracts/src/v0.8/automation/v2_1/test/BaseTest.t.sol +++ b/contracts/src/v0.8/automation/dev/test/BaseTest.t.sol @@ -1,10 +1,11 @@ -// SPDX-License-Identifier: BUSL-1.1 +// SPDX-License-Identifier: MIT pragma solidity 0.8.16; -import {StructFactory} from "./StructFactory.sol"; import "forge-std/Test.sol"; -contract BaseTest is Test, StructFactory { +contract BaseTest is Test { + address internal OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e; + function setUp() public virtual { vm.startPrank(OWNER); deal(OWNER, 1e20); diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistrar2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistrar2_2.sol new file mode 100644 index 00000000000..1fa1feeb578 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistrar2_2.sol @@ -0,0 +1,535 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.16; + +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {IAutomationRegistryMaster} from "../interfaces/v2_2/IAutomationRegistryMaster.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; +import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; + +/** + * @notice Contract to accept requests for upkeep registrations + * @dev There are 2 registration workflows in this contract + * Flow 1. auto approve OFF / manual registration - UI calls `register` function on this contract, this contract owner at a later time then manually + * calls `approve` to register upkeep and emit events to inform UI and others interested. + * Flow 2. auto approve ON / real time registration - UI calls `register` function as before, which calls the `registerUpkeep` function directly on + * keeper registry and then emits approved event to finish the flow automatically without manual intervention. + * The idea is to have same interface(functions,events) for UI or anyone using this contract irrespective of auto approve being enabled or not. + * they can just listen to `RegistrationRequested` & `RegistrationApproved` events and know the status on registrations. + */ +contract AutomationRegistrar2_2 is TypeAndVersionInterface, ConfirmedOwner, IERC677Receiver { + /** + * DISABLED: No auto approvals, all new upkeeps should be approved manually. + * ENABLED_SENDER_ALLOWLIST: Auto approvals for allowed senders subject to max allowed. Manual for rest. + * ENABLED_ALL: Auto approvals for all new upkeeps subject to max allowed. + */ + enum AutoApproveType { + DISABLED, + ENABLED_SENDER_ALLOWLIST, + ENABLED_ALL + } + + bytes4 private constant REGISTER_REQUEST_SELECTOR = this.register.selector; + + mapping(bytes32 => PendingRequest) private s_pendingRequests; + mapping(uint8 => TriggerRegistrationStorage) private s_triggerRegistrations; + + LinkTokenInterface public immutable LINK; + + /** + * @notice versions: + * - KeeperRegistrar 2.1.0: Update for compatability with registry 2.1.0 + * Add auto approval levels by type + * - KeeperRegistrar 2.0.0: Remove source from register + * Breaks our example of "Register an Upkeep using your own deployed contract" + * - KeeperRegistrar 1.1.0: Add functionality for sender allowlist in auto approve + * : Remove rate limit and add max allowed for auto approve + * - KeeperRegistrar 1.0.0: initial release + */ + string public constant override typeAndVersion = "AutomationRegistrar 2.1.0"; + + /** + * @notice TriggerRegistrationStorage stores the auto-approval levels for upkeeps by type + * @member autoApproveType the auto approval setting (see enum) + * @member autoApproveMaxAllowed the max number of upkeeps that can be auto approved of this type + * @member approvedCount the count of upkeeps auto approved of this type + */ + struct TriggerRegistrationStorage { + AutoApproveType autoApproveType; + uint32 autoApproveMaxAllowed; + uint32 approvedCount; + } + + /** + * @notice InitialTriggerConfig configures the auto-approval levels for upkeeps by trigger type + * @dev this struct is only used in the constructor to set the initial values for various trigger configs + * @member triggerType the upkeep type to configure + * @member autoApproveType the auto approval setting (see enum) + * @member autoApproveMaxAllowed the max number of upkeeps that can be auto approved of this type + */ + struct InitialTriggerConfig { + uint8 triggerType; + AutoApproveType autoApproveType; + uint32 autoApproveMaxAllowed; + } + + struct RegistrarConfig { + IAutomationRegistryMaster AutomationRegistry; + uint96 minLINKJuels; + } + + struct PendingRequest { + address admin; + uint96 balance; + } + + struct RegistrationParams { + string name; + bytes encryptedEmail; + address upkeepContract; + uint32 gasLimit; + address adminAddress; + uint8 triggerType; + bytes checkData; + bytes triggerConfig; + bytes offchainConfig; + uint96 amount; + } + + RegistrarConfig private s_config; + // Only applicable if s_config.configType is ENABLED_SENDER_ALLOWLIST + mapping(address => bool) private s_autoApproveAllowedSenders; + + event RegistrationRequested( + bytes32 indexed hash, + string name, + bytes encryptedEmail, + address indexed upkeepContract, + uint32 gasLimit, + address adminAddress, + uint8 triggerType, + bytes triggerConfig, + bytes offchainConfig, + bytes checkData, + uint96 amount + ); + + event RegistrationApproved(bytes32 indexed hash, string displayName, uint256 indexed upkeepId); + + event RegistrationRejected(bytes32 indexed hash); + + event AutoApproveAllowedSenderSet(address indexed senderAddress, bool allowed); + + event ConfigChanged(address AutomationRegistry, uint96 minLINKJuels); + + event TriggerConfigSet(uint8 triggerType, AutoApproveType autoApproveType, uint32 autoApproveMaxAllowed); + + error InvalidAdminAddress(); + error RequestNotFound(); + error HashMismatch(); + error OnlyAdminOrOwner(); + error InsufficientPayment(); + error RegistrationRequestFailed(); + error OnlyLink(); + error AmountMismatch(); + error SenderMismatch(); + error FunctionNotPermitted(); + error LinkTransferFailed(address to); + error InvalidDataLength(); + + /** + * @param LINKAddress Address of Link token + * @param AutomationRegistry keeper registry address + * @param minLINKJuels minimum LINK that new registrations should fund their upkeep with + * @param triggerConfigs the initial config for individual triggers + */ + constructor( + address LINKAddress, + address AutomationRegistry, + uint96 minLINKJuels, + InitialTriggerConfig[] memory triggerConfigs + ) ConfirmedOwner(msg.sender) { + LINK = LinkTokenInterface(LINKAddress); + setConfig(AutomationRegistry, minLINKJuels); + for (uint256 idx = 0; idx < triggerConfigs.length; idx++) { + setTriggerConfig( + triggerConfigs[idx].triggerType, + triggerConfigs[idx].autoApproveType, + triggerConfigs[idx].autoApproveMaxAllowed + ); + } + } + + //EXTERNAL + + /** + * @notice register can only be called through transferAndCall on LINK contract + * @param name string of the upkeep to be registered + * @param encryptedEmail email address of upkeep contact + * @param upkeepContract address to perform upkeep on + * @param gasLimit amount of gas to provide the target contract when performing upkeep + * @param adminAddress address to cancel upkeep and withdraw remaining funds + * @param triggerType the type of trigger for the upkeep + * @param checkData data passed to the contract when checking for upkeep + * @param triggerConfig the config for the trigger + * @param offchainConfig offchainConfig for upkeep in bytes + * @param amount quantity of LINK upkeep is funded with (specified in Juels) + * @param sender address of the sender making the request + */ + function register( + string memory name, + bytes calldata encryptedEmail, + address upkeepContract, + uint32 gasLimit, + address adminAddress, + uint8 triggerType, + bytes memory checkData, + bytes memory triggerConfig, + bytes memory offchainConfig, + uint96 amount, + address sender + ) external onlyLINK { + _register( + RegistrationParams({ + name: name, + encryptedEmail: encryptedEmail, + upkeepContract: upkeepContract, + gasLimit: gasLimit, + adminAddress: adminAddress, + triggerType: triggerType, + checkData: checkData, + triggerConfig: triggerConfig, + offchainConfig: offchainConfig, + amount: amount + }), + sender + ); + } + + /** + * @notice Allows external users to register upkeeps; assumes amount is approved for transfer by the contract + * @param requestParams struct of all possible registration parameters + */ + function registerUpkeep(RegistrationParams calldata requestParams) external returns (uint256) { + if (requestParams.amount < s_config.minLINKJuels) { + revert InsufficientPayment(); + } + + LINK.transferFrom(msg.sender, address(this), requestParams.amount); + + return _register(requestParams, msg.sender); + } + + /** + * @dev register upkeep on AutomationRegistry contract and emit RegistrationApproved event + */ + function approve( + string memory name, + address upkeepContract, + uint32 gasLimit, + address adminAddress, + uint8 triggerType, + bytes calldata checkData, + bytes memory triggerConfig, + bytes calldata offchainConfig, + bytes32 hash + ) external onlyOwner { + PendingRequest memory request = s_pendingRequests[hash]; + if (request.admin == address(0)) { + revert RequestNotFound(); + } + bytes32 expectedHash = keccak256( + abi.encode(upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig) + ); + if (hash != expectedHash) { + revert HashMismatch(); + } + delete s_pendingRequests[hash]; + _approve( + RegistrationParams({ + name: name, + encryptedEmail: "", + upkeepContract: upkeepContract, + gasLimit: gasLimit, + adminAddress: adminAddress, + triggerType: triggerType, + checkData: checkData, + triggerConfig: triggerConfig, + offchainConfig: offchainConfig, + amount: request.balance + }), + expectedHash + ); + } + + /** + * @notice cancel will remove a registration request and return the refunds to the request.admin + * @param hash the request hash + */ + function cancel(bytes32 hash) external { + PendingRequest memory request = s_pendingRequests[hash]; + if (!(msg.sender == request.admin || msg.sender == owner())) { + revert OnlyAdminOrOwner(); + } + if (request.admin == address(0)) { + revert RequestNotFound(); + } + delete s_pendingRequests[hash]; + bool success = LINK.transfer(request.admin, request.balance); + if (!success) { + revert LinkTransferFailed(request.admin); + } + emit RegistrationRejected(hash); + } + + /** + * @notice owner calls this function to set contract config + * @param AutomationRegistry new keeper registry address + * @param minLINKJuels minimum LINK that new registrations should fund their upkeep with + */ + function setConfig(address AutomationRegistry, uint96 minLINKJuels) public onlyOwner { + s_config = RegistrarConfig({ + minLINKJuels: minLINKJuels, + AutomationRegistry: IAutomationRegistryMaster(AutomationRegistry) + }); + emit ConfigChanged(AutomationRegistry, minLINKJuels); + } + + /** + * @notice owner calls to set the config for this upkeep type + * @param triggerType the upkeep type to configure + * @param autoApproveType the auto approval setting (see enum) + * @param autoApproveMaxAllowed the max number of upkeeps that can be auto approved of this type + */ + function setTriggerConfig( + uint8 triggerType, + AutoApproveType autoApproveType, + uint32 autoApproveMaxAllowed + ) public onlyOwner { + s_triggerRegistrations[triggerType].autoApproveType = autoApproveType; + s_triggerRegistrations[triggerType].autoApproveMaxAllowed = autoApproveMaxAllowed; + emit TriggerConfigSet(triggerType, autoApproveType, autoApproveMaxAllowed); + } + + /** + * @notice owner calls this function to set allowlist status for senderAddress + * @param senderAddress senderAddress to set the allowlist status for + * @param allowed true if senderAddress needs to be added to allowlist, false if needs to be removed + */ + function setAutoApproveAllowedSender(address senderAddress, bool allowed) external onlyOwner { + s_autoApproveAllowedSenders[senderAddress] = allowed; + + emit AutoApproveAllowedSenderSet(senderAddress, allowed); + } + + /** + * @notice read the allowlist status of senderAddress + * @param senderAddress address to read the allowlist status for + */ + function getAutoApproveAllowedSender(address senderAddress) external view returns (bool) { + return s_autoApproveAllowedSenders[senderAddress]; + } + + /** + * @notice read the current registration configuration + */ + function getConfig() external view returns (address AutomationRegistry, uint256 minLINKJuels) { + RegistrarConfig memory config = s_config; + return (address(config.AutomationRegistry), config.minLINKJuels); + } + + /** + * @notice read the config for this upkeep type + * @param triggerType upkeep type to read config for + */ + function getTriggerRegistrationDetails(uint8 triggerType) external view returns (TriggerRegistrationStorage memory) { + return s_triggerRegistrations[triggerType]; + } + + /** + * @notice gets the admin address and the current balance of a registration request + */ + function getPendingRequest(bytes32 hash) external view returns (address, uint96) { + PendingRequest memory request = s_pendingRequests[hash]; + return (request.admin, request.balance); + } + + /** + * @notice Called when LINK is sent to the contract via `transferAndCall` + * @param sender Address of the sender transfering LINK + * @param amount Amount of LINK sent (specified in Juels) + * @param data Payload of the transaction + */ + function onTokenTransfer( + address sender, + uint256 amount, + bytes calldata data + ) + external + override + onlyLINK + permittedFunctionsForLINK(data) + isActualAmount(amount, data) + isActualSender(sender, data) + { + if (amount < s_config.minLINKJuels) { + revert InsufficientPayment(); + } + (bool success, ) = address(this).delegatecall(data); + // calls register + if (!success) { + revert RegistrationRequestFailed(); + } + } + + // ================================================================ + // | PRIVATE | + // ================================================================ + + /** + * @dev verify registration request and emit RegistrationRequested event + */ + function _register(RegistrationParams memory params, address sender) private returns (uint256) { + if (params.adminAddress == address(0)) { + revert InvalidAdminAddress(); + } + bytes32 hash = keccak256( + abi.encode( + params.upkeepContract, + params.gasLimit, + params.adminAddress, + params.triggerType, + params.checkData, + params.triggerConfig, + params.offchainConfig + ) + ); + + emit RegistrationRequested( + hash, + params.name, + params.encryptedEmail, + params.upkeepContract, + params.gasLimit, + params.adminAddress, + params.triggerType, + params.triggerConfig, + params.offchainConfig, + params.checkData, + params.amount + ); + + uint256 upkeepId; + if (_shouldAutoApprove(s_triggerRegistrations[params.triggerType], sender)) { + s_triggerRegistrations[params.triggerType].approvedCount++; + upkeepId = _approve(params, hash); + } else { + uint96 newBalance = s_pendingRequests[hash].balance + params.amount; + s_pendingRequests[hash] = PendingRequest({admin: params.adminAddress, balance: newBalance}); + } + + return upkeepId; + } + + /** + * @dev register upkeep on AutomationRegistry contract and emit RegistrationApproved event + */ + function _approve(RegistrationParams memory params, bytes32 hash) private returns (uint256) { + IAutomationRegistryMaster AutomationRegistry = s_config.AutomationRegistry; + uint256 upkeepId = AutomationRegistry.registerUpkeep( + params.upkeepContract, + params.gasLimit, + params.adminAddress, + params.triggerType, + params.checkData, + params.triggerConfig, + params.offchainConfig + ); + bool success = LINK.transferAndCall(address(AutomationRegistry), params.amount, abi.encode(upkeepId)); + if (!success) { + revert LinkTransferFailed(address(AutomationRegistry)); + } + emit RegistrationApproved(hash, params.name, upkeepId); + return upkeepId; + } + + /** + * @dev verify sender allowlist if needed and check max limit + */ + function _shouldAutoApprove(TriggerRegistrationStorage memory config, address sender) private view returns (bool) { + if (config.autoApproveType == AutoApproveType.DISABLED) { + return false; + } + if (config.autoApproveType == AutoApproveType.ENABLED_SENDER_ALLOWLIST && (!s_autoApproveAllowedSenders[sender])) { + return false; + } + if (config.approvedCount < config.autoApproveMaxAllowed) { + return true; + } + return false; + } + + // ================================================================ + // | MODIFIERS | + // ================================================================ + + /** + * @dev Reverts if not sent from the LINK token + */ + modifier onlyLINK() { + if (msg.sender != address(LINK)) { + revert OnlyLink(); + } + _; + } + + /** + * @dev Reverts if the given data does not begin with the `register` function selector + * @param _data The data payload of the request + */ + modifier permittedFunctionsForLINK(bytes memory _data) { + bytes4 funcSelector; + assembly { + // solhint-disable-next-line avoid-low-level-calls + funcSelector := mload(add(_data, 32)) // First 32 bytes contain length of data + } + if (funcSelector != REGISTER_REQUEST_SELECTOR) { + revert FunctionNotPermitted(); + } + _; + } + + /** + * @dev Reverts if the actual amount passed does not match the expected amount + * @param expected amount that should match the actual amount + * @param data bytes + */ + modifier isActualAmount(uint256 expected, bytes calldata data) { + // decode register function arguments to get actual amount + (, , , , , , , , , uint96 amount, ) = abi.decode( + data[4:], + (string, bytes, address, uint32, address, uint8, bytes, bytes, bytes, uint96, address) + ); + if (expected != amount) { + revert AmountMismatch(); + } + _; + } + + /** + * @dev Reverts if the actual sender address does not match the expected sender address + * @param expected address that should match the actual sender address + * @param data bytes + */ + modifier isActualSender(address expected, bytes calldata data) { + // decode register function arguments to get actual sender + (, , , , , , , , , , address sender) = abi.decode( + data[4:], + (string, bytes, address, uint32, address, uint8, bytes, bytes, bytes, uint96, address) + ); + if (expected != sender) { + revert SenderMismatch(); + } + _; + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistry2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistry2_2.sol new file mode 100644 index 00000000000..e3b429518cf --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistry2_2.sol @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.16; + +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {AutomationRegistryBase2_2} from "./AutomationRegistryBase2_2.sol"; +import {AutomationRegistryLogicB2_2} from "./AutomationRegistryLogicB2_2.sol"; +import {Chainable} from "../../Chainable.sol"; +import {IERC677Receiver} from "../../../shared/interfaces/IERC677Receiver.sol"; +import {OCR2Abstract} from "../../../shared/ocr2/OCR2Abstract.sol"; + +/** + * @notice Registry for adding work for Chainlink nodes to perform on client + * contracts. Clients must support the AutomationCompatibleInterface interface. + */ +contract AutomationRegistry2_2 is AutomationRegistryBase2_2, OCR2Abstract, Chainable, IERC677Receiver { + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableSet for EnumerableSet.AddressSet; + + /** + * @notice versions: + * AutomationRegistry 2.2.0: moves chain-spicific integration code into a separate module + * KeeperRegistry 2.1.0: introduces support for log triggers + * removes the need for "wrapped perform data" + * KeeperRegistry 2.0.2: pass revert bytes as performData when target contract reverts + * fixes issue with arbitrum block number + * does an early return in case of stale report instead of revert + * KeeperRegistry 2.0.1: implements workaround for buggy migrate function in 1.X + * KeeperRegistry 2.0.0: implement OCR interface + * KeeperRegistry 1.3.0: split contract into Proxy and Logic + * account for Arbitrum and Optimism L1 gas fee + * allow users to configure upkeeps + * KeeperRegistry 1.2.0: allow funding within performUpkeep + * allow configurable registry maxPerformGas + * add function to let admin change upkeep gas limit + * add minUpkeepSpend requirement + * upgrade to solidity v0.8 + * KeeperRegistry 1.1.0: added flatFeeMicroLink + * KeeperRegistry 1.0.0: initial release + */ + string public constant override typeAndVersion = "AutomationRegistry 2.2.0"; + + /** + * @param logicA the address of the first logic contract, but cast as logicB in order to call logicB functions + */ + constructor( + AutomationRegistryLogicB2_2 logicA + ) + AutomationRegistryBase2_2( + logicA.getMode(), + logicA.getLinkAddress(), + logicA.getLinkNativeFeedAddress(), + logicA.getFastGasFeedAddress(), + logicA.getAutomationForwarderLogic() + ) + Chainable(address(logicA)) + {} + + // ================================================================ + // | ACTIONS | + // ================================================================ + + /** + * @inheritdoc OCR2Abstract + */ + function transmit( + bytes32[3] calldata reportContext, + bytes calldata rawReport, + bytes32[] calldata rs, + bytes32[] calldata ss, + bytes32 rawVs + ) external override { + uint256 gasOverhead = gasleft(); + HotVars memory hotVars = s_hotVars; + + if (hotVars.paused) revert RegistryPaused(); + if (!s_transmitters[msg.sender].active) revert OnlyActiveTransmitters(); + + // Verify signatures + if (s_latestConfigDigest != reportContext[0]) revert ConfigDigestMismatch(); + if (rs.length != hotVars.f + 1 || rs.length != ss.length) revert IncorrectNumberOfSignatures(); + _verifyReportSignature(reportContext, rawReport, rs, ss, rawVs); + + Report memory report = _decodeReport(rawReport); + UpkeepTransmitInfo[] memory upkeepTransmitInfo = new UpkeepTransmitInfo[](report.upkeepIds.length); + uint16 numUpkeepsPassedChecks; + + for (uint256 i = 0; i < report.upkeepIds.length; i++) { + upkeepTransmitInfo[i].upkeep = s_upkeep[report.upkeepIds[i]]; + upkeepTransmitInfo[i].triggerType = _getTriggerType(report.upkeepIds[i]); + upkeepTransmitInfo[i].maxLinkPayment = _getMaxLinkPayment( + hotVars, + upkeepTransmitInfo[i].triggerType, + uint32(report.gasLimits[i]), + uint32(report.performDatas[i].length), + report.fastGasWei, + report.linkNative, + true + ); + (upkeepTransmitInfo[i].earlyChecksPassed, upkeepTransmitInfo[i].dedupID) = _prePerformChecks( + report.upkeepIds[i], + report.triggers[i], + upkeepTransmitInfo[i], + hotVars + ); + + if (upkeepTransmitInfo[i].earlyChecksPassed) { + numUpkeepsPassedChecks += 1; + } else { + continue; + } + + // Actually perform the target upkeep + (upkeepTransmitInfo[i].performSuccess, upkeepTransmitInfo[i].gasUsed) = _performUpkeep( + upkeepTransmitInfo[i].upkeep.forwarder, + report.gasLimits[i], + report.performDatas[i] + ); + + // Deduct that gasUsed by upkeep from our running counter + gasOverhead -= upkeepTransmitInfo[i].gasUsed; + + // Store last perform block number / deduping key for upkeep + _updateTriggerMarker(report.upkeepIds[i], upkeepTransmitInfo[i]); + } + // No upkeeps to be performed in this report + if (numUpkeepsPassedChecks == 0) { + return; + } + + // This is the overall gas overhead that will be split across performed upkeeps + // Take upper bound of 16 gas per callData bytes, which is approximated to be reportLength + // Rest of msg.data is accounted for in accounting overheads + gasOverhead = + (gasOverhead - gasleft() + 16 * rawReport.length) + + ACCOUNTING_FIXED_GAS_OVERHEAD + + (ACCOUNTING_PER_SIGNER_GAS_OVERHEAD * (hotVars.f + 1)); + gasOverhead = gasOverhead / numUpkeepsPassedChecks + ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD; + + uint96 totalReimbursement; + uint96 totalPremium; + { + uint96 reimbursement; + uint96 premium; + for (uint256 i = 0; i < report.upkeepIds.length; i++) { + if (upkeepTransmitInfo[i].earlyChecksPassed) { + upkeepTransmitInfo[i].gasOverhead = _getCappedGasOverhead( + gasOverhead, + upkeepTransmitInfo[i].triggerType, + uint32(report.performDatas[i].length), + hotVars.f + ); + + (reimbursement, premium) = _postPerformPayment( + hotVars, + report.upkeepIds[i], + upkeepTransmitInfo[i], + report.fastGasWei, + report.linkNative, + numUpkeepsPassedChecks + ); + totalPremium += premium; + totalReimbursement += reimbursement; + + emit UpkeepPerformed( + report.upkeepIds[i], + upkeepTransmitInfo[i].performSuccess, + reimbursement + premium, + upkeepTransmitInfo[i].gasUsed, + upkeepTransmitInfo[i].gasOverhead, + report.triggers[i] + ); + } + } + } + // record payments + s_transmitters[msg.sender].balance += totalReimbursement; + s_hotVars.totalPremium += totalPremium; + + uint40 epochAndRound = uint40(uint256(reportContext[1])); + uint32 epoch = uint32(epochAndRound >> 8); + if (epoch > hotVars.latestEpoch) { + s_hotVars.latestEpoch = epoch; + } + } + + /** + * @notice simulates the upkeep with the perform data returned from checkUpkeep + * @param id identifier of the upkeep to execute the data with. + * @param performData calldata parameter to be passed to the target upkeep. + * @return success whether the call reverted or not + * @return gasUsed the amount of gas the target contract consumed + */ + function simulatePerformUpkeep( + uint256 id, + bytes calldata performData + ) external cannotExecute returns (bool success, uint256 gasUsed) { + if (s_hotVars.paused) revert RegistryPaused(); + Upkeep memory upkeep = s_upkeep[id]; + (success, gasUsed) = _performUpkeep(upkeep.forwarder, upkeep.performGas, performData); + return (success, gasUsed); + } + + /** + * @notice uses LINK's transferAndCall to LINK and add funding to an upkeep + * @dev safe to cast uint256 to uint96 as total LINK supply is under UINT96MAX + * @param sender the account which transferred the funds + * @param amount number of LINK transfer + */ + function onTokenTransfer(address sender, uint256 amount, bytes calldata data) external override { + if (msg.sender != address(i_link)) revert OnlyCallableByLINKToken(); + if (data.length != 32) revert InvalidDataLength(); + uint256 id = abi.decode(data, (uint256)); + if (s_upkeep[id].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + s_upkeep[id].balance = s_upkeep[id].balance + uint96(amount); + s_expectedLinkBalance = s_expectedLinkBalance + amount; + emit FundsAdded(id, sender, uint96(amount)); + } + + // ================================================================ + // | SETTERS | + // ================================================================ + + /** + * @inheritdoc OCR2Abstract + * @dev prefer the type-safe version of setConfig (below) whenever possible + */ + function setConfig( + address[] memory signers, + address[] memory transmitters, + uint8 f, + bytes memory onchainConfigBytes, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) external override { + setConfigTypeSafe( + signers, + transmitters, + f, + abi.decode(onchainConfigBytes, (OnchainConfig)), + offchainConfigVersion, + offchainConfig + ); + } + + function setConfigTypeSafe( + address[] memory signers, + address[] memory transmitters, + uint8 f, + OnchainConfig memory onchainConfig, + uint64 offchainConfigVersion, + bytes memory offchainConfig + ) public onlyOwner { + if (signers.length > MAX_NUM_ORACLES) revert TooManyOracles(); + if (f == 0) revert IncorrectNumberOfFaultyOracles(); + if (signers.length != transmitters.length || signers.length <= 3 * f) revert IncorrectNumberOfSigners(); + + // move all pooled payments out of the pool to each transmitter's balance + uint96 totalPremium = s_hotVars.totalPremium; + uint96 oldLength = uint96(s_transmittersList.length); + for (uint256 i = 0; i < oldLength; i++) { + _updateTransmitterBalanceFromPool(s_transmittersList[i], totalPremium, oldLength); + } + + // remove any old signer/transmitter addresses + address signerAddress; + address transmitterAddress; + for (uint256 i = 0; i < oldLength; i++) { + signerAddress = s_signersList[i]; + transmitterAddress = s_transmittersList[i]; + delete s_signers[signerAddress]; + // Do not delete the whole transmitter struct as it has balance information stored + s_transmitters[transmitterAddress].active = false; + } + delete s_signersList; + delete s_transmittersList; + + // add new signer/transmitter addresses + { + Transmitter memory transmitter; + address temp; + for (uint256 i = 0; i < signers.length; i++) { + if (s_signers[signers[i]].active) revert RepeatedSigner(); + if (signers[i] == ZERO_ADDRESS) revert InvalidSigner(); + s_signers[signers[i]] = Signer({active: true, index: uint8(i)}); + + temp = transmitters[i]; + if (temp == ZERO_ADDRESS) revert InvalidTransmitter(); + transmitter = s_transmitters[temp]; + if (transmitter.active) revert RepeatedTransmitter(); + transmitter.active = true; + transmitter.index = uint8(i); + // new transmitters start afresh from current totalPremium + // some spare change of premium from previous pool will be forfeited + transmitter.lastCollected = totalPremium; + s_transmitters[temp] = transmitter; + } + } + s_signersList = signers; + s_transmittersList = transmitters; + + s_hotVars = HotVars({ + f: f, + paymentPremiumPPB: onchainConfig.paymentPremiumPPB, + flatFeeMicroLink: onchainConfig.flatFeeMicroLink, + stalenessSeconds: onchainConfig.stalenessSeconds, + gasCeilingMultiplier: onchainConfig.gasCeilingMultiplier, + paused: s_hotVars.paused, + reentrancyGuard: s_hotVars.reentrancyGuard, + totalPremium: totalPremium, + latestEpoch: 0, // DON restarts epoch + reorgProtectionEnabled: onchainConfig.reorgProtectionEnabled + }); + + s_storage = Storage({ + checkGasLimit: onchainConfig.checkGasLimit, + minUpkeepSpend: onchainConfig.minUpkeepSpend, + maxPerformGas: onchainConfig.maxPerformGas, + transcoder: onchainConfig.transcoder, + maxCheckDataSize: onchainConfig.maxCheckDataSize, + maxPerformDataSize: onchainConfig.maxPerformDataSize, + maxRevertDataSize: onchainConfig.maxRevertDataSize, + upkeepPrivilegeManager: onchainConfig.upkeepPrivilegeManager, + nonce: s_storage.nonce, + configCount: s_storage.configCount, + latestConfigBlockNumber: s_storage.latestConfigBlockNumber, + ownerLinkBalance: s_storage.ownerLinkBalance + }); + s_fallbackGasPrice = onchainConfig.fallbackGasPrice; + s_fallbackLinkPrice = onchainConfig.fallbackLinkPrice; + + uint32 previousConfigBlockNumber = s_storage.latestConfigBlockNumber; + s_storage.latestConfigBlockNumber = uint32(_blockNum()); + s_storage.configCount += 1; + + bytes memory onchainConfigBytes = abi.encode(onchainConfig); + + s_latestConfigDigest = _configDigestFromConfigData( + block.chainid, + address(this), + s_storage.configCount, + signers, + transmitters, + f, + onchainConfigBytes, + offchainConfigVersion, + offchainConfig + ); + + for (uint256 idx = 0; idx < s_registrars.length(); idx++) { + s_registrars.remove(s_registrars.at(idx)); + } + + for (uint256 idx = 0; idx < onchainConfig.registrars.length; idx++) { + s_registrars.add(onchainConfig.registrars[idx]); + } + + emit ConfigSet( + previousConfigBlockNumber, + s_latestConfigDigest, + s_storage.configCount, + signers, + transmitters, + f, + onchainConfigBytes, + offchainConfigVersion, + offchainConfig + ); + } + + // ================================================================ + // | GETTERS | + // ================================================================ + + /** + * @inheritdoc OCR2Abstract + */ + function latestConfigDetails() + external + view + override + returns (uint32 configCount, uint32 blockNumber, bytes32 configDigest) + { + return (s_storage.configCount, s_storage.latestConfigBlockNumber, s_latestConfigDigest); + } + + /** + * @inheritdoc OCR2Abstract + */ + function latestConfigDigestAndEpoch() + external + view + override + returns (bool scanLogs, bytes32 configDigest, uint32 epoch) + { + return (false, s_latestConfigDigest, s_hotVars.latestEpoch); + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryBase2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryBase2_2.sol new file mode 100644 index 00000000000..43fd3eb18e2 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryBase2_2.sol @@ -0,0 +1,965 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.16; + +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {ArbGasInfo} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; +import {OVM_GasPriceOracle} from "../../../vendor/@eth-optimism/contracts/v0.8.9/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; +import {ExecutionPrevention} from "../../ExecutionPrevention.sol"; +import {ArbSys} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbSys.sol"; +import {StreamsLookupCompatibleInterface} from "../../interfaces/StreamsLookupCompatibleInterface.sol"; +import {ILogAutomation, Log} from "../../interfaces/ILogAutomation.sol"; +import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; +import {ConfirmedOwner} from "../../../shared/access/ConfirmedOwner.sol"; +import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; +import {LinkTokenInterface} from "../../../shared/interfaces/LinkTokenInterface.sol"; +import {KeeperCompatibleInterface} from "../../interfaces/KeeperCompatibleInterface.sol"; +import {UpkeepFormat} from "../../interfaces/UpkeepTranscoderInterface.sol"; + +/** + * @notice Base Keeper Registry contract, contains shared logic between + * AutomationRegistry and AutomationRegistryLogic + * @dev all errors, events, and internal functions should live here + */ +abstract contract AutomationRegistryBase2_2 is ConfirmedOwner, ExecutionPrevention { + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableSet for EnumerableSet.AddressSet; + + address internal constant ZERO_ADDRESS = address(0); + address internal constant IGNORE_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF; + bytes4 internal constant CHECK_SELECTOR = KeeperCompatibleInterface.checkUpkeep.selector; + bytes4 internal constant PERFORM_SELECTOR = KeeperCompatibleInterface.performUpkeep.selector; + bytes4 internal constant CHECK_CALLBACK_SELECTOR = StreamsLookupCompatibleInterface.checkCallback.selector; + bytes4 internal constant CHECK_LOG_SELECTOR = ILogAutomation.checkLog.selector; + uint256 internal constant PERFORM_GAS_MIN = 2_300; + uint256 internal constant CANCELLATION_DELAY = 50; + uint256 internal constant PERFORM_GAS_CUSHION = 5_000; + uint256 internal constant PPB_BASE = 1_000_000_000; + uint32 internal constant UINT32_MAX = type(uint32).max; + uint96 internal constant LINK_TOTAL_SUPPLY = 1e27; + // The first byte of the mask can be 0, because we only ever have 31 oracles + uint256 internal constant ORACLE_MASK = 0x0001010101010101010101010101010101010101010101010101010101010101; + /** + * @dev UPKEEP_TRANSCODER_VERSION_BASE is temporary necessity for backwards compatibility with + * MigratableAutomationRegistryInterfaceV1 - it should be removed in future versions in favor of + * UPKEEP_VERSION_BASE and MigratableAutomationRegistryInterfaceV2 + */ + UpkeepFormat internal constant UPKEEP_TRANSCODER_VERSION_BASE = UpkeepFormat.V1; + uint8 internal constant UPKEEP_VERSION_BASE = 3; + // L1_FEE_DATA_PADDING includes 35 bytes for L1 data padding for Optimism + bytes internal constant L1_FEE_DATA_PADDING = + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + + uint256 internal constant REGISTRY_CONDITIONAL_OVERHEAD = 90_000; // Used in maxPayment estimation, and in capping overheads during actual payment + uint256 internal constant REGISTRY_LOG_OVERHEAD = 110_000; // Used only in maxPayment estimation, and in capping overheads during actual payment. + uint256 internal constant REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD = 20; // Used only in maxPayment estimation, and in capping overheads during actual payment. Value scales with performData length. + uint256 internal constant REGISTRY_PER_SIGNER_GAS_OVERHEAD = 7_500; // Used only in maxPayment estimation, and in capping overheads during actual payment. Value scales with f. + + uint256 internal constant ACCOUNTING_FIXED_GAS_OVERHEAD = 27_500; // Used in actual payment. Fixed overhead per tx + uint256 internal constant ACCOUNTING_PER_SIGNER_GAS_OVERHEAD = 1_100; // Used in actual payment. overhead per signer + uint256 internal constant ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD = 7_000; // Used in actual payment. overhead per upkeep performed + + OVM_GasPriceOracle internal constant OPTIMISM_ORACLE = OVM_GasPriceOracle(0x420000000000000000000000000000000000000F); + ArbGasInfo internal constant ARB_NITRO_ORACLE = ArbGasInfo(0x000000000000000000000000000000000000006C); + ArbSys internal constant ARB_SYS = ArbSys(0x0000000000000000000000000000000000000064); + + LinkTokenInterface internal immutable i_link; + AggregatorV3Interface internal immutable i_linkNativeFeed; + AggregatorV3Interface internal immutable i_fastGasFeed; + Mode internal immutable i_mode; + address internal immutable i_automationForwarderLogic; + + /** + * @dev - The storage is gas optimised for one and only one function - transmit. All the storage accessed in transmit + * is stored compactly. Rest of the storage layout is not of much concern as transmit is the only hot path + */ + + // Upkeep storage + EnumerableSet.UintSet internal s_upkeepIDs; + mapping(uint256 => Upkeep) internal s_upkeep; // accessed during transmit + mapping(uint256 => address) internal s_upkeepAdmin; + mapping(uint256 => address) internal s_proposedAdmin; + mapping(uint256 => bytes) internal s_checkData; + mapping(bytes32 => bool) internal s_dedupKeys; + // Registry config and state + EnumerableSet.AddressSet internal s_registrars; + mapping(address => Transmitter) internal s_transmitters; + mapping(address => Signer) internal s_signers; + address[] internal s_signersList; // s_signersList contains the signing address of each oracle + address[] internal s_transmittersList; // s_transmittersList contains the transmission address of each oracle + mapping(address => address) internal s_transmitterPayees; // s_payees contains the mapping from transmitter to payee. + mapping(address => address) internal s_proposedPayee; // proposed payee for a transmitter + bytes32 internal s_latestConfigDigest; // Read on transmit path in case of signature verification + HotVars internal s_hotVars; // Mixture of config and state, used in transmit + Storage internal s_storage; // Mixture of config and state, not used in transmit + uint256 internal s_fallbackGasPrice; + uint256 internal s_fallbackLinkPrice; + uint256 internal s_expectedLinkBalance; // Used in case of erroneous LINK transfers to contract + mapping(address => MigrationPermission) internal s_peerRegistryMigrationPermission; // Permissions for migration to and fro + mapping(uint256 => bytes) internal s_upkeepTriggerConfig; // upkeep triggers + mapping(uint256 => bytes) internal s_upkeepOffchainConfig; // general config set by users for each upkeep + mapping(uint256 => bytes) internal s_upkeepPrivilegeConfig; // general config set by an administrative role for an upkeep + mapping(address => bytes) internal s_adminPrivilegeConfig; // general config set by an administrative role for an admin + + error ArrayHasNoEntries(); + error CannotCancel(); + error CheckDataExceedsLimit(); + error ConfigDigestMismatch(); + error DuplicateEntry(); + error DuplicateSigners(); + error GasLimitCanOnlyIncrease(); + error GasLimitOutsideRange(); + error IncorrectNumberOfFaultyOracles(); + error IncorrectNumberOfSignatures(); + error IncorrectNumberOfSigners(); + error IndexOutOfRange(); + error InsufficientFunds(); + error InvalidDataLength(); + error InvalidTrigger(); + error InvalidPayee(); + error InvalidRecipient(); + error InvalidReport(); + error InvalidSigner(); + error InvalidTransmitter(); + error InvalidTriggerType(); + error MaxCheckDataSizeCanOnlyIncrease(); + error MaxPerformDataSizeCanOnlyIncrease(); + error MigrationNotPermitted(); + error NotAContract(); + error OnlyActiveSigners(); + error OnlyActiveTransmitters(); + error OnlyCallableByAdmin(); + error OnlyCallableByLINKToken(); + error OnlyCallableByOwnerOrAdmin(); + error OnlyCallableByOwnerOrRegistrar(); + error OnlyCallableByPayee(); + error OnlyCallableByProposedAdmin(); + error OnlyCallableByProposedPayee(); + error OnlyCallableByUpkeepPrivilegeManager(); + error OnlyPausedUpkeep(); + error OnlyUnpausedUpkeep(); + error ParameterLengthError(); + error PaymentGreaterThanAllLINK(); + error ReentrantCall(); + error RegistryPaused(); + error RepeatedSigner(); + error RepeatedTransmitter(); + error TargetCheckReverted(bytes reason); + error TooManyOracles(); + error TranscoderNotSet(); + error UpkeepAlreadyExists(); + error UpkeepCancelled(); + error UpkeepNotCanceled(); + error UpkeepNotNeeded(); + error ValueNotChanged(); + + enum MigrationPermission { + NONE, + OUTGOING, + INCOMING, + BIDIRECTIONAL + } + + enum Mode { + DEFAULT, + ARBITRUM, + OPTIMISM + } + + enum Trigger { + CONDITION, + LOG + } + + enum UpkeepFailureReason { + NONE, + UPKEEP_CANCELLED, + UPKEEP_PAUSED, + TARGET_CHECK_REVERTED, + UPKEEP_NOT_NEEDED, + PERFORM_DATA_EXCEEDS_LIMIT, + INSUFFICIENT_BALANCE, + CALLBACK_REVERTED, + REVERT_DATA_EXCEEDS_LIMIT, + REGISTRY_PAUSED + } + + /** + * @notice OnchainConfig of the registry + * @dev only used in params and return values + * @member paymentPremiumPPB payment premium rate oracles receive on top of + * being reimbursed for gas, measured in parts per billion + * @member flatFeeMicroLink flat fee paid to oracles for performing upkeeps, + * priced in MicroLink; can be used in conjunction with or independently of + * paymentPremiumPPB + * @member checkGasLimit gas limit when checking for upkeep + * @member stalenessSeconds number of seconds that is allowed for feed data to + * be stale before switching to the fallback pricing + * @member gasCeilingMultiplier multiplier to apply to the fast gas feed price + * when calculating the payment ceiling for keepers + * @member minUpkeepSpend minimum LINK that an upkeep must spend before cancelling + * @member maxPerformGas max performGas allowed for an upkeep on this registry + * @member maxCheckDataSize max length of checkData bytes + * @member maxPerformDataSize max length of performData bytes + * @member maxRevertDataSize max length of revertData bytes + * @member fallbackGasPrice gas price used if the gas price feed is stale + * @member fallbackLinkPrice LINK price used if the LINK price feed is stale + * @member transcoder address of the transcoder contract + * @member registrars addresses of the registrar contracts + * @member upkeepPrivilegeManager address which can set privilege for upkeeps + * @member reorgProtectionEnabled if this registry will enable re-org protection checks + */ + struct OnchainConfig { + uint32 paymentPremiumPPB; + uint32 flatFeeMicroLink; // min 0.000001 LINK, max 4294 LINK + uint32 checkGasLimit; + uint24 stalenessSeconds; + uint16 gasCeilingMultiplier; + uint96 minUpkeepSpend; + uint32 maxPerformGas; + uint32 maxCheckDataSize; + uint32 maxPerformDataSize; + uint32 maxRevertDataSize; + uint256 fallbackGasPrice; + uint256 fallbackLinkPrice; + address transcoder; + address[] registrars; + address upkeepPrivilegeManager; + bool reorgProtectionEnabled; + } + + /** + * @notice state of the registry + * @dev only used in params and return values + * @dev this will likely be deprecated in a future version of the registry in favor of individual getters + * @member nonce used for ID generation + * @member ownerLinkBalance withdrawable balance of LINK by contract owner + * @member expectedLinkBalance the expected balance of LINK of the registry + * @member totalPremium the total premium collected on registry so far + * @member numUpkeeps total number of upkeeps on the registry + * @member configCount ordinal number of current config, out of all configs applied to this contract so far + * @member latestConfigBlockNumber last block at which this config was set + * @member latestConfigDigest domain-separation tag for current config + * @member latestEpoch for which a report was transmitted + * @member paused freeze on execution scoped to the entire registry + */ + struct State { + uint32 nonce; + uint96 ownerLinkBalance; + uint256 expectedLinkBalance; + uint96 totalPremium; + uint256 numUpkeeps; + uint32 configCount; + uint32 latestConfigBlockNumber; + bytes32 latestConfigDigest; + uint32 latestEpoch; + bool paused; + } + + /** + * @notice relevant state of an upkeep which is used in transmit function + * @member paused if this upkeep has been paused + * @member performGas the gas limit of upkeep execution + * @member maxValidBlocknumber until which block this upkeep is valid + * @member forwarder the forwarder contract to use for this upkeep + * @member amountSpent the amount this upkeep has spent + * @member balance the balance of this upkeep + * @member lastPerformedBlockNumber the last block number when this upkeep was performed + */ + struct Upkeep { + bool paused; + uint32 performGas; + uint32 maxValidBlocknumber; + IAutomationForwarder forwarder; + // 0 bytes left in 1st EVM word - not written to in transmit + uint96 amountSpent; + uint96 balance; + uint32 lastPerformedBlockNumber; + // 2 bytes left in 2nd EVM word - written in transmit path + } + + /** + * @notice all information about an upkeep + * @dev only used in return values + * @dev this will likely be deprecated in a future version of the registry + * @member target the contract which needs to be serviced + * @member performGas the gas limit of upkeep execution + * @member checkData the checkData bytes for this upkeep + * @member balance the balance of this upkeep + * @member admin for this upkeep + * @member maxValidBlocknumber until which block this upkeep is valid + * @member lastPerformedBlockNumber the last block number when this upkeep was performed + * @member amountSpent the amount this upkeep has spent + * @member paused if this upkeep has been paused + * @member offchainConfig the off-chain config of this upkeep + */ + struct UpkeepInfo { + address target; + uint32 performGas; + bytes checkData; + uint96 balance; + address admin; + uint64 maxValidBlocknumber; + uint32 lastPerformedBlockNumber; + uint96 amountSpent; + bool paused; + bytes offchainConfig; + } + + /// @dev Config + State storage struct which is on hot transmit path + struct HotVars { + uint96 totalPremium; // ─────────╮ total historical payment to oracles for premium + uint32 paymentPremiumPPB; // │ premium percentage charged to user over tx cost + uint32 flatFeeMicroLink; // │ flat fee charged to user for every perform + uint32 latestEpoch; // │ latest epoch for which a report was transmitted + uint24 stalenessSeconds; // │ Staleness tolerance for feeds + uint16 gasCeilingMultiplier; // │ multiplier on top of fast gas feed for upper bound + uint8 f; // │ maximum number of faulty oracles + bool paused; // │ pause switch for all upkeeps in the registry + bool reentrancyGuard; // ────────╯ guard against reentrancy + bool reorgProtectionEnabled; // if this registry should enable re-org protection mechanism + } + + /// @dev Config + State storage struct which is not on hot transmit path + struct Storage { + uint96 minUpkeepSpend; // Minimum amount an upkeep must spend + address transcoder; // Address of transcoder contract used in migrations + // 1 EVM word full + uint96 ownerLinkBalance; // Balance of owner, accumulates minUpkeepSpend in case it is not spent + uint32 checkGasLimit; // Gas limit allowed in checkUpkeep + uint32 maxPerformGas; // Max gas an upkeep can use on this registry + uint32 nonce; // Nonce for each upkeep created + uint32 configCount; // incremented each time a new config is posted, The count + // is incorporated into the config digest to prevent replay attacks. + uint32 latestConfigBlockNumber; // makes it easier for offchain systems to extract config from logs + // 2 EVM word full + uint32 maxCheckDataSize; // max length of checkData bytes + uint32 maxPerformDataSize; // max length of performData bytes + uint32 maxRevertDataSize; // max length of revertData bytes + address upkeepPrivilegeManager; // address which can set privilege for upkeeps + // 3 EVM word full + } + + /// @dev Report transmitted by OCR to transmit function + struct Report { + uint256 fastGasWei; + uint256 linkNative; + uint256[] upkeepIds; + uint256[] gasLimits; + bytes[] triggers; + bytes[] performDatas; + } + + /** + * @dev This struct is used to maintain run time information about an upkeep in transmit function + * @member upkeep the upkeep struct + * @member earlyChecksPassed whether the upkeep passed early checks before perform + * @member maxLinkPayment the max amount this upkeep could pay for work + * @member performSuccess whether the perform was successful + * @member triggerType the type of trigger + * @member gasUsed gasUsed by this upkeep in perform + * @member gasOverhead gasOverhead for this upkeep + * @member dedupID unique ID used to dedup an upkeep/trigger combo + */ + struct UpkeepTransmitInfo { + Upkeep upkeep; + bool earlyChecksPassed; + uint96 maxLinkPayment; + bool performSuccess; + Trigger triggerType; + uint256 gasUsed; + uint256 gasOverhead; + bytes32 dedupID; + } + + struct Transmitter { + bool active; + uint8 index; // Index of oracle in s_signersList/s_transmittersList + uint96 balance; + uint96 lastCollected; + } + + struct Signer { + bool active; + // Index of oracle in s_signersList/s_transmittersList + uint8 index; + } + + /** + * @notice the trigger structure conditional trigger type + */ + struct ConditionalTrigger { + uint32 blockNum; + bytes32 blockHash; + } + + /** + * @notice the trigger structure of log upkeeps + * @dev NOTE that blockNum / blockHash describe the block used for the callback, + * not necessarily the block number that the log was emitted in!!!! + */ + struct LogTrigger { + bytes32 logBlockHash; + bytes32 txHash; + uint32 logIndex; + uint32 blockNum; + bytes32 blockHash; + } + + event AdminPrivilegeConfigSet(address indexed admin, bytes privilegeConfig); + event CancelledUpkeepReport(uint256 indexed id, bytes trigger); + event DedupKeyAdded(bytes32 indexed dedupKey); + event FundsAdded(uint256 indexed id, address indexed from, uint96 amount); + event FundsWithdrawn(uint256 indexed id, uint256 amount, address to); + event InsufficientFundsUpkeepReport(uint256 indexed id, bytes trigger); + event OwnerFundsWithdrawn(uint96 amount); + event Paused(address account); + event PayeesUpdated(address[] transmitters, address[] payees); + event PayeeshipTransferRequested(address indexed transmitter, address indexed from, address indexed to); + event PayeeshipTransferred(address indexed transmitter, address indexed from, address indexed to); + event PaymentWithdrawn(address indexed transmitter, uint256 indexed amount, address indexed to, address payee); + event ReorgedUpkeepReport(uint256 indexed id, bytes trigger); + event StaleUpkeepReport(uint256 indexed id, bytes trigger); + event UpkeepAdminTransferred(uint256 indexed id, address indexed from, address indexed to); + event UpkeepAdminTransferRequested(uint256 indexed id, address indexed from, address indexed to); + event UpkeepCanceled(uint256 indexed id, uint64 indexed atBlockHeight); + event UpkeepCheckDataSet(uint256 indexed id, bytes newCheckData); + event UpkeepGasLimitSet(uint256 indexed id, uint96 gasLimit); + event UpkeepMigrated(uint256 indexed id, uint256 remainingBalance, address destination); + event UpkeepOffchainConfigSet(uint256 indexed id, bytes offchainConfig); + event UpkeepPaused(uint256 indexed id); + event UpkeepPerformed( + uint256 indexed id, + bool indexed success, + uint96 totalPayment, + uint256 gasUsed, + uint256 gasOverhead, + bytes trigger + ); + event UpkeepPrivilegeConfigSet(uint256 indexed id, bytes privilegeConfig); + event UpkeepReceived(uint256 indexed id, uint256 startingBalance, address importedFrom); + event UpkeepRegistered(uint256 indexed id, uint32 performGas, address admin); + event UpkeepTriggerConfigSet(uint256 indexed id, bytes triggerConfig); + event UpkeepUnpaused(uint256 indexed id); + event Unpaused(address account); + + /** + * @param mode the contract mode of default, Arbitrum, or Optimism + * @param link address of the LINK Token + * @param linkNativeFeed address of the LINK/Native price feed + * @param fastGasFeed address of the Fast Gas price feed + */ + constructor( + Mode mode, + address link, + address linkNativeFeed, + address fastGasFeed, + address automationForwarderLogic + ) ConfirmedOwner(msg.sender) { + i_mode = mode; + i_link = LinkTokenInterface(link); + i_linkNativeFeed = AggregatorV3Interface(linkNativeFeed); + i_fastGasFeed = AggregatorV3Interface(fastGasFeed); + i_automationForwarderLogic = automationForwarderLogic; + } + + // ================================================================ + // | INTERNAL FUNCTIONS ONLY | + // ================================================================ + + /** + * @dev creates a new upkeep with the given fields + * @param id the id of the upkeep + * @param upkeep the upkeep to create + * @param admin address to cancel upkeep and withdraw remaining funds + * @param checkData data which is passed to user's checkUpkeep + * @param triggerConfig the trigger config for this upkeep + * @param offchainConfig the off-chain config of this upkeep + */ + function _createUpkeep( + uint256 id, + Upkeep memory upkeep, + address admin, + bytes memory checkData, + bytes memory triggerConfig, + bytes memory offchainConfig + ) internal { + if (s_hotVars.paused) revert RegistryPaused(); + if (checkData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit(); + if (upkeep.performGas < PERFORM_GAS_MIN || upkeep.performGas > s_storage.maxPerformGas) + revert GasLimitOutsideRange(); + if (address(s_upkeep[id].forwarder) != address(0)) revert UpkeepAlreadyExists(); + s_upkeep[id] = upkeep; + s_upkeepAdmin[id] = admin; + s_checkData[id] = checkData; + s_expectedLinkBalance = s_expectedLinkBalance + upkeep.balance; + s_upkeepTriggerConfig[id] = triggerConfig; + s_upkeepOffchainConfig[id] = offchainConfig; + s_upkeepIDs.add(id); + } + + /** + * @dev creates an ID for the upkeep based on the upkeep's type + * @dev the format of the ID looks like this: + * ****00000000000X**************** + * 4 bytes of entropy + * 11 bytes of zeros + * 1 identifying byte for the trigger type + * 16 bytes of entropy + * @dev this maintains the same level of entropy as eth addresses, so IDs will still be unique + * @dev we add the "identifying" part in the middle so that it is mostly hidden from users who usually only + * see the first 4 and last 4 hex values ex 0x1234...ABCD + */ + function _createID(Trigger triggerType) internal view returns (uint256) { + bytes1 empty; + bytes memory idBytes = abi.encodePacked( + keccak256(abi.encode(_blockHash(_blockNum() - 1), address(this), s_storage.nonce)) + ); + for (uint256 idx = 4; idx < 15; idx++) { + idBytes[idx] = empty; + } + idBytes[15] = bytes1(uint8(triggerType)); + return uint256(bytes32(idBytes)); + } + + /** + * @dev retrieves feed data for fast gas/native and link/native prices. if the feed + * data is stale it uses the configured fallback price. Once a price is picked + * for gas it takes the min of gas price in the transaction or the fast gas + * price in order to reduce costs for the upkeep clients. + */ + function _getFeedData(HotVars memory hotVars) internal view returns (uint256 gasWei, uint256 linkNative) { + uint32 stalenessSeconds = hotVars.stalenessSeconds; + bool staleFallback = stalenessSeconds > 0; + uint256 timestamp; + int256 feedValue; + (, feedValue, , timestamp, ) = i_fastGasFeed.latestRoundData(); + if ( + feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp) + ) { + gasWei = s_fallbackGasPrice; + } else { + gasWei = uint256(feedValue); + } + (, feedValue, , timestamp, ) = i_linkNativeFeed.latestRoundData(); + if ( + feedValue <= 0 || block.timestamp < timestamp || (staleFallback && stalenessSeconds < block.timestamp - timestamp) + ) { + linkNative = s_fallbackLinkPrice; + } else { + linkNative = uint256(feedValue); + } + return (gasWei, linkNative); + } + + /** + * @dev calculates LINK paid for gas spent plus a configure premium percentage + * @param gasLimit the amount of gas used + * @param gasOverhead the amount of gas overhead + * @param fastGasWei the fast gas price + * @param linkNative the exchange ratio between LINK and Native token + * @param numBatchedUpkeeps the number of upkeeps in this batch. Used to divide the L1 cost + * @param isExecution if this is triggered by a perform upkeep function + */ + function _calculatePaymentAmount( + HotVars memory hotVars, + uint256 gasLimit, + uint256 gasOverhead, + uint256 fastGasWei, + uint256 linkNative, + uint16 numBatchedUpkeeps, + bool isExecution + ) internal view returns (uint96, uint96) { + uint256 gasWei = fastGasWei * hotVars.gasCeilingMultiplier; + // in case it's actual execution use actual gas price, capped by fastGasWei * gasCeilingMultiplier + if (isExecution && tx.gasprice < gasWei) { + gasWei = tx.gasprice; + } + + uint256 l1CostWei = 0; + if (i_mode == Mode.OPTIMISM) { + bytes memory txCallData = new bytes(0); + if (isExecution) { + txCallData = bytes.concat(msg.data, L1_FEE_DATA_PADDING); + } else { + // fee is 4 per 0 byte, 16 per non-zero byte. Worst case we can have + // s_storage.maxPerformDataSize non zero-bytes. Instead of setting bytes to non-zero + // we initialize 'new bytes' of length 4*maxPerformDataSize to cover for zero bytes. + txCallData = new bytes(4 * s_storage.maxPerformDataSize); + } + l1CostWei = OPTIMISM_ORACLE.getL1Fee(txCallData); + } else if (i_mode == Mode.ARBITRUM) { + if (isExecution) { + l1CostWei = ARB_NITRO_ORACLE.getCurrentTxL1GasFees(); + } else { + // fee is 4 per 0 byte, 16 per non-zero byte - we assume all non-zero and + // max data size to calculate max payment + (, uint256 perL1CalldataUnit, , , , ) = ARB_NITRO_ORACLE.getPricesInWei(); + l1CostWei = perL1CalldataUnit * s_storage.maxPerformDataSize * 16; + } + } + // if it's not performing upkeeps, use gas ceiling multiplier to estimate the upper bound + if (!isExecution) { + l1CostWei = hotVars.gasCeilingMultiplier * l1CostWei; + } + // Divide l1CostWei among all batched upkeeps. Spare change from division is not charged + l1CostWei = l1CostWei / numBatchedUpkeeps; + + uint256 gasPayment = ((gasWei * (gasLimit + gasOverhead) + l1CostWei) * 1e18) / linkNative; + uint256 premium = (((gasWei * gasLimit) + l1CostWei) * 1e9 * hotVars.paymentPremiumPPB) / + linkNative + + uint256(hotVars.flatFeeMicroLink) * + 1e12; + // LINK_TOTAL_SUPPLY < UINT96_MAX + if (gasPayment + premium > LINK_TOTAL_SUPPLY) revert PaymentGreaterThanAllLINK(); + return (uint96(gasPayment), uint96(premium)); + } + + /** + * @dev calculates the max LINK payment for an upkeep + */ + function _getMaxLinkPayment( + HotVars memory hotVars, + Trigger triggerType, + uint32 performGas, + uint32 performDataLength, + uint256 fastGasWei, + uint256 linkNative, + bool isExecution // Whether this is an actual perform execution or just a simulation + ) internal view returns (uint96) { + uint256 gasOverhead = _getMaxGasOverhead(triggerType, performDataLength, hotVars.f); + (uint96 reimbursement, uint96 premium) = _calculatePaymentAmount( + hotVars, + performGas, + gasOverhead, + fastGasWei, + linkNative, + 1, // Consider only 1 upkeep in batch to get maxPayment + isExecution + ); + + return reimbursement + premium; + } + + /** + * @dev returns the max gas overhead that can be charged for an upkeep + */ + function _getMaxGasOverhead(Trigger triggerType, uint32 performDataLength, uint8 f) internal pure returns (uint256) { + // performData causes additional overhead in report length and memory operations + uint256 baseOverhead; + if (triggerType == Trigger.CONDITION) { + baseOverhead = REGISTRY_CONDITIONAL_OVERHEAD; + } else if (triggerType == Trigger.LOG) { + baseOverhead = REGISTRY_LOG_OVERHEAD; + } else { + revert InvalidTriggerType(); + } + return + baseOverhead + + (REGISTRY_PER_SIGNER_GAS_OVERHEAD * (f + 1)) + + (REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD * performDataLength); + } + + /** + * @dev move a transmitter's balance from total pool to withdrawable balance + */ + function _updateTransmitterBalanceFromPool( + address transmitterAddress, + uint96 totalPremium, + uint96 payeeCount + ) internal returns (uint96) { + Transmitter memory transmitter = s_transmitters[transmitterAddress]; + + if (transmitter.active) { + uint96 uncollected = totalPremium - transmitter.lastCollected; + uint96 due = uncollected / payeeCount; + transmitter.balance += due; + transmitter.lastCollected += due * payeeCount; + s_transmitters[transmitterAddress] = transmitter; + } + + return transmitter.balance; + } + + /** + * @dev gets the trigger type from an upkeepID (trigger type is encoded in the middle of the ID) + */ + function _getTriggerType(uint256 upkeepId) internal pure returns (Trigger) { + bytes32 rawID = bytes32(upkeepId); + bytes1 empty = bytes1(0); + for (uint256 idx = 4; idx < 15; idx++) { + if (rawID[idx] != empty) { + // old IDs that were created before this standard and migrated to this registry + return Trigger.CONDITION; + } + } + return Trigger(uint8(rawID[15])); + } + + function _checkPayload( + uint256 upkeepId, + Trigger triggerType, + bytes memory triggerData + ) internal view returns (bytes memory) { + if (triggerType == Trigger.CONDITION) { + return abi.encodeWithSelector(CHECK_SELECTOR, s_checkData[upkeepId]); + } else if (triggerType == Trigger.LOG) { + Log memory log = abi.decode(triggerData, (Log)); + return abi.encodeWithSelector(CHECK_LOG_SELECTOR, log, s_checkData[upkeepId]); + } + revert InvalidTriggerType(); + } + + /** + * @dev _decodeReport decodes a serialized report into a Report struct + */ + function _decodeReport(bytes calldata rawReport) internal pure returns (Report memory) { + Report memory report = abi.decode(rawReport, (Report)); + uint256 expectedLength = report.upkeepIds.length; + if ( + report.gasLimits.length != expectedLength || + report.triggers.length != expectedLength || + report.performDatas.length != expectedLength + ) { + revert InvalidReport(); + } + return report; + } + + /** + * @dev Does some early sanity checks before actually performing an upkeep + * @return bool whether the upkeep should be performed + * @return bytes32 dedupID for preventing duplicate performances of this trigger + */ + function _prePerformChecks( + uint256 upkeepId, + bytes memory rawTrigger, + UpkeepTransmitInfo memory transmitInfo, + HotVars memory hotVars + ) internal returns (bool, bytes32) { + bytes32 dedupID; + if (transmitInfo.triggerType == Trigger.CONDITION) { + if (!_validateConditionalTrigger(upkeepId, rawTrigger, transmitInfo, hotVars)) return (false, dedupID); + } else if (transmitInfo.triggerType == Trigger.LOG) { + bool valid; + (valid, dedupID) = _validateLogTrigger(upkeepId, rawTrigger, hotVars); + if (!valid) return (false, dedupID); + } else { + revert InvalidTriggerType(); + } + if (transmitInfo.upkeep.maxValidBlocknumber <= _blockNum()) { + // Can happen when an upkeep got cancelled after report was generated. + // However we have a CANCELLATION_DELAY of 50 blocks so shouldn't happen in practice + emit CancelledUpkeepReport(upkeepId, rawTrigger); + return (false, dedupID); + } + if (transmitInfo.upkeep.balance < transmitInfo.maxLinkPayment) { + // Can happen due to fluctuations in gas / link prices + emit InsufficientFundsUpkeepReport(upkeepId, rawTrigger); + return (false, dedupID); + } + return (true, dedupID); + } + + /** + * @dev Does some early sanity checks before actually performing an upkeep + */ + function _validateConditionalTrigger( + uint256 upkeepId, + bytes memory rawTrigger, + UpkeepTransmitInfo memory transmitInfo, + HotVars memory hotVars + ) internal returns (bool) { + ConditionalTrigger memory trigger = abi.decode(rawTrigger, (ConditionalTrigger)); + if (trigger.blockNum < transmitInfo.upkeep.lastPerformedBlockNumber) { + // Can happen when another report performed this upkeep after this report was generated + emit StaleUpkeepReport(upkeepId, rawTrigger); + return false; + } + if ( + (hotVars.reorgProtectionEnabled && + (trigger.blockHash != bytes32("") && _blockHash(trigger.blockNum) != trigger.blockHash)) || + trigger.blockNum >= _blockNum() + ) { + // There are two cases of reorged report + // 1. trigger block number is in future: this is an edge case during extreme deep reorgs of chain + // which is always protected against + // 2. blockHash at trigger block number was same as trigger time. This is an optional check which is + // applied if DON sends non empty trigger.blockHash. Note: It only works for last 256 blocks on chain + // when it is sent + emit ReorgedUpkeepReport(upkeepId, rawTrigger); + return false; + } + return true; + } + + function _validateLogTrigger( + uint256 upkeepId, + bytes memory rawTrigger, + HotVars memory hotVars + ) internal returns (bool, bytes32) { + LogTrigger memory trigger = abi.decode(rawTrigger, (LogTrigger)); + bytes32 dedupID = keccak256(abi.encodePacked(upkeepId, trigger.logBlockHash, trigger.txHash, trigger.logIndex)); + if ( + (hotVars.reorgProtectionEnabled && + (trigger.blockHash != bytes32("") && _blockHash(trigger.blockNum) != trigger.blockHash)) || + trigger.blockNum >= _blockNum() + ) { + // Reorg protection is same as conditional trigger upkeeps + emit ReorgedUpkeepReport(upkeepId, rawTrigger); + return (false, dedupID); + } + if (s_dedupKeys[dedupID]) { + emit StaleUpkeepReport(upkeepId, rawTrigger); + return (false, dedupID); + } + return (true, dedupID); + } + + /** + * @dev Verify signatures attached to report + */ + function _verifyReportSignature( + bytes32[3] calldata reportContext, + bytes calldata report, + bytes32[] calldata rs, + bytes32[] calldata ss, + bytes32 rawVs + ) internal view { + bytes32 h = keccak256(abi.encode(keccak256(report), reportContext)); + // i-th byte counts number of sigs made by i-th signer + uint256 signedCount = 0; + + Signer memory signer; + address signerAddress; + for (uint256 i = 0; i < rs.length; i++) { + signerAddress = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]); + signer = s_signers[signerAddress]; + if (!signer.active) revert OnlyActiveSigners(); + unchecked { + signedCount += 1 << (8 * signer.index); + } + } + + if (signedCount & ORACLE_MASK != signedCount) revert DuplicateSigners(); + } + + /** + * @dev updates a storage marker for this upkeep to prevent duplicate and out of order performances + * @dev for conditional triggers we set the latest block number, for log triggers we store a dedupID + */ + function _updateTriggerMarker(uint256 upkeepID, UpkeepTransmitInfo memory upkeepTransmitInfo) internal { + if (upkeepTransmitInfo.triggerType == Trigger.CONDITION) { + s_upkeep[upkeepID].lastPerformedBlockNumber = uint32(_blockNum()); + } else if (upkeepTransmitInfo.triggerType == Trigger.LOG) { + s_dedupKeys[upkeepTransmitInfo.dedupID] = true; + emit DedupKeyAdded(upkeepTransmitInfo.dedupID); + } + } + + /** + * @dev calls the Upkeep target with the performData param passed in by the + * transmitter and the exact gas required by the Upkeep + */ + function _performUpkeep( + IAutomationForwarder forwarder, + uint256 performGas, + bytes memory performData + ) internal nonReentrant returns (bool success, uint256 gasUsed) { + performData = abi.encodeWithSelector(PERFORM_SELECTOR, performData); + return forwarder.forward(performGas, performData); + } + + /** + * @dev does postPerform payment processing for an upkeep. Deducts upkeep's balance and increases + * amount spent. + */ + function _postPerformPayment( + HotVars memory hotVars, + uint256 upkeepId, + UpkeepTransmitInfo memory upkeepTransmitInfo, + uint256 fastGasWei, + uint256 linkNative, + uint16 numBatchedUpkeeps + ) internal returns (uint96 gasReimbursement, uint96 premium) { + (gasReimbursement, premium) = _calculatePaymentAmount( + hotVars, + upkeepTransmitInfo.gasUsed, + upkeepTransmitInfo.gasOverhead, + fastGasWei, + linkNative, + numBatchedUpkeeps, + true + ); + + uint96 payment = gasReimbursement + premium; + s_upkeep[upkeepId].balance -= payment; + s_upkeep[upkeepId].amountSpent += payment; + + return (gasReimbursement, premium); + } + + /** + * @dev Caps the gas overhead by the constant overhead used within initial payment checks in order to + * prevent a revert in payment processing. + */ + function _getCappedGasOverhead( + uint256 calculatedGasOverhead, + Trigger triggerType, + uint32 performDataLength, + uint8 f + ) internal pure returns (uint256 cappedGasOverhead) { + cappedGasOverhead = _getMaxGasOverhead(triggerType, performDataLength, f); + if (calculatedGasOverhead < cappedGasOverhead) { + return calculatedGasOverhead; + } + return cappedGasOverhead; + } + + /** + * @dev ensures the upkeep is not cancelled and the caller is the upkeep admin + */ + function _requireAdminAndNotCancelled(uint256 upkeepId) internal view { + if (msg.sender != s_upkeepAdmin[upkeepId]) revert OnlyCallableByAdmin(); + if (s_upkeep[upkeepId].maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + } + + /** + * @dev returns the current block number in a chain agnostic manner + */ + function _blockNum() internal view returns (uint256) { + if (i_mode == Mode.ARBITRUM) { + return ARB_SYS.arbBlockNumber(); + } else { + return block.number; + } + } + + /** + * @dev returns the blockhash of the provided block number in a chain agnostic manner + * @param n the blocknumber to retrieve the blockhash for + * @return blockhash the blockhash of block number n, or 0 if n is out queryable of range + */ + function _blockHash(uint256 n) internal view returns (bytes32) { + if (i_mode == Mode.ARBITRUM) { + uint256 blockNum = ARB_SYS.arbBlockNumber(); + if (n >= blockNum || blockNum - n > 256) { + return ""; + } + return ARB_SYS.arbBlockHash(n); + } else { + return blockhash(n); + } + } + + /** + * @dev replicates Open Zeppelin's ReentrancyGuard but optimized to fit our storage + */ + modifier nonReentrant() { + if (s_hotVars.reentrancyGuard) revert ReentrantCall(); + s_hotVars.reentrancyGuard = true; + _; + s_hotVars.reentrancyGuard = false; + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicA2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicA2_2.sol new file mode 100644 index 00000000000..8c2183c4e23 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicA2_2.sol @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.16; + +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {AutomationRegistryBase2_2} from "./AutomationRegistryBase2_2.sol"; +import {AutomationRegistryLogicB2_2} from "./AutomationRegistryLogicB2_2.sol"; +import {Chainable} from "../../Chainable.sol"; +import {AutomationForwarder} from "../../AutomationForwarder.sol"; +import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; +import {UpkeepTranscoderInterfaceV2} from "../../interfaces/UpkeepTranscoderInterfaceV2.sol"; +import {MigratableKeeperRegistryInterfaceV2} from "../../interfaces/MigratableKeeperRegistryInterfaceV2.sol"; + +/** + * @notice Logic contract, works in tandem with AutomationRegistry as a proxy + */ +contract AutomationRegistryLogicA2_2 is AutomationRegistryBase2_2, Chainable { + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableSet for EnumerableSet.AddressSet; + + /** + * @param logicB the address of the second logic contract + */ + constructor( + AutomationRegistryLogicB2_2 logicB + ) + AutomationRegistryBase2_2( + logicB.getMode(), + logicB.getLinkAddress(), + logicB.getLinkNativeFeedAddress(), + logicB.getFastGasFeedAddress(), + logicB.getAutomationForwarderLogic() + ) + Chainable(address(logicB)) + {} + + /** + * @notice called by the automation DON to check if work is needed + * @param id the upkeep ID to check for work needed + * @param triggerData extra contextual data about the trigger (not used in all code paths) + * @dev this one of the core functions called in the hot path + * @dev there is a 2nd checkUpkeep function (below) that is being maintained for backwards compatibility + * @dev there is an incongruency on what gets returned during failure modes + * ex sometimes we include price data, sometimes we omit it depending on the failure + */ + function checkUpkeep( + uint256 id, + bytes memory triggerData + ) + public + cannotExecute + returns ( + bool upkeepNeeded, + bytes memory performData, + UpkeepFailureReason upkeepFailureReason, + uint256 gasUsed, + uint256 gasLimit, + uint256 fastGasWei, + uint256 linkNative + ) + { + Trigger triggerType = _getTriggerType(id); + HotVars memory hotVars = s_hotVars; + Upkeep memory upkeep = s_upkeep[id]; + + if (hotVars.paused) return (false, bytes(""), UpkeepFailureReason.REGISTRY_PAUSED, 0, upkeep.performGas, 0, 0); + if (upkeep.maxValidBlocknumber != UINT32_MAX) + return (false, bytes(""), UpkeepFailureReason.UPKEEP_CANCELLED, 0, upkeep.performGas, 0, 0); + if (upkeep.paused) return (false, bytes(""), UpkeepFailureReason.UPKEEP_PAUSED, 0, upkeep.performGas, 0, 0); + + (fastGasWei, linkNative) = _getFeedData(hotVars); + uint96 maxLinkPayment = _getMaxLinkPayment( + hotVars, + triggerType, + upkeep.performGas, + s_storage.maxPerformDataSize, + fastGasWei, + linkNative, + false + ); + if (upkeep.balance < maxLinkPayment) { + return (false, bytes(""), UpkeepFailureReason.INSUFFICIENT_BALANCE, 0, upkeep.performGas, 0, 0); + } + + bytes memory callData = _checkPayload(id, triggerType, triggerData); + + gasUsed = gasleft(); + (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(callData); + gasUsed = gasUsed - gasleft(); + + if (!success) { + // User's target check reverted. We capture the revert data here and pass it within performData + if (result.length > s_storage.maxRevertDataSize) { + return ( + false, + bytes(""), + UpkeepFailureReason.REVERT_DATA_EXCEEDS_LIMIT, + gasUsed, + upkeep.performGas, + fastGasWei, + linkNative + ); + } + return ( + upkeepNeeded, + result, + UpkeepFailureReason.TARGET_CHECK_REVERTED, + gasUsed, + upkeep.performGas, + fastGasWei, + linkNative + ); + } + + (upkeepNeeded, performData) = abi.decode(result, (bool, bytes)); + if (!upkeepNeeded) + return ( + false, + bytes(""), + UpkeepFailureReason.UPKEEP_NOT_NEEDED, + gasUsed, + upkeep.performGas, + fastGasWei, + linkNative + ); + + if (performData.length > s_storage.maxPerformDataSize) + return ( + false, + bytes(""), + UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, + gasUsed, + upkeep.performGas, + fastGasWei, + linkNative + ); + + return (upkeepNeeded, performData, upkeepFailureReason, gasUsed, upkeep.performGas, fastGasWei, linkNative); + } + + /** + * @notice see other checkUpkeep function for description + * @dev this function may be deprecated in a future version of chainlink automation + */ + function checkUpkeep( + uint256 id + ) + external + returns ( + bool upkeepNeeded, + bytes memory performData, + UpkeepFailureReason upkeepFailureReason, + uint256 gasUsed, + uint256 gasLimit, + uint256 fastGasWei, + uint256 linkNative + ) + { + return checkUpkeep(id, bytes("")); + } + + /** + * @dev checkCallback is used specifically for automation data streams lookups (see StreamsLookupCompatibleInterface.sol) + * @param id the upkeepID to execute a callback for + * @param values the values returned from the data streams lookup + * @param extraData the user-provided extra context data + */ + function checkCallback( + uint256 id, + bytes[] memory values, + bytes calldata extraData + ) + external + cannotExecute + returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed) + { + bytes memory payload = abi.encodeWithSelector(CHECK_CALLBACK_SELECTOR, values, extraData); + return executeCallback(id, payload); + } + + /** + * @notice this is a generic callback executor that forwards a call to a user's contract with the configured + * gas limit + * @param id the upkeepID to execute a callback for + * @param payload the data (including function selector) to call on the upkeep target contract + */ + function executeCallback( + uint256 id, + bytes memory payload + ) + public + cannotExecute + returns (bool upkeepNeeded, bytes memory performData, UpkeepFailureReason upkeepFailureReason, uint256 gasUsed) + { + Upkeep memory upkeep = s_upkeep[id]; + gasUsed = gasleft(); + (bool success, bytes memory result) = upkeep.forwarder.getTarget().call{gas: s_storage.checkGasLimit}(payload); + gasUsed = gasUsed - gasleft(); + if (!success) { + return (false, bytes(""), UpkeepFailureReason.CALLBACK_REVERTED, gasUsed); + } + (upkeepNeeded, performData) = abi.decode(result, (bool, bytes)); + if (!upkeepNeeded) { + return (false, bytes(""), UpkeepFailureReason.UPKEEP_NOT_NEEDED, gasUsed); + } + if (performData.length > s_storage.maxPerformDataSize) { + return (false, bytes(""), UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, gasUsed); + } + return (upkeepNeeded, performData, upkeepFailureReason, gasUsed); + } + + /** + * @notice adds a new upkeep + * @param target address to perform upkeep on + * @param gasLimit amount of gas to provide the target contract when + * performing upkeep + * @param admin address to cancel upkeep and withdraw remaining funds + * @param triggerType the trigger for the upkeep + * @param checkData data passed to the contract when checking for upkeep + * @param triggerConfig the config for the trigger + * @param offchainConfig arbitrary offchain config for the upkeep + */ + function registerUpkeep( + address target, + uint32 gasLimit, + address admin, + Trigger triggerType, + bytes calldata checkData, + bytes memory triggerConfig, + bytes memory offchainConfig + ) public returns (uint256 id) { + if (msg.sender != owner() && !s_registrars.contains(msg.sender)) revert OnlyCallableByOwnerOrRegistrar(); + if (!target.isContract()) revert NotAContract(); + id = _createID(triggerType); + IAutomationForwarder forwarder = IAutomationForwarder( + address(new AutomationForwarder(target, address(this), i_automationForwarderLogic)) + ); + _createUpkeep( + id, + Upkeep({ + performGas: gasLimit, + balance: 0, + maxValidBlocknumber: UINT32_MAX, + lastPerformedBlockNumber: 0, + amountSpent: 0, + paused: false, + forwarder: forwarder + }), + admin, + checkData, + triggerConfig, + offchainConfig + ); + s_storage.nonce++; + emit UpkeepRegistered(id, gasLimit, admin); + emit UpkeepCheckDataSet(id, checkData); + emit UpkeepTriggerConfigSet(id, triggerConfig); + emit UpkeepOffchainConfigSet(id, offchainConfig); + return (id); + } + + /** + * @notice this function registers a conditional upkeep, using a backwards compatible function signature + * @dev this function is backwards compatible with versions <=2.0, but may be removed in a future version + */ + function registerUpkeep( + address target, + uint32 gasLimit, + address admin, + bytes calldata checkData, + bytes calldata offchainConfig + ) external returns (uint256 id) { + return registerUpkeep(target, gasLimit, admin, Trigger.CONDITION, checkData, bytes(""), offchainConfig); + } + + /** + * @notice cancels an upkeep + * @param id the upkeepID to cancel + * @dev if a user cancels an upkeep, their funds are locked for CANCELLATION_DELAY blocks to + * allow any pending performUpkeep txs time to get confirmed + */ + function cancelUpkeep(uint256 id) external { + Upkeep memory upkeep = s_upkeep[id]; + bool canceled = upkeep.maxValidBlocknumber != UINT32_MAX; + bool isOwner = msg.sender == owner(); + + if (canceled && !(isOwner && upkeep.maxValidBlocknumber > _blockNum())) revert CannotCancel(); + if (!isOwner && msg.sender != s_upkeepAdmin[id]) revert OnlyCallableByOwnerOrAdmin(); + + uint256 height = _blockNum(); + if (!isOwner) { + height = height + CANCELLATION_DELAY; + } + s_upkeep[id].maxValidBlocknumber = uint32(height); + s_upkeepIDs.remove(id); + + // charge the cancellation fee if the minUpkeepSpend is not met + uint96 minUpkeepSpend = s_storage.minUpkeepSpend; + uint96 cancellationFee = 0; + // cancellationFee is supposed to be min(max(minUpkeepSpend - amountSpent,0), amountLeft) + if (upkeep.amountSpent < minUpkeepSpend) { + cancellationFee = minUpkeepSpend - upkeep.amountSpent; + if (cancellationFee > upkeep.balance) { + cancellationFee = upkeep.balance; + } + } + s_upkeep[id].balance = upkeep.balance - cancellationFee; + s_storage.ownerLinkBalance = s_storage.ownerLinkBalance + cancellationFee; + + emit UpkeepCanceled(id, uint64(height)); + } + + /** + * @notice adds fund to an upkeep + * @param id the upkeepID + * @param amount the amount of LINK to fund, in jules (jules = "wei" of LINK) + */ + function addFunds(uint256 id, uint96 amount) external { + Upkeep memory upkeep = s_upkeep[id]; + if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + s_upkeep[id].balance = upkeep.balance + amount; + s_expectedLinkBalance = s_expectedLinkBalance + amount; + i_link.transferFrom(msg.sender, address(this), amount); + emit FundsAdded(id, msg.sender, amount); + } + + /** + * @notice migrates upkeeps from one registry to another + * @param ids the upkeepIDs to migrate + * @param destination the destination registry address + * @dev a transcoder must be set in order to enable migration + * @dev migration permissions must be set on *both* sending and receiving registries + * @dev only an upkeep admin can migrate their upkeeps + */ + function migrateUpkeeps(uint256[] calldata ids, address destination) external { + if ( + s_peerRegistryMigrationPermission[destination] != MigrationPermission.OUTGOING && + s_peerRegistryMigrationPermission[destination] != MigrationPermission.BIDIRECTIONAL + ) revert MigrationNotPermitted(); + if (s_storage.transcoder == ZERO_ADDRESS) revert TranscoderNotSet(); + if (ids.length == 0) revert ArrayHasNoEntries(); + uint256 id; + Upkeep memory upkeep; + uint256 totalBalanceRemaining; + address[] memory admins = new address[](ids.length); + Upkeep[] memory upkeeps = new Upkeep[](ids.length); + bytes[] memory checkDatas = new bytes[](ids.length); + bytes[] memory triggerConfigs = new bytes[](ids.length); + bytes[] memory offchainConfigs = new bytes[](ids.length); + for (uint256 idx = 0; idx < ids.length; idx++) { + id = ids[idx]; + upkeep = s_upkeep[id]; + _requireAdminAndNotCancelled(id); + upkeep.forwarder.updateRegistry(destination); + upkeeps[idx] = upkeep; + admins[idx] = s_upkeepAdmin[id]; + checkDatas[idx] = s_checkData[id]; + triggerConfigs[idx] = s_upkeepTriggerConfig[id]; + offchainConfigs[idx] = s_upkeepOffchainConfig[id]; + totalBalanceRemaining = totalBalanceRemaining + upkeep.balance; + delete s_upkeep[id]; + delete s_checkData[id]; + delete s_upkeepTriggerConfig[id]; + delete s_upkeepOffchainConfig[id]; + // nullify existing proposed admin change if an upkeep is being migrated + delete s_proposedAdmin[id]; + s_upkeepIDs.remove(id); + emit UpkeepMigrated(id, upkeep.balance, destination); + } + s_expectedLinkBalance = s_expectedLinkBalance - totalBalanceRemaining; + bytes memory encodedUpkeeps = abi.encode( + ids, + upkeeps, + new address[](ids.length), + admins, + checkDatas, + triggerConfigs, + offchainConfigs + ); + MigratableKeeperRegistryInterfaceV2(destination).receiveUpkeeps( + UpkeepTranscoderInterfaceV2(s_storage.transcoder).transcodeUpkeeps( + UPKEEP_VERSION_BASE, + MigratableKeeperRegistryInterfaceV2(destination).upkeepVersion(), + encodedUpkeeps + ) + ); + i_link.transfer(destination, totalBalanceRemaining); + } + + /** + * @notice received upkeeps migrated from another registry + * @param encodedUpkeeps the raw upkeep data to import + * @dev this function is never called directly, it is only called by another registry's migrate function + */ + function receiveUpkeeps(bytes calldata encodedUpkeeps) external { + if ( + s_peerRegistryMigrationPermission[msg.sender] != MigrationPermission.INCOMING && + s_peerRegistryMigrationPermission[msg.sender] != MigrationPermission.BIDIRECTIONAL + ) revert MigrationNotPermitted(); + ( + uint256[] memory ids, + Upkeep[] memory upkeeps, + address[] memory targets, + address[] memory upkeepAdmins, + bytes[] memory checkDatas, + bytes[] memory triggerConfigs, + bytes[] memory offchainConfigs + ) = abi.decode(encodedUpkeeps, (uint256[], Upkeep[], address[], address[], bytes[], bytes[], bytes[])); + for (uint256 idx = 0; idx < ids.length; idx++) { + if (address(upkeeps[idx].forwarder) == ZERO_ADDRESS) { + upkeeps[idx].forwarder = IAutomationForwarder( + address(new AutomationForwarder(targets[idx], address(this), i_automationForwarderLogic)) + ); + } + _createUpkeep( + ids[idx], + upkeeps[idx], + upkeepAdmins[idx], + checkDatas[idx], + triggerConfigs[idx], + offchainConfigs[idx] + ); + emit UpkeepReceived(ids[idx], upkeeps[idx].balance, msg.sender); + } + } + + /** + * @notice sets the upkeep trigger config + * @param id the upkeepID to change the trigger for + * @param triggerConfig the new trigger config + */ + function setUpkeepTriggerConfig(uint256 id, bytes calldata triggerConfig) external { + _requireAdminAndNotCancelled(id); + s_upkeepTriggerConfig[id] = triggerConfig; + emit UpkeepTriggerConfigSet(id, triggerConfig); + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicB2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicB2_2.sol new file mode 100644 index 00000000000..04fec3d5f2b --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationRegistryLogicB2_2.sol @@ -0,0 +1,517 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.16; + +import {AutomationRegistryBase2_2} from "./AutomationRegistryBase2_2.sol"; +import {EnumerableSet} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/structs/EnumerableSet.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; +import {UpkeepFormat} from "../../interfaces/UpkeepTranscoderInterface.sol"; +import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; + +contract AutomationRegistryLogicB2_2 is AutomationRegistryBase2_2 { + using Address for address; + using EnumerableSet for EnumerableSet.UintSet; + using EnumerableSet for EnumerableSet.AddressSet; + + /** + * @dev see AutomationRegistry master contract for constructor description + */ + constructor( + Mode mode, + address link, + address linkNativeFeed, + address fastGasFeed, + address automationForwarderLogic + ) AutomationRegistryBase2_2(mode, link, linkNativeFeed, fastGasFeed, automationForwarderLogic) {} + + // ================================================================ + // | UPKEEP MANAGEMENT | + // ================================================================ + + /** + * @notice transfers the address of an admin for an upkeep + */ + function transferUpkeepAdmin(uint256 id, address proposed) external { + _requireAdminAndNotCancelled(id); + if (proposed == msg.sender) revert ValueNotChanged(); + + if (s_proposedAdmin[id] != proposed) { + s_proposedAdmin[id] = proposed; + emit UpkeepAdminTransferRequested(id, msg.sender, proposed); + } + } + + /** + * @notice accepts the transfer of an upkeep admin + */ + function acceptUpkeepAdmin(uint256 id) external { + Upkeep memory upkeep = s_upkeep[id]; + if (upkeep.maxValidBlocknumber != UINT32_MAX) revert UpkeepCancelled(); + if (s_proposedAdmin[id] != msg.sender) revert OnlyCallableByProposedAdmin(); + address past = s_upkeepAdmin[id]; + s_upkeepAdmin[id] = msg.sender; + s_proposedAdmin[id] = ZERO_ADDRESS; + + emit UpkeepAdminTransferred(id, past, msg.sender); + } + + /** + * @notice pauses an upkeep - an upkeep will be neither checked nor performed while paused + */ + function pauseUpkeep(uint256 id) external { + _requireAdminAndNotCancelled(id); + Upkeep memory upkeep = s_upkeep[id]; + if (upkeep.paused) revert OnlyUnpausedUpkeep(); + s_upkeep[id].paused = true; + s_upkeepIDs.remove(id); + emit UpkeepPaused(id); + } + + /** + * @notice unpauses an upkeep + */ + function unpauseUpkeep(uint256 id) external { + _requireAdminAndNotCancelled(id); + Upkeep memory upkeep = s_upkeep[id]; + if (!upkeep.paused) revert OnlyPausedUpkeep(); + s_upkeep[id].paused = false; + s_upkeepIDs.add(id); + emit UpkeepUnpaused(id); + } + + /** + * @notice updates the checkData for an upkeep + */ + function setUpkeepCheckData(uint256 id, bytes calldata newCheckData) external { + _requireAdminAndNotCancelled(id); + if (newCheckData.length > s_storage.maxCheckDataSize) revert CheckDataExceedsLimit(); + s_checkData[id] = newCheckData; + emit UpkeepCheckDataSet(id, newCheckData); + } + + /** + * @notice updates the gas limit for an upkeep + */ + function setUpkeepGasLimit(uint256 id, uint32 gasLimit) external { + if (gasLimit < PERFORM_GAS_MIN || gasLimit > s_storage.maxPerformGas) revert GasLimitOutsideRange(); + _requireAdminAndNotCancelled(id); + s_upkeep[id].performGas = gasLimit; + + emit UpkeepGasLimitSet(id, gasLimit); + } + + /** + * @notice updates the offchain config for an upkeep + */ + function setUpkeepOffchainConfig(uint256 id, bytes calldata config) external { + _requireAdminAndNotCancelled(id); + s_upkeepOffchainConfig[id] = config; + emit UpkeepOffchainConfigSet(id, config); + } + + /** + * @notice withdraws LINK funds from an upkeep + * @dev note that an upkeep must be cancelled first!! + */ + function withdrawFunds(uint256 id, address to) external nonReentrant { + if (to == ZERO_ADDRESS) revert InvalidRecipient(); + Upkeep memory upkeep = s_upkeep[id]; + if (s_upkeepAdmin[id] != msg.sender) revert OnlyCallableByAdmin(); + if (upkeep.maxValidBlocknumber > _blockNum()) revert UpkeepNotCanceled(); + uint96 amountToWithdraw = s_upkeep[id].balance; + s_expectedLinkBalance = s_expectedLinkBalance - amountToWithdraw; + s_upkeep[id].balance = 0; + i_link.transfer(to, amountToWithdraw); + emit FundsWithdrawn(id, amountToWithdraw, to); + } + + // ================================================================ + // | NODE MANAGEMENT | + // ================================================================ + + /** + * @notice transfers the address of payee for a transmitter + */ + function transferPayeeship(address transmitter, address proposed) external { + if (s_transmitterPayees[transmitter] != msg.sender) revert OnlyCallableByPayee(); + if (proposed == msg.sender) revert ValueNotChanged(); + + if (s_proposedPayee[transmitter] != proposed) { + s_proposedPayee[transmitter] = proposed; + emit PayeeshipTransferRequested(transmitter, msg.sender, proposed); + } + } + + /** + * @notice accepts the transfer of the payee + */ + function acceptPayeeship(address transmitter) external { + if (s_proposedPayee[transmitter] != msg.sender) revert OnlyCallableByProposedPayee(); + address past = s_transmitterPayees[transmitter]; + s_transmitterPayees[transmitter] = msg.sender; + s_proposedPayee[transmitter] = ZERO_ADDRESS; + + emit PayeeshipTransferred(transmitter, past, msg.sender); + } + + /** + * @notice withdraws LINK received as payment for work performed + */ + function withdrawPayment(address from, address to) external { + if (to == ZERO_ADDRESS) revert InvalidRecipient(); + if (s_transmitterPayees[from] != msg.sender) revert OnlyCallableByPayee(); + uint96 balance = _updateTransmitterBalanceFromPool(from, s_hotVars.totalPremium, uint96(s_transmittersList.length)); + s_transmitters[from].balance = 0; + s_expectedLinkBalance = s_expectedLinkBalance - balance; + i_link.transfer(to, balance); + emit PaymentWithdrawn(from, balance, to, msg.sender); + } + + // ================================================================ + // | OWNER / MANAGER ACTIONS | + // ================================================================ + + /** + * @notice sets the privilege config for an upkeep + */ + function setUpkeepPrivilegeConfig(uint256 upkeepId, bytes calldata newPrivilegeConfig) external { + if (msg.sender != s_storage.upkeepPrivilegeManager) { + revert OnlyCallableByUpkeepPrivilegeManager(); + } + s_upkeepPrivilegeConfig[upkeepId] = newPrivilegeConfig; + emit UpkeepPrivilegeConfigSet(upkeepId, newPrivilegeConfig); + } + + /** + * @notice withdraws the owner's LINK balance + */ + function withdrawOwnerFunds() external onlyOwner { + uint96 amount = s_storage.ownerLinkBalance; + s_expectedLinkBalance = s_expectedLinkBalance - amount; + s_storage.ownerLinkBalance = 0; + emit OwnerFundsWithdrawn(amount); + i_link.transfer(msg.sender, amount); + } + + /** + * @notice allows the owner to withdraw any LINK accidentally sent to the contract + */ + function recoverFunds() external onlyOwner { + uint256 total = i_link.balanceOf(address(this)); + i_link.transfer(msg.sender, total - s_expectedLinkBalance); + } + + /** + * @notice sets the payees for the transmitters + */ + function setPayees(address[] calldata payees) external onlyOwner { + if (s_transmittersList.length != payees.length) revert ParameterLengthError(); + for (uint256 i = 0; i < s_transmittersList.length; i++) { + address transmitter = s_transmittersList[i]; + address oldPayee = s_transmitterPayees[transmitter]; + address newPayee = payees[i]; + if ( + (newPayee == ZERO_ADDRESS) || (oldPayee != ZERO_ADDRESS && oldPayee != newPayee && newPayee != IGNORE_ADDRESS) + ) revert InvalidPayee(); + if (newPayee != IGNORE_ADDRESS) { + s_transmitterPayees[transmitter] = newPayee; + } + } + emit PayeesUpdated(s_transmittersList, payees); + } + + /** + * @notice sets the migration permission for a peer registry + * @dev this must be done before upkeeps can be migrated to/from another registry + */ + function setPeerRegistryMigrationPermission(address peer, MigrationPermission permission) external onlyOwner { + s_peerRegistryMigrationPermission[peer] = permission; + } + + /** + * @notice pauses the entire registry + */ + function pause() external onlyOwner { + s_hotVars.paused = true; + emit Paused(msg.sender); + } + + /** + * @notice unpauses the entire registry + */ + function unpause() external onlyOwner { + s_hotVars.paused = false; + emit Unpaused(msg.sender); + } + + /** + * @notice sets a generic bytes field used to indicate the privilege that this admin address had + * @param admin the address to set privilege for + * @param newPrivilegeConfig the privileges that this admin has + */ + function setAdminPrivilegeConfig(address admin, bytes calldata newPrivilegeConfig) external { + if (msg.sender != s_storage.upkeepPrivilegeManager) { + revert OnlyCallableByUpkeepPrivilegeManager(); + } + s_adminPrivilegeConfig[admin] = newPrivilegeConfig; + emit AdminPrivilegeConfigSet(admin, newPrivilegeConfig); + } + + // ================================================================ + // | GETTERS | + // ================================================================ + + function getConditionalGasOverhead() external pure returns (uint256) { + return REGISTRY_CONDITIONAL_OVERHEAD; + } + + function getLogGasOverhead() external pure returns (uint256) { + return REGISTRY_LOG_OVERHEAD; + } + + function getPerPerformByteGasOverhead() external pure returns (uint256) { + return REGISTRY_PER_PERFORM_BYTE_GAS_OVERHEAD; + } + + function getPerSignerGasOverhead() external pure returns (uint256) { + return REGISTRY_PER_SIGNER_GAS_OVERHEAD; + } + + function getCancellationDelay() external pure returns (uint256) { + return CANCELLATION_DELAY; + } + + function getMode() external view returns (Mode) { + return i_mode; + } + + function getLinkAddress() external view returns (address) { + return address(i_link); + } + + function getLinkNativeFeedAddress() external view returns (address) { + return address(i_linkNativeFeed); + } + + function getFastGasFeedAddress() external view returns (address) { + return address(i_fastGasFeed); + } + + function getAutomationForwarderLogic() external view returns (address) { + return i_automationForwarderLogic; + } + + function upkeepTranscoderVersion() public pure returns (UpkeepFormat) { + return UPKEEP_TRANSCODER_VERSION_BASE; + } + + function upkeepVersion() public pure returns (uint8) { + return UPKEEP_VERSION_BASE; + } + + /** + * @notice read all of the details about an upkeep + * @dev this function may be deprecated in a future version of automation in favor of individual + * getters for each field + */ + function getUpkeep(uint256 id) external view returns (UpkeepInfo memory upkeepInfo) { + Upkeep memory reg = s_upkeep[id]; + address target = address(reg.forwarder) == address(0) ? address(0) : reg.forwarder.getTarget(); + upkeepInfo = UpkeepInfo({ + target: target, + performGas: reg.performGas, + checkData: s_checkData[id], + balance: reg.balance, + admin: s_upkeepAdmin[id], + maxValidBlocknumber: reg.maxValidBlocknumber, + lastPerformedBlockNumber: reg.lastPerformedBlockNumber, + amountSpent: reg.amountSpent, + paused: reg.paused, + offchainConfig: s_upkeepOffchainConfig[id] + }); + return upkeepInfo; + } + + /** + * @notice retrieve active upkeep IDs. Active upkeep is defined as an upkeep which is not paused and not canceled. + * @param startIndex starting index in list + * @param maxCount max count to retrieve (0 = unlimited) + * @dev the order of IDs in the list is **not guaranteed**, therefore, if making successive calls, one + * should consider keeping the blockheight constant to ensure a holistic picture of the contract state + */ + function getActiveUpkeepIDs(uint256 startIndex, uint256 maxCount) external view returns (uint256[] memory) { + uint256 numUpkeeps = s_upkeepIDs.length(); + if (startIndex >= numUpkeeps) revert IndexOutOfRange(); + uint256 endIndex = startIndex + maxCount; + endIndex = endIndex > numUpkeeps || maxCount == 0 ? numUpkeeps : endIndex; + uint256[] memory ids = new uint256[](endIndex - startIndex); + for (uint256 idx = 0; idx < ids.length; idx++) { + ids[idx] = s_upkeepIDs.at(idx + startIndex); + } + return ids; + } + + /** + * @notice returns the upkeep's trigger type + */ + function getTriggerType(uint256 upkeepId) external pure returns (Trigger) { + return _getTriggerType(upkeepId); + } + + /** + * @notice returns the trigger config for an upkeeep + */ + function getUpkeepTriggerConfig(uint256 upkeepId) public view returns (bytes memory) { + return s_upkeepTriggerConfig[upkeepId]; + } + + /** + * @notice read the current info about any transmitter address + */ + function getTransmitterInfo( + address query + ) external view returns (bool active, uint8 index, uint96 balance, uint96 lastCollected, address payee) { + Transmitter memory transmitter = s_transmitters[query]; + + uint96 pooledShare = 0; + if (transmitter.active) { + uint96 totalDifference = s_hotVars.totalPremium - transmitter.lastCollected; + pooledShare = totalDifference / uint96(s_transmittersList.length); + } + + return ( + transmitter.active, + transmitter.index, + (transmitter.balance + pooledShare), + transmitter.lastCollected, + s_transmitterPayees[query] + ); + } + + /** + * @notice read the current info about any signer address + */ + function getSignerInfo(address query) external view returns (bool active, uint8 index) { + Signer memory signer = s_signers[query]; + return (signer.active, signer.index); + } + + /** + * @notice read the current state of the registry + */ + function getState() + external + view + returns ( + State memory state, + OnchainConfig memory config, + address[] memory signers, + address[] memory transmitters, + uint8 f + ) + { + state = State({ + nonce: s_storage.nonce, + ownerLinkBalance: s_storage.ownerLinkBalance, + expectedLinkBalance: s_expectedLinkBalance, + totalPremium: s_hotVars.totalPremium, + numUpkeeps: s_upkeepIDs.length(), + configCount: s_storage.configCount, + latestConfigBlockNumber: s_storage.latestConfigBlockNumber, + latestConfigDigest: s_latestConfigDigest, + latestEpoch: s_hotVars.latestEpoch, + paused: s_hotVars.paused + }); + + config = OnchainConfig({ + paymentPremiumPPB: s_hotVars.paymentPremiumPPB, + flatFeeMicroLink: s_hotVars.flatFeeMicroLink, + checkGasLimit: s_storage.checkGasLimit, + stalenessSeconds: s_hotVars.stalenessSeconds, + gasCeilingMultiplier: s_hotVars.gasCeilingMultiplier, + minUpkeepSpend: s_storage.minUpkeepSpend, + maxPerformGas: s_storage.maxPerformGas, + maxCheckDataSize: s_storage.maxCheckDataSize, + maxPerformDataSize: s_storage.maxPerformDataSize, + maxRevertDataSize: s_storage.maxRevertDataSize, + fallbackGasPrice: s_fallbackGasPrice, + fallbackLinkPrice: s_fallbackLinkPrice, + transcoder: s_storage.transcoder, + registrars: s_registrars.values(), + upkeepPrivilegeManager: s_storage.upkeepPrivilegeManager, + reorgProtectionEnabled: s_hotVars.reorgProtectionEnabled + }); + + return (state, config, s_signersList, s_transmittersList, s_hotVars.f); + } + + /** + * @notice calculates the minimum balance required for an upkeep to remain eligible + * @param id the upkeep id to calculate minimum balance for + */ + function getBalance(uint256 id) external view returns (uint96 balance) { + return s_upkeep[id].balance; + } + + /** + * @notice calculates the minimum balance required for an upkeep to remain eligible + * @param id the upkeep id to calculate minimum balance for + */ + function getMinBalance(uint256 id) external view returns (uint96) { + return getMinBalanceForUpkeep(id); + } + + /** + * @notice calculates the minimum balance required for an upkeep to remain eligible + * @param id the upkeep id to calculate minimum balance for + * @dev this will be deprecated in a future version in favor of getMinBalance + */ + function getMinBalanceForUpkeep(uint256 id) public view returns (uint96 minBalance) { + return getMaxPaymentForGas(_getTriggerType(id), s_upkeep[id].performGas); + } + + /** + * @notice calculates the maximum payment for a given gas limit + * @param gasLimit the gas to calculate payment for + */ + function getMaxPaymentForGas(Trigger triggerType, uint32 gasLimit) public view returns (uint96 maxPayment) { + HotVars memory hotVars = s_hotVars; + (uint256 fastGasWei, uint256 linkNative) = _getFeedData(hotVars); + return + _getMaxLinkPayment(hotVars, triggerType, gasLimit, s_storage.maxPerformDataSize, fastGasWei, linkNative, false); + } + + /** + * @notice retrieves the migration permission for a peer registry + */ + function getPeerRegistryMigrationPermission(address peer) external view returns (MigrationPermission) { + return s_peerRegistryMigrationPermission[peer]; + } + + /** + * @notice returns the upkeep privilege config + */ + function getUpkeepPrivilegeConfig(uint256 upkeepId) external view returns (bytes memory) { + return s_upkeepPrivilegeConfig[upkeepId]; + } + + /** + * @notice returns the upkeep privilege config + */ + function getAdminPrivilegeConfig(address admin) external view returns (bytes memory) { + return s_adminPrivilegeConfig[admin]; + } + + /** + * @notice returns the upkeep's forwarder contract + */ + function getForwarder(uint256 upkeepID) external view returns (IAutomationForwarder) { + return s_upkeep[upkeepID].forwarder; + } + + /** + * @notice returns the upkeep's forwarder contract + */ + function hasDedupKey(bytes32 dedupKey) external view returns (bool) { + return s_dedupKeys[dedupKey]; + } +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/AutomationUtils2_2.sol b/contracts/src/v0.8/automation/dev/v2_2/AutomationUtils2_2.sol new file mode 100644 index 00000000000..2b8fd8df6ac --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/AutomationUtils2_2.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.16; + +import {AutomationRegistryBase2_2} from "./AutomationRegistryBase2_2.sol"; +import {Log} from "../../interfaces/ILogAutomation.sol"; + +/** + * @notice this file exposes structs that are otherwise internal to the automation registry + * doing this allows those structs to be encoded and decoded with type safety in offchain code + * and tests because generated wrappers are made available + */ + +/** + * @notice structure of trigger for log triggers + */ +struct LogTriggerConfig { + address contractAddress; + uint8 filterSelector; // denotes which topics apply to filter ex 000, 101, 111...only last 3 bits apply + bytes32 topic0; + bytes32 topic1; + bytes32 topic2; + bytes32 topic3; +} + +contract AutomationUtils2_2 { + /** + * @dev this can be removed as OnchainConfig is now exposed directly from the registry + */ + function _onChainConfig(AutomationRegistryBase2_2.OnchainConfig memory) external {} // 0x2ff92a81 + + function _report(AutomationRegistryBase2_2.Report memory) external {} // 0xe65d6546 + + function _logTriggerConfig(LogTriggerConfig memory) external {} // 0x21f373d7 + + function _logTrigger(AutomationRegistryBase2_2.LogTrigger memory) external {} // 0x1c8d8260 + + function _conditionalTrigger(AutomationRegistryBase2_2.ConditionalTrigger memory) external {} // 0x4b6df294 + + function _log(Log memory) external {} // 0xe9720a49 +} diff --git a/contracts/src/v0.8/automation/dev/v2_2/LICENSE b/contracts/src/v0.8/automation/dev/v2_2/LICENSE new file mode 100644 index 00000000000..9230d392a98 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/LICENSE @@ -0,0 +1,57 @@ +Business Source License 1.1 + +License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. +"Business Source License" is a trademark of MariaDB Corporation Ab. + +--- + +Parameters + +Licensor: SmartContract Chainlink Limited SEZC + +Licensed Work: Automation v2.2 +The Licensed Work is (c) 2024 SmartContract Chainlink Limited SEZC + +Additional Use Grant(s): +You may make use of Automation v2.1, v2.2 (which is available subject to the license here the “Licensed Work”) solely for purposes listed below: +https://github.com/smartcontractkit/chainlink-automation/tree/main/Automation_Grants.md + +Change Date: January 22, 2028 + +Change License: MIT + +--- + +Terms + +The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use. + +Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate. + +If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work. + +All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor. + +You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work. + +Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work. + +This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License). + +TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE. + +MariaDB hereby grants you permission to use this License’s text to license your works, and to refer to it using the trademark "Business Source License", as long as you comply with the Covenants of Licensor below. + +--- + +Covenants of Licensor + +In consideration of the right to use this License’s text and the "Business Source License" name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor: + +1. To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where "compatible" means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses without limitation. + +2. To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text "None". + +3. To specify a Change Date. + +4. Not to modify this License in any other way. diff --git a/contracts/src/v0.8/automation/dev/v2_2/README.md b/contracts/src/v0.8/automation/dev/v2_2/README.md new file mode 100644 index 00000000000..abd3eb0ca84 --- /dev/null +++ b/contracts/src/v0.8/automation/dev/v2_2/README.md @@ -0,0 +1,40 @@ +# Automation Contract Structure + +The on-chain component of Chainlink automation is too large to fit into the [size requirements][size-limit-eip] of a single contract. It is also too large to fit into 2 contracts, a solution that works for most large projects. Therefore, we included this explanation of how the pieces fit together and various tradeoffs incurred. + +### Glossary + +**Master Contract** - also known as the “storage” contract. This is the contract whose state we care about. It is the entry-point into the chain of delegatecalls. (We avoid the term "proxy" because it is commonly associated with upgradability, and this system _is not upgradable_ even though it relies on some of the same mechanics.) + +**Logic Contract** - this a contract whose sole purpose is to hold code. We use the code at this address and execute it in the context of the master contract in order to increase our total capacity for on-chain code. + +### Overview + +We chain multiple logic contracts together using [fallback functions][fallback] and [delegatecall][delegatecall]. If a function definition is not found on one contract, we fall back to the next, always executing the function in the scope of the master contract. The actual implementation of this is based off of [OZ's Proxy contract][oz-proxy]. + +### Diagram + +```mermaid +graph LR + Master -- delegatecall --> la[Logic A] + la -- delegatecall --> lb[Logic B] + lb -. delegatecall .-> lx[Logic X] +``` + +### Special Considerations + +- functions on the master contract have the least gas overhead, therefore, our most price-sensitive functions live there +- functions on the master contract have first-class support from tools like etherscan and tenderly - functions that we (or users) call often to debug should live there +- etherscan supports executing logic contract functions that are once removed from the master - therefore we give secondary preference to the first logic contract for user and debugging functions +- functions on logic A through logic X (as of writing) have no support on etherscan and will essentially be "invisible" to everyone but advanced users - we will try to reserve this space for uncommon interactions that are mostly done progamatically +- We use Logic A, B, C... to avoid confusion with the version ex `AutomationRegistryLogicA2_2.sol` --> Logic Contract A verion 2.1 +- Storage locations for logic contract addresses MUST BE BYTECODE (this is done by marking them as "immutable") otherwise the chaining mechanism will break + +### Master Interface + +The Master Interface is a deduped combination of all the interfaces from all contracts in the chain. We generate this interface programatically using the script `generate-automation-master-interface.ts`. This process is not a hardened one. Users of this script should take great care to ensure it's efficacy. + +[size-limit-eip]: https://eips.ethereum.org/EIPS/eip-170 +[fallback]: https://docs.soliditylang.org/en/v0.8.12/contracts.html#fallback-function +[delegatecall]: https://docs.soliditylang.org/en/v0.8.12/introduction-to-smart-contracts.html?highlight=delegatecall#delegatecall-callcode-and-libraries +[oz-proxy]: https://docs.openzeppelin.com/contracts/4.x/api/proxy#Proxy diff --git a/contracts/src/v0.8/automation/libraries/internal/Cron.sol b/contracts/src/v0.8/automation/libraries/internal/Cron.sol index fe72c412b60..ae4f90d0d71 100644 --- a/contracts/src/v0.8/automation/libraries/internal/Cron.sol +++ b/contracts/src/v0.8/automation/libraries/internal/Cron.sol @@ -84,6 +84,7 @@ struct Field { * abstraction called a Spec. The library also includes a spec function, nextTick(), which * determines the next time a cron job should fire based on the current block timestamp. */ +// solhint-disable chainlink-solidity/prefix-internal-functions-with-underscore, no-global-import library Cron { using strings for *; diff --git a/contracts/src/v0.8/automation/v2_1/test/AutomationForwarder.t.sol b/contracts/src/v0.8/automation/test/AutomationForwarder.t.sol similarity index 88% rename from contracts/src/v0.8/automation/v2_1/test/AutomationForwarder.t.sol rename to contracts/src/v0.8/automation/test/AutomationForwarder.t.sol index 078d22d6c96..aee2fcfbd29 100644 --- a/contracts/src/v0.8/automation/v2_1/test/AutomationForwarder.t.sol +++ b/contracts/src/v0.8/automation/test/AutomationForwarder.t.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.16; -import {IAutomationRegistryConsumer} from "../../interfaces/IAutomationRegistryConsumer.sol"; -import {IAutomationForwarder} from "../../interfaces/IAutomationForwarder.sol"; +import {IAutomationRegistryConsumer} from "../interfaces/IAutomationRegistryConsumer.sol"; +import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; import {AutomationForwarder} from "../AutomationForwarder.sol"; import {AutomationForwarderLogic} from "../AutomationForwarderLogic.sol"; -import {MockKeeperRegistry2_1} from "../../mocks/MockKeeperRegistry2_1.sol"; -import {UpkeepCounter} from "../../testhelpers/UpkeepCounter.sol"; +import {MockKeeperRegistry2_1} from "../mocks/MockKeeperRegistry2_1.sol"; +import {UpkeepCounter} from "../testhelpers/UpkeepCounter.sol"; import {BaseTest} from "./BaseTest.t.sol"; // in contracts directory, run -// forge test --match-path src/v0.8/automation/v2_1/test/AutomationForwarder.t.sol +// forge test --match-path src/v0.8/automation/test/AutomationForwarder.t.sol contract AutomationForwarderSetUp is BaseTest { IAutomationForwarder internal forwarder; diff --git a/contracts/src/v0.8/automation/test/BaseTest.t.sol b/contracts/src/v0.8/automation/test/BaseTest.t.sol index bcde8a11480..ecba6521c64 100644 --- a/contracts/src/v0.8/automation/test/BaseTest.t.sol +++ b/contracts/src/v0.8/automation/test/BaseTest.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.6; +pragma solidity ^0.8.0; import "forge-std/Test.sol"; diff --git a/contracts/src/v0.8/automation/v2_1/test/StructFactory.sol b/contracts/src/v0.8/automation/test/StructFactory.sol similarity index 85% rename from contracts/src/v0.8/automation/v2_1/test/StructFactory.sol rename to contracts/src/v0.8/automation/test/StructFactory.sol index 83bb9e89050..9317244a31e 100644 --- a/contracts/src/v0.8/automation/v2_1/test/StructFactory.sol +++ b/contracts/src/v0.8/automation/test/StructFactory.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.16; +pragma solidity ^0.8.0; contract StructFactory { address internal OWNER; diff --git a/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol b/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol index 563c1354b66..979cc6138ac 100644 --- a/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol +++ b/contracts/src/v0.8/automation/testhelpers/SimpleLogUpkeepCounter.sol @@ -4,6 +4,12 @@ pragma solidity 0.8.6; import {ILogAutomation, Log} from "../interfaces/ILogAutomation.sol"; +struct CheckData { + uint256 checkBurnAmount; + uint256 performBurnAmount; + bytes32 eventSig; +} + contract SimpleLogUpkeepCounter is ILogAutomation { event PerformingUpkeep( address indexed from, @@ -11,14 +17,17 @@ contract SimpleLogUpkeepCounter is ILogAutomation { uint256 lastBlock, uint256 previousBlock, uint256 counter, - uint256 timeToPerform + uint256 timeToPerform, + bool isRecovered ); + mapping(bytes32 => bool) public dummyMap; // used to force storage lookup uint256 public lastBlock; uint256 public previousPerformBlock; uint256 public initialBlock; uint256 public counter; uint256 public timeToPerform; + bool public isRecovered; constructor() { previousPerformBlock = 0; @@ -27,8 +36,27 @@ contract SimpleLogUpkeepCounter is ILogAutomation { counter = 0; } - function checkLog(Log calldata log, bytes memory) external view override returns (bool, bytes memory) { - return (true, abi.encode(log)); + function _checkDataConfig(CheckData memory) external {} + + function checkLog(Log calldata log, bytes calldata checkData) external view override returns (bool, bytes memory) { + (uint256 checkBurnAmount, uint256 performBurnAmount, bytes32 eventSig) = abi.decode( + checkData, + (uint256, uint256, bytes32) + ); + uint256 startGas = gasleft(); + bytes32 dummyIndex = blockhash(block.number - 1); + bool dummy; + // burn gas + if (checkBurnAmount > 0) { + while (startGas - gasleft() < checkBurnAmount) { + dummy = dummy && dummyMap[dummyIndex]; // arbitrary storage reads + dummyIndex = keccak256(abi.encode(dummyIndex, address(this))); + } + } + if (log.topics[2] == eventSig) { + return (true, abi.encode(log, block.number, checkData)); + } + return (false, abi.encode(log, block.number, checkData)); } function performUpkeep(bytes calldata performData) external override { @@ -38,8 +66,34 @@ contract SimpleLogUpkeepCounter is ILogAutomation { lastBlock = block.number; counter = counter + 1; previousPerformBlock = lastBlock; - Log memory log = abi.decode(performData, (Log)); + (Log memory log, uint256 checkBlock, bytes memory extraData) = abi.decode(performData, (Log, uint256, bytes)); timeToPerform = block.timestamp - log.timestamp; - emit PerformingUpkeep(tx.origin, initialBlock, lastBlock, previousPerformBlock, counter, timeToPerform); + isRecovered = false; + if (checkBlock != log.blockNumber) { + isRecovered = true; + } + (uint256 checkBurnAmount, uint256 performBurnAmount, bytes32 eventSig) = abi.decode( + extraData, + (uint256, uint256, bytes32) + ); + uint256 startGas = gasleft(); + bytes32 dummyIndex = blockhash(block.number - 1); + bool dummy; + // burn gas + if (performBurnAmount > 0) { + while (startGas - gasleft() < performBurnAmount) { + dummy = dummy && dummyMap[dummyIndex]; // arbitrary storage reads + dummyIndex = keccak256(abi.encode(dummyIndex, address(this))); + } + } + emit PerformingUpkeep( + tx.origin, + initialBlock, + lastBlock, + previousPerformBlock, + counter, + timeToPerform, + isRecovered + ); } } diff --git a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol index 9b9dc2d6b7d..b858800d73a 100644 --- a/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol +++ b/contracts/src/v0.8/automation/upkeeps/LinkAvailableBalanceMonitor.sol @@ -3,7 +3,9 @@ pragma solidity 0.8.19; import {AutomationCompatibleInterface} from "../interfaces/AutomationCompatibleInterface.sol"; -import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {AccessControl} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/access/AccessControl.sol"; +import {EnumerableMap} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableMap.sol"; +import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; import {Pausable} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/security/Pausable.sol"; @@ -33,7 +35,10 @@ interface ILinkAvailable { /// this is a "trusless" upkeep, meaning it does not trust the caller of performUpkeep; /// we could save a fair amount of gas and re-write this upkeep for use with Automation v2.0+, /// which has significantly different trust assumptions -contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationCompatibleInterface { +contract LinkAvailableBalanceMonitor is AccessControl, AutomationCompatibleInterface, Pausable { + using EnumerableMap for EnumerableMap.UintToAddressMap; + using EnumerableSet for EnumerableSet.AddressSet; + event BalanceUpdated(address indexed addr, uint256 oldBalance, uint256 newBalance); event FundsWithdrawn(uint256 amountWithdrawn, address payee); event UpkeepIntervalSet(uint256 oldUpkeepInterval, uint256 newUpkeepInterval); @@ -54,6 +59,7 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp error InvalidUpkeepInterval(uint8 upkeepInterval); error InvalidLinkTokenAddress(address lt); error InvalidWatchList(); + error InvalidChainSelector(); error DuplicateAddress(address duplicate); struct MonitoredAddress { @@ -63,24 +69,49 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp bool isActive; } - IERC20 private immutable LINK_TOKEN; + bytes32 private constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); + bytes32 private constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); + uint96 private constant DEFAULT_TOP_UP_AMOUNT_JULES = 9000000000000000000; + uint96 private constant DEFAULT_MIN_BALANCE_JULES = 1000000000000000000; + IERC20 private immutable i_linkToken; + uint256 private s_minWaitPeriodSeconds; uint16 private s_maxPerform; uint16 private s_maxCheck; uint8 private s_upkeepInterval; - address[] private s_watchList; - mapping(address targetAddress => MonitoredAddress targetProperties) internal s_targets; - /// @param linkTokenAddress the LINK token address + /// @notice s_watchList contains all the addresses watched by this monitor + /// @dev It mainly provides the length() function + EnumerableSet.AddressSet private s_watchList; + + /// @notice s_targets contains all the addresses watched by this monitor + /// Each key points to a MonitoredAddress with all the needed metadata + mapping(address targetAddress => MonitoredAddress targetProperties) private s_targets; + + /// @notice s_onRampAddresses represents a list of CCIP onRamp addresses watched on this contract + /// There has to be only one onRamp per dstChainSelector. + /// dstChainSelector is needed as we have to track the live onRamp, and delete the onRamp + /// whenever a new one is deployed with the same dstChainSelector. + EnumerableMap.UintToAddressMap private s_onRampAddresses; + + /// @param admin is the administrator address of this contract + /// @param linkToken the LINK token address + /// @param minWaitPeriodSeconds represents the amount of time that has to wait a contract to be funded + /// @param maxPerform maximum amount of contracts to fund + /// @param maxCheck maximum amount of contracts to check + /// @param upkeepInterval randomizes the check for underfunded contracts constructor( - address linkTokenAddress, + address admin, + IERC20 linkToken, uint256 minWaitPeriodSeconds, uint16 maxPerform, uint16 maxCheck, uint8 upkeepInterval - ) ConfirmedOwner(msg.sender) { - if (linkTokenAddress == address(0)) revert InvalidLinkTokenAddress(linkTokenAddress); - LINK_TOKEN = IERC20(linkTokenAddress); + ) { + _setRoleAdmin(ADMIN_ROLE, ADMIN_ROLE); + _setRoleAdmin(EXECUTOR_ROLE, ADMIN_ROLE); + _grantRole(ADMIN_ROLE, admin); + i_linkToken = linkToken; setMinWaitPeriodSeconds(minWaitPeriodSeconds); setMaxPerform(maxPerform); setMaxCheck(maxCheck); @@ -94,18 +125,31 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp function setWatchList( address[] calldata addresses, uint96[] calldata minBalances, - uint96[] calldata topUpAmounts - ) external onlyOwner { - if (addresses.length != minBalances.length || addresses.length != topUpAmounts.length) { + uint96[] calldata topUpAmounts, + uint64[] calldata dstChainSelectors + ) external onlyAdminOrExecutor { + if ( + addresses.length != minBalances.length || + addresses.length != topUpAmounts.length || + addresses.length != dstChainSelectors.length + ) { revert InvalidWatchList(); } - for (uint256 idx = 0; idx < s_watchList.length; idx++) { - delete s_targets[s_watchList[idx]]; + for (uint256 idx = s_watchList.length(); idx > 0; idx--) { + address member = s_watchList.at(idx - 1); + s_watchList.remove(member); + delete s_targets[member]; + } + // s_onRampAddresses is not the same length as s_watchList, so it has + // to be clean in a separate loop + for (uint256 idx = 0; idx < s_onRampAddresses.length(); idx++) { + (uint256 key, ) = s_onRampAddresses.at(idx); + s_onRampAddresses.remove(key); } for (uint256 idx = 0; idx < addresses.length; idx++) { address targetAddress = addresses[idx]; - if (s_targets[targetAddress].isActive) revert DuplicateAddress(addresses[idx]); - if (addresses[idx] == address(0)) revert InvalidWatchList(); + if (s_targets[targetAddress].isActive) revert DuplicateAddress(targetAddress); + if (targetAddress == address(0)) revert InvalidWatchList(); if (topUpAmounts[idx] == 0) revert InvalidWatchList(); s_targets[targetAddress] = MonitoredAddress({ isActive: true, @@ -113,11 +157,55 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp topUpAmount: topUpAmounts[idx], lastTopUpTimestamp: 0 }); + if (dstChainSelectors[idx] > 0) { + s_onRampAddresses.set(dstChainSelectors[idx], targetAddress); + } + s_watchList.add(targetAddress); } - s_watchList = addresses; emit WatchlistUpdated(); } + /// @notice Adds a new address to the watchlist + /// @param targetAddress the address to be added to the watchlist + /// @param dstChainSelector carries a non-zero value in case the targetAddress is an onRamp, otherwise it carries a 0 + /// @dev this function has to be compatible with the event onRampSet(address, dstChainSelector) emitted by + /// the CCIP router. Important detail to know is this event is also emitted when an onRamp is decomissioned, + /// in which case it will carry the proper dstChainSelector along with the 0x0 address + function addToWatchListOrDecomission(address targetAddress, uint64 dstChainSelector) public onlyAdminOrExecutor { + if (s_targets[targetAddress].isActive) revert DuplicateAddress(targetAddress); + bool onRampExists = s_onRampAddresses.contains(dstChainSelector); + // if targetAddress is an existing onRamp, there's a need of cleaning the previous onRamp associated to this dstChainSelector + // there's no need to remove any other address that's not an onRamp + if (dstChainSelector > 0 && onRampExists) { + address oldAddress = s_onRampAddresses.get(dstChainSelector); + removeFromWatchList(oldAddress); + } + // only add the new address if it's not 0x0 + if (targetAddress != address(0)) { + s_onRampAddresses.set(dstChainSelector, targetAddress); + s_targets[targetAddress] = MonitoredAddress({ + isActive: true, + minBalance: DEFAULT_MIN_BALANCE_JULES, + topUpAmount: DEFAULT_TOP_UP_AMOUNT_JULES, + lastTopUpTimestamp: 0 + }); + s_watchList.add(targetAddress); + } else { + // if the address is 0x0, it means the onRamp has ben decomissioned and has to be cleaned + s_onRampAddresses.remove(dstChainSelector); + } + } + + /// @notice Delete an address from the watchlist and sets the target to inactive + /// @param targetAddress the address to be deleted + function removeFromWatchList(address targetAddress) public onlyAdminOrExecutor returns (bool) { + if (s_watchList.remove(targetAddress)) { + delete s_targets[targetAddress]; + return true; + } + return false; + } + /// @notice Gets a list of proxies that are underfunded, up to the s_maxPerform size /// @dev the function starts at a random index in the list to avoid biasing the first /// addresses in the list over latter ones. @@ -127,7 +215,7 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp function sampleUnderfundedAddresses() public view returns (address[] memory) { uint16 maxPerform = s_maxPerform; uint16 maxCheck = s_maxCheck; - uint256 numTargets = s_watchList.length; + uint256 numTargets = s_watchList.length(); uint256 idx = uint256(blockhash(block.number - (block.number % s_upkeepInterval) - 1)) % numTargets; uint256 numToCheck = numTargets < maxCheck ? numTargets : maxCheck; uint256 numFound = 0; @@ -138,7 +226,7 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp numChecked < numToCheck; (idx, numChecked) = ((idx + 1) % numTargets, numChecked + 1) ) { - address targetAddress = s_watchList[idx]; + address targetAddress = s_watchList.at(idx); target = s_targets[targetAddress]; if (_needsFunding(targetAddress, target.minBalance)) { targetsToFund[numFound] = targetAddress; @@ -156,17 +244,19 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp return targetsToFund; } + /// @notice tries to fund an array of target addresses, checking if they're underfunded in the process + /// @param targetAddresses is an array of contract addresses to be funded in case they're underfunded function topUp(address[] memory targetAddresses) public whenNotPaused { MonitoredAddress memory target; - uint256 localBalance = LINK_TOKEN.balanceOf(address(this)); + uint256 localBalance = i_linkToken.balanceOf(address(this)); for (uint256 idx = 0; idx < targetAddresses.length; idx++) { address targetAddress = targetAddresses[idx]; target = s_targets[targetAddress]; if (localBalance >= target.topUpAmount && _needsFunding(targetAddress, target.minBalance)) { - bool success = LINK_TOKEN.transfer(targetAddress, target.topUpAmount); + bool success = i_linkToken.transfer(targetAddress, target.topUpAmount); if (success) { localBalance -= target.topUpAmount; - target.lastTopUpTimestamp = uint56(block.timestamp); + s_targets[targetAddress].lastTopUpTimestamp = uint56(block.timestamp); emit TopUpSucceeded(targetAddress); } else { emit TopUpFailed(targetAddress); @@ -201,7 +291,9 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp } try target.linkAvailableForPayment() returns (int256 balance) { if ( - balance < int256(minBalance) && addressToCheck.lastTopUpTimestamp + s_minWaitPeriodSeconds <= block.timestamp + balance < int256(minBalance) && + addressToCheck.lastTopUpTimestamp + s_minWaitPeriodSeconds <= block.timestamp && + addressToCheck.isActive ) { return true; } @@ -231,14 +323,14 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp /// @notice Withdraws the contract balance in the LINK token. /// @param amount the amount of the LINK to withdraw /// @param payee the address to pay - function withdraw(uint256 amount, address payable payee) external onlyOwner { + function withdraw(uint256 amount, address payable payee) external onlyAdminOrExecutor { if (payee == address(0)) revert InvalidAddress(payee); - LINK_TOKEN.transfer(payee, amount); + i_linkToken.transfer(payee, amount); emit FundsWithdrawn(amount, payee); } /// @notice Sets the minimum balance for the given target address - function setMinBalance(address target, uint96 minBalance) external onlyOwner { + function setMinBalance(address target, uint96 minBalance) external onlyRole(ADMIN_ROLE) { if (target == address(0)) revert InvalidAddress(target); if (minBalance == 0) revert InvalidMinBalance(minBalance); if (!s_targets[target].isActive) revert InvalidWatchList(); @@ -248,7 +340,7 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp } /// @notice Sets the minimum balance for the given target address - function setTopUpAmount(address target, uint96 topUpAmount) external onlyOwner { + function setTopUpAmount(address target, uint96 topUpAmount) external onlyRole(ADMIN_ROLE) { if (target == address(0)) revert InvalidAddress(target); if (topUpAmount == 0) revert InvalidTopUpAmount(topUpAmount); if (!s_targets[target].isActive) revert InvalidWatchList(); @@ -258,28 +350,28 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp } /// @notice Update s_maxPerform - function setMaxPerform(uint16 maxPerform) public onlyOwner { - s_maxPerform = maxPerform; + function setMaxPerform(uint16 maxPerform) public onlyRole(ADMIN_ROLE) { emit MaxPerformSet(s_maxPerform, maxPerform); + s_maxPerform = maxPerform; } /// @notice Update s_maxCheck - function setMaxCheck(uint16 maxCheck) public onlyOwner { - s_maxCheck = maxCheck; + function setMaxCheck(uint16 maxCheck) public onlyRole(ADMIN_ROLE) { emit MaxCheckSet(s_maxCheck, maxCheck); + s_maxCheck = maxCheck; } /// @notice Sets the minimum wait period (in seconds) for addresses between funding - function setMinWaitPeriodSeconds(uint256 minWaitPeriodSeconds) public onlyOwner { - s_minWaitPeriodSeconds = minWaitPeriodSeconds; + function setMinWaitPeriodSeconds(uint256 minWaitPeriodSeconds) public onlyRole(ADMIN_ROLE) { emit MinWaitPeriodSet(s_minWaitPeriodSeconds, minWaitPeriodSeconds); + s_minWaitPeriodSeconds = minWaitPeriodSeconds; } /// @notice Update s_upkeepInterval - function setUpkeepInterval(uint8 upkeepInterval) public onlyOwner { + function setUpkeepInterval(uint8 upkeepInterval) public onlyRole(ADMIN_ROLE) { if (upkeepInterval > 255) revert InvalidUpkeepInterval(upkeepInterval); - s_upkeepInterval = upkeepInterval; emit UpkeepIntervalSet(s_upkeepInterval, upkeepInterval); + s_upkeepInterval = upkeepInterval; } /// @notice Gets maxPerform @@ -304,7 +396,13 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp /// @notice Gets the list of subscription ids being watched function getWatchList() external view returns (address[] memory) { - return s_watchList; + return s_watchList.values(); + } + + /// @notice Gets the onRamp address with the specified dstChainSelector + function getOnRampAddressAtChainSelector(uint64 dstChainSelector) external view returns (address) { + if (dstChainSelector == 0) revert InvalidChainSelector(); + return s_onRampAddresses.get(dstChainSelector); } /// @notice Gets configuration information for an address on the watchlist @@ -315,13 +413,23 @@ contract LinkAvailableBalanceMonitor is ConfirmedOwner, Pausable, AutomationComp return (target.isActive, target.minBalance, target.topUpAmount); } + /// @dev Modifier to make a function callable only by executor role or the + /// admin role. + modifier onlyAdminOrExecutor() { + address sender = _msgSender(); + if (!hasRole(ADMIN_ROLE, sender)) { + _checkRole(EXECUTOR_ROLE, sender); + } + _; + } + /// @notice Pause the contract, which prevents executing performUpkeep - function pause() external onlyOwner { + function pause() external onlyRole(ADMIN_ROLE) { _pause(); } /// @notice Unpause the contract - function unpause() external onlyOwner { + function unpause() external onlyRole(ADMIN_ROLE) { _unpause(); } } diff --git a/contracts/src/v0.8/automation/v2_1/KeeperRegistryLogicA2_1.sol b/contracts/src/v0.8/automation/v2_1/KeeperRegistryLogicA2_1.sol index e3845ce63bd..517d14d8c9b 100644 --- a/contracts/src/v0.8/automation/v2_1/KeeperRegistryLogicA2_1.sol +++ b/contracts/src/v0.8/automation/v2_1/KeeperRegistryLogicA2_1.sol @@ -6,7 +6,7 @@ import {Address} from "../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils import {KeeperRegistryBase2_1} from "./KeeperRegistryBase2_1.sol"; import {KeeperRegistryLogicB2_1} from "./KeeperRegistryLogicB2_1.sol"; import {Chainable} from "../Chainable.sol"; -import {AutomationForwarder} from "./AutomationForwarder.sol"; +import {AutomationForwarder} from "../AutomationForwarder.sol"; import {IAutomationForwarder} from "../interfaces/IAutomationForwarder.sol"; import {UpkeepTranscoderInterfaceV2} from "../interfaces/UpkeepTranscoderInterfaceV2.sol"; import {MigratableKeeperRegistryInterfaceV2} from "../interfaces/MigratableKeeperRegistryInterfaceV2.sol"; diff --git a/contracts/src/v0.8/automation/v2_1/LICENSE b/contracts/src/v0.8/automation/v2_1/LICENSE index 7d09d647f5b..f60ab657175 100644 --- a/contracts/src/v0.8/automation/v2_1/LICENSE +++ b/contracts/src/v0.8/automation/v2_1/LICENSE @@ -12,7 +12,8 @@ Licensor: SmartContract Chainlink Limited SEZC Licensed Work: Automation v2.1 The Licensed Work is (c) 2023 SmartContract Chainlink Limited SEZC -Additional Use Grant: Any uses listed and defined at https://github.com/smartcontractkit/chainlink-automation/tree/main/pkg/v3/Automation_v2.1_Grants.md +Additional Use Grant: Any uses listed and defined at https://github.com/smartcontractkit/chainlink-automation/tree/main/Automation_Grants.md + Change Date: September 12, 2027 diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol index cb4f2f45677..c3f351e6c76 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import {IFunctionsSubscriptions} from "./interfaces/IFunctionsSubscriptions.sol"; import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; -import {IFunctionsBilling} from "./interfaces/IFunctionsBilling.sol"; +import {IFunctionsBilling, FunctionsBillingConfig} from "./interfaces/IFunctionsBilling.sol"; import {Routable} from "./Routable.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; @@ -37,25 +37,9 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { event CommitmentDeleted(bytes32 requestId); - // ================================================================ - // | Configuration state | - // ================================================================ - - struct Config { - uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) - uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. - uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. - uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. - uint72 donFee; // ║ Additional flat fee (in Juels of LINK) that will be split between Node Operators. Max value is 2^80 - 1 == 1.2m LINK. - uint40 minimumEstimateGasPriceWei; // ║ The lowest amount of wei that will be used as the tx.gasprice when estimating the cost to fulfill the request - uint16 maxSupportedRequestDataVersion; // ═══════╝ The highest support request data version supported by the node. All lower versions should also be supported. - uint224 fallbackNativePerUnitLink; // ═══════════╗ Fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale - uint32 requestTimeoutSeconds; // ════════════════╝ How many seconds it takes before we consider a request to be timed out - } - - Config private s_config; + FunctionsBillingConfig private s_config; - event ConfigUpdated(Config config); + event ConfigUpdated(FunctionsBillingConfig config); error UnsupportedRequestDataVersion(); error InsufficientBalance(); @@ -81,7 +65,7 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // ================================================================ // | Initialization | // ================================================================ - constructor(address router, Config memory config, address linkToNativeFeed) Routable(router) { + constructor(address router, FunctionsBillingConfig memory config, address linkToNativeFeed) Routable(router) { s_linkToNativeFeed = AggregatorV3Interface(linkToNativeFeed); updateConfig(config); @@ -93,13 +77,13 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { /// @notice Gets the Chainlink Coordinator's billing configuration /// @return config - function getConfig() external view returns (Config memory) { + function getConfig() external view returns (FunctionsBillingConfig memory) { return s_config; } /// @notice Sets the Chainlink Coordinator's billing configuration - /// @param config - See the contents of the Config struct in IFunctionsBilling.Config for more information - function updateConfig(Config memory config) public { + /// @param config - See the contents of the FunctionsBillingConfig struct in IFunctionsBilling.sol for more information + function updateConfig(FunctionsBillingConfig memory config) public { _onlyOwner(); s_config = config; @@ -122,7 +106,7 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { /// @inheritdoc IFunctionsBilling function getWeiPerUnitLink() public view returns (uint256) { - Config memory config = s_config; + FunctionsBillingConfig memory config = s_config; (, int256 weiPerUnitLink, , uint256 timestamp, ) = s_linkToNativeFeed.latestRoundData(); // solhint-disable-next-line not-rely-on-time if (config.feedStalenessSeconds < block.timestamp - timestamp && config.feedStalenessSeconds > 0) { @@ -199,7 +183,7 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { function _startBilling( FunctionsResponse.RequestMeta memory request ) internal returns (FunctionsResponse.Commitment memory commitment) { - Config memory config = s_config; + FunctionsBillingConfig memory config = s_config; // Nodes should support all past versions of the structure if (request.dataVersion > config.maxSupportedRequestDataVersion) { diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol index 16e9029ce3f..33c45c218d4 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.19; import {IFunctionsCoordinator} from "./interfaces/IFunctionsCoordinator.sol"; import {ITypeAndVersion} from "../../../shared/interfaces/ITypeAndVersion.sol"; -import {FunctionsBilling} from "./FunctionsBilling.sol"; +import {FunctionsBilling, FunctionsBillingConfig} from "./FunctionsBilling.sol"; import {OCR2Base} from "./ocr/OCR2Base.sol"; import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; @@ -17,7 +17,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli /// @inheritdoc ITypeAndVersion // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - string public constant override typeAndVersion = "Functions Coordinator v1.1.0"; + string public constant override typeAndVersion = "Functions Coordinator v1.2.0"; event OracleRequest( bytes32 indexed requestId, @@ -42,7 +42,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli constructor( address router, - Config memory config, + FunctionsBillingConfig memory config, address linkToNativeFeed ) OCR2Base() FunctionsBilling(router, config, linkToNativeFeed) {} diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol index 2e12a75679a..d86d881151c 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsRouter.sol @@ -19,7 +19,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, using FunctionsResponse for FunctionsResponse.FulfillResult; // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - string public constant override typeAndVersion = "Functions Router v1.0.0"; + string public constant override typeAndVersion = "Functions Router v2.0.0"; // We limit return data to a selector plus 4 words. This is to avoid // malicious contracts from returning large amounts of data and causing @@ -90,7 +90,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, uint72 adminFee; // ║ Flat fee (in Juels of LINK) that will be paid to the Router owner for operation of the network bytes4 handleOracleFulfillmentSelector; // ║ The function selector that is used when calling back to the Client contract uint16 gasForCallExactCheck; // ════════════════╝ Used during calling back to the client. Ensures we have at least enough gas to be able to revert if gasAmount > 63//64*gas available. - uint32[] maxCallbackGasLimits; // ══════════════╸ List of max callback gas limits used by flag with GAS_FLAG_INDEX + uint32[] maxCallbackGasLimits; // ══════════════╸ List of max callback gas limits used by flag with MAX_CALLBACK_GAS_LIMIT_FLAGS_INDEX uint16 subscriptionDepositMinimumRequests; //═══╗ Amount of requests that must be completed before the full subscription balance will be released when closing a subscription account. uint72 subscriptionDepositJuels; // ════════════╝ Amount of subscription funds that are held as a deposit until Config.subscriptionDepositMinimumRequests are made using the subscription. } @@ -306,7 +306,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, bytes memory response, bytes memory err, uint96 juelsPerGas, - uint96 costWithoutCallback, + uint96 costWithoutFulfillment, address transmitter, FunctionsResponse.Commitment memory commitment ) external override returns (FunctionsResponse.FulfillResult resultCode, uint96) { @@ -341,7 +341,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, { uint96 callbackCost = juelsPerGas * SafeCast.toUint96(commitment.callbackGasLimit); - uint96 totalCostJuels = commitment.adminFee + costWithoutCallback + callbackCost; + uint96 totalCostJuels = commitment.adminFee + costWithoutFulfillment + callbackCost; // Check that the subscription can still afford to fulfill the request if (totalCostJuels > getSubscription(commitment.subscriptionId).balance) { @@ -379,7 +379,7 @@ contract FunctionsRouter is IFunctionsRouter, FunctionsSubscriptions, Pausable, commitment.adminFee, juelsPerGas, SafeCast.toUint96(result.gasUsed), - costWithoutCallback + costWithoutFulfillment ); emit RequestProcessed({ diff --git a/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol index b36d063ad7d..3d93a3fef04 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/accessControl/TermsOfServiceAllowList.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {ITermsOfServiceAllowList} from "./interfaces/ITermsOfServiceAllowList.sol"; +import {ITermsOfServiceAllowList, TermsOfServiceAllowListConfig} from "./interfaces/ITermsOfServiceAllowList.sol"; import {IAccessController} from "../../../../shared/interfaces/IAccessController.sol"; import {ITypeAndVersion} from "../../../../shared/interfaces/ITypeAndVersion.sol"; @@ -17,10 +17,10 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, /// @inheritdoc ITypeAndVersion // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.0.0"; + string public constant override typeAndVersion = "Functions Terms of Service Allow List v1.1.0"; EnumerableSet.AddressSet private s_allowedSenders; - mapping(address => bool) private s_blockedSenders; + EnumerableSet.AddressSet private s_blockedSenders; event AddedAccess(address user); event BlockedAccess(address user); @@ -29,24 +29,17 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, error InvalidSignature(); error InvalidUsage(); error RecipientIsBlocked(); + error InvalidCalldata(); - // ================================================================ - // | Configuration state | - // ================================================================ - struct Config { - bool enabled; // ═════════════╗ When enabled, access will be checked against s_allowedSenders. When disabled, all access will be allowed. - address signerPublicKey; // ══╝ The key pair that needs to sign the acceptance data - } - - Config private s_config; + TermsOfServiceAllowListConfig private s_config; - event ConfigUpdated(Config config); + event ConfigUpdated(TermsOfServiceAllowListConfig config); // ================================================================ // | Initialization | // ================================================================ - constructor(Config memory config) ConfirmedOwner(msg.sender) { + constructor(TermsOfServiceAllowListConfig memory config) ConfirmedOwner(msg.sender) { updateConfig(config); } @@ -56,13 +49,13 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, /// @notice Gets the contracts's configuration /// @return config - function getConfig() external view returns (Config memory) { + function getConfig() external view returns (TermsOfServiceAllowListConfig memory) { return s_config; } /// @notice Sets the contracts's configuration - /// @param config - See the contents of the TermsOfServiceAllowList.Config struct for more information - function updateConfig(Config memory config) public onlyOwner { + /// @param config - See the contents of the TermsOfServiceAllowListConfig struct in ITermsOfServiceAllowList.sol for more information + function updateConfig(TermsOfServiceAllowListConfig memory config) public onlyOwner { s_config = config; emit ConfigUpdated(config); } @@ -78,7 +71,7 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, /// @inheritdoc ITermsOfServiceAllowList function acceptTermsOfService(address acceptor, address recipient, bytes32 r, bytes32 s, uint8 v) external override { - if (s_blockedSenders[recipient]) { + if (s_blockedSenders.contains(recipient)) { revert RecipientIsBlocked(); } @@ -99,8 +92,9 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, } // Add recipient to the allow list - s_allowedSenders.add(recipient); - emit AddedAccess(recipient); + if (s_allowedSenders.add(recipient)) { + emit AddedAccess(recipient); + } } /// @inheritdoc ITermsOfServiceAllowList @@ -108,6 +102,32 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, return s_allowedSenders.values(); } + /// @inheritdoc ITermsOfServiceAllowList + function getAllowedSendersCount() external view override returns (uint64) { + return uint64(s_allowedSenders.length()); + } + + /// @inheritdoc ITermsOfServiceAllowList + function getAllowedSendersInRange( + uint64 allowedSenderIdxStart, + uint64 allowedSenderIdxEnd + ) external view override returns (address[] memory allowedSenders) { + if ( + allowedSenderIdxStart > allowedSenderIdxEnd || + allowedSenderIdxEnd >= s_allowedSenders.length() || + s_allowedSenders.length() == 0 + ) { + revert InvalidCalldata(); + } + + allowedSenders = new address[]((allowedSenderIdxEnd - allowedSenderIdxStart) + 1); + for (uint256 i = 0; i <= allowedSenderIdxEnd - allowedSenderIdxStart; ++i) { + allowedSenders[i] = s_allowedSenders.at(uint256(allowedSenderIdxStart + i)); + } + + return allowedSenders; + } + /// @inheritdoc IAccessController function hasAccess(address user, bytes calldata /* data */) external view override returns (bool) { if (!s_config.enabled) { @@ -125,19 +145,45 @@ contract TermsOfServiceAllowList is ITermsOfServiceAllowList, IAccessController, if (!s_config.enabled) { return false; } - return s_blockedSenders[sender]; + return s_blockedSenders.contains(sender); } /// @inheritdoc ITermsOfServiceAllowList function blockSender(address sender) external override onlyOwner { s_allowedSenders.remove(sender); - s_blockedSenders[sender] = true; + s_blockedSenders.add(sender); emit BlockedAccess(sender); } /// @inheritdoc ITermsOfServiceAllowList function unblockSender(address sender) external override onlyOwner { - s_blockedSenders[sender] = false; + s_blockedSenders.remove(sender); emit UnblockedAccess(sender); } + + /// @inheritdoc ITermsOfServiceAllowList + function getBlockedSendersCount() external view override returns (uint64) { + return uint64(s_blockedSenders.length()); + } + + /// @inheritdoc ITermsOfServiceAllowList + function getBlockedSendersInRange( + uint64 blockedSenderIdxStart, + uint64 blockedSenderIdxEnd + ) external view override returns (address[] memory blockedSenders) { + if ( + blockedSenderIdxStart > blockedSenderIdxEnd || + blockedSenderIdxEnd >= s_blockedSenders.length() || + s_blockedSenders.length() == 0 + ) { + revert InvalidCalldata(); + } + + blockedSenders = new address[]((blockedSenderIdxEnd - blockedSenderIdxStart) + 1); + for (uint256 i = 0; i <= blockedSenderIdxEnd - blockedSenderIdxStart; ++i) { + blockedSenders[i] = s_blockedSenders.at(uint256(blockedSenderIdxStart + i)); + } + + return blockedSenders; + } } diff --git a/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol b/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol index af4daa18bc3..65db9c42b69 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol @@ -22,6 +22,22 @@ interface ITermsOfServiceAllowList { /// @return addresses - all allowed addresses function getAllAllowedSenders() external view returns (address[] memory); + /// @notice Get details about the total number of allowed senders + /// @return count - total number of allowed senders in the system + function getAllowedSendersCount() external view returns (uint64); + + /// @notice Retrieve a list of allowed senders using an inclusive range + /// @dev WARNING: getAllowedSendersInRange uses EnumerableSet .length() and .at() methods to iterate over the list + /// without the need for an extra mapping. These method can not guarantee the ordering when new elements are added. + /// Evaluate if eventual consistency will satisfy your usecase before using it. + /// @param allowedSenderIdxStart - index of the allowed sender to start the range at + /// @param allowedSenderIdxEnd - index of the allowed sender to end the range at + /// @return allowedSenders - allowed addresses in the range provided + function getAllowedSendersInRange( + uint64 allowedSenderIdxStart, + uint64 allowedSenderIdxEnd + ) external view returns (address[] memory allowedSenders); + /// @notice Allows access to the sender based on acceptance of the Terms of Service /// @param acceptor - The wallet address that has accepted the Terms of Service on the UI /// @param recipient - The recipient address that the acceptor is taking responsibility for @@ -37,4 +53,28 @@ interface ITermsOfServiceAllowList { /// @notice Re-allows a previously blocked sender to accept the Terms of Service /// @param sender - Address of the sender to unblock function unblockSender(address sender) external; + + /// @notice Get details about the total number of blocked senders + /// @return count - total number of blocked senders in the system + function getBlockedSendersCount() external view returns (uint64); + + /// @notice Retrieve a list of blocked senders using an inclusive range + /// @dev WARNING: getBlockedSendersInRange uses EnumerableSet .length() and .at() methods to iterate over the list + /// without the need for an extra mapping. These method can not guarantee the ordering when new elements are added. + /// Evaluate if eventual consistency will satisfy your usecase before using it. + /// @param blockedSenderIdxStart - index of the blocked sender to start the range at + /// @param blockedSenderIdxEnd - index of the blocked sender to end the range at + /// @return blockedSenders - blocked addresses in the range provided + function getBlockedSendersInRange( + uint64 blockedSenderIdxStart, + uint64 blockedSenderIdxEnd + ) external view returns (address[] memory blockedSenders); +} + +// ================================================================ +// | Configuration state | +// ================================================================ +struct TermsOfServiceAllowListConfig { + bool enabled; // ═════════════╗ When enabled, access will be checked against s_allowedSenders. When disabled, all access will be allowed. + address signerPublicKey; // ══╝ The key pair that needs to sign the acceptance data } diff --git a/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol index 6291d05e57c..0bd7817f779 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/interfaces/IFunctionsBilling.sol @@ -40,5 +40,22 @@ interface IFunctionsBilling { function oracleWithdraw(address recipient, uint96 amount) external; /// @notice Withdraw all LINK earned by Oracles through fulfilling requests + /// @dev transmitter addresses must support LINK tokens to avoid tokens from getting stuck as oracleWithdrawAll() calls will forward tokens directly to transmitters function oracleWithdrawAll() external; } + +// ================================================================ +// | Configuration state | +// ================================================================ + +struct FunctionsBillingConfig { + uint32 fulfillmentGasPriceOverEstimationBP; // ══╗ Percentage of gas price overestimation to account for changes in gas price between request and response. Held as basis points (one hundredth of 1 percentage point) + uint32 feedStalenessSeconds; // ║ How long before we consider the feed price to be stale and fallback to fallbackNativePerUnitLink. + uint32 gasOverheadBeforeCallback; // ║ Represents the average gas execution cost before the fulfillment callback. This amount is always billed for every request. + uint32 gasOverheadAfterCallback; // ║ Represents the average gas execution cost after the fulfillment callback. This amount is always billed for every request. + uint72 donFee; // ║ Additional flat fee (in Juels of LINK) that will be split between Node Operators. Max value is 2^80 - 1 == 1.2m LINK. + uint40 minimumEstimateGasPriceWei; // ║ The lowest amount of wei that will be used as the tx.gasprice when estimating the cost to fulfill the request + uint16 maxSupportedRequestDataVersion; // ═══════╝ The highest support request data version supported by the node. All lower versions should also be supported. + uint224 fallbackNativePerUnitLink; // ═══════════╗ Fallback NATIVE CURRENCY / LINK conversion rate if the data feed is stale + uint32 requestTimeoutSeconds; // ════════════════╝ How many seconds it takes before we consider a request to be timed out +} diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol index 739521c5305..66640003427 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol @@ -10,6 +10,8 @@ import {Routable} from "../../dev/v1_X/Routable.sol"; import {FunctionsRouterSetup, FunctionsSubscriptionSetup, FunctionsClientRequestSetup, FunctionsFulfillmentSetup, FunctionsMultipleFulfillmentsSetup} from "./Setup.t.sol"; +import {FunctionsBillingConfig} from "../../dev/v1_X/interfaces/IFunctionsBilling.sol"; + /// @notice #constructor contract FunctionsBilling_Constructor is FunctionsSubscriptionSetup { function test_Constructor_Success() public { @@ -25,7 +27,7 @@ contract FunctionsBilling_GetConfig is FunctionsRouterSetup { vm.stopPrank(); vm.startPrank(STRANGER_ADDRESS); - FunctionsBilling.Config memory config = s_functionsCoordinator.getConfig(); + FunctionsBillingConfig memory config = s_functionsCoordinator.getConfig(); assertEq(config.feedStalenessSeconds, getCoordinatorConfig().feedStalenessSeconds); assertEq(config.gasOverheadBeforeCallback, getCoordinatorConfig().gasOverheadBeforeCallback); assertEq(config.gasOverheadAfterCallback, getCoordinatorConfig().gasOverheadAfterCallback); @@ -39,12 +41,12 @@ contract FunctionsBilling_GetConfig is FunctionsRouterSetup { /// @notice #updateConfig contract FunctionsBilling_UpdateConfig is FunctionsRouterSetup { - FunctionsBilling.Config internal configToSet; + FunctionsBillingConfig internal configToSet; function setUp() public virtual override { FunctionsRouterSetup.setUp(); - configToSet = FunctionsBilling.Config({ + configToSet = FunctionsBillingConfig({ feedStalenessSeconds: getCoordinatorConfig().feedStalenessSeconds * 2, gasOverheadAfterCallback: getCoordinatorConfig().gasOverheadAfterCallback * 2, gasOverheadBeforeCallback: getCoordinatorConfig().gasOverheadBeforeCallback * 2, @@ -66,7 +68,7 @@ contract FunctionsBilling_UpdateConfig is FunctionsRouterSetup { s_functionsCoordinator.updateConfig(configToSet); } - event ConfigUpdated(FunctionsBilling.Config config); + event ConfigUpdated(FunctionsBillingConfig config); function test_UpdateConfig_Success() public { // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). @@ -79,7 +81,7 @@ contract FunctionsBilling_UpdateConfig is FunctionsRouterSetup { s_functionsCoordinator.updateConfig(configToSet); - FunctionsBilling.Config memory config = s_functionsCoordinator.getConfig(); + FunctionsBillingConfig memory config = s_functionsCoordinator.getConfig(); assertEq(config.feedStalenessSeconds, configToSet.feedStalenessSeconds); assertEq(config.gasOverheadAfterCallback, configToSet.gasOverheadAfterCallback); assertEq(config.gasOverheadBeforeCallback, configToSet.gasOverheadBeforeCallback); diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol index f6d3d41e632..c21a2c090f7 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol @@ -14,7 +14,7 @@ import {FunctionsRouterSetup, FunctionsDONSetup, FunctionsSubscriptionSetup} fro /// @notice #constructor contract FunctionsCoordinator_Constructor is FunctionsRouterSetup { function test_Constructor_Success() public { - assertEq(s_functionsCoordinator.typeAndVersion(), "Functions Coordinator v1.1.0"); + assertEq(s_functionsCoordinator.typeAndVersion(), "Functions Coordinator v1.2.0"); assertEq(s_functionsCoordinator.owner(), OWNER_ADDRESS); } } diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol index 081fe2f6649..43540ba02b8 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsRouter.t.sol @@ -21,7 +21,7 @@ import "forge-std/Vm.sol"; /// @notice #constructor contract FunctionsRouter_Constructor is FunctionsRouterSetup { function test_Constructor_Success() public { - assertEq(s_functionsRouter.typeAndVersion(), "Functions Router v1.0.0"); + assertEq(s_functionsRouter.typeAndVersion(), "Functions Router v2.0.0"); assertEq(s_functionsRouter.owner(), OWNER_ADDRESS); } } diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol index 5a54bcc84ca..907eadacd8e 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsSubscriptions.t.sol @@ -130,12 +130,8 @@ contract FunctionsSubscriptions_OwnerCancelSubscription is FunctionsSubscription contract FunctionsSubscriptions_RecoverFunds is FunctionsRouterSetup { event FundsRecovered(address to, uint256 amount); - function test_RecoverFunds_Success(uint64 fundsTransferred) public { - //amount must be less than LINK total supply - vm.assume(fundsTransferred < 1_000_000_000 * 1e18); - vm.assume(fundsTransferred > 0); - - // uint256 fundsTransferred = 1 * 1e18; // 1 LINK + function test_RecoverFunds_Success() public { + uint256 fundsTransferred = 1 * 1e18; // 1 LINK s_linkToken.transfer(address(s_functionsRouter), fundsTransferred); // topic0 (function signature, always checked), NOT topic1 (false), NOT topic2 (false), NOT topic3 (false), and data (true). @@ -320,58 +316,43 @@ contract FunctionsSubscriptions_OnTokenTransfer is FunctionsClientSetup { s_functionsRouter.addConsumer(s_subscriptionId, address(s_functionsClient)); } - function test_OnTokenTransfer_RevertIfPaused(uint96 fundingAmount) public { - // Funding amount must be less than LINK total supply + function test_OnTokenTransfer_RevertIfPaused() public { + // Funding amount must be less than or equal to LINK total supply uint256 totalSupplyJuels = 1_000_000_000 * 1e18; - vm.assume(fundingAmount <= totalSupplyJuels); - vm.assume(fundingAmount >= 0); - s_functionsRouter.pause(); vm.expectRevert("Pausable: paused"); - s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); + s_linkToken.transferAndCall(address(s_functionsRouter), totalSupplyJuels, abi.encode(s_subscriptionId)); } - function test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96 fundingAmount) public { - // Funding amount must be less than LINK total supply + function test_OnTokenTransfer_RevertIfCallerIsNotLink() public { + // Funding amount must be less than or equal to LINK total supply uint256 totalSupplyJuels = 1_000_000_000 * 1e18; - vm.assume(fundingAmount <= totalSupplyJuels); - vm.assume(fundingAmount >= 0); - vm.expectRevert(FunctionsSubscriptions.OnlyCallableFromLink.selector); - s_functionsRouter.onTokenTransfer(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); + s_functionsRouter.onTokenTransfer(address(s_functionsRouter), totalSupplyJuels, abi.encode(s_subscriptionId)); } - function test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96 fundingAmount) public { - // Funding amount must be less than LINK total supply + function test_OnTokenTransfer_RevertIfCallerIsNoCalldata() public { + // Funding amount must be less than or equal to LINK total supply uint256 totalSupplyJuels = 1_000_000_000 * 1e18; - vm.assume(fundingAmount <= totalSupplyJuels); - vm.assume(fundingAmount >= 0); - vm.expectRevert(FunctionsSubscriptions.InvalidCalldata.selector); - s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, new bytes(0)); + s_linkToken.transferAndCall(address(s_functionsRouter), totalSupplyJuels, new bytes(0)); } - function test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96 fundingAmount) public { - // Funding amount must be less than LINK total supply + function test_OnTokenTransfer_RevertIfCallerIsNoSubscription() public { + // Funding amount must be less than or equal to LINK total supply uint256 totalSupplyJuels = 1_000_000_000 * 1e18; - vm.assume(fundingAmount <= totalSupplyJuels); - vm.assume(fundingAmount >= 0); - vm.expectRevert(FunctionsSubscriptions.InvalidSubscription.selector); uint64 invalidSubscriptionId = 123456789; - s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(invalidSubscriptionId)); + s_linkToken.transferAndCall(address(s_functionsRouter), totalSupplyJuels, abi.encode(invalidSubscriptionId)); } function test_OnTokenTransfer_Success(uint96 fundingAmount) public { // Funding amount must be less than LINK total supply uint256 totalSupplyJuels = 1_000_000_000 * 1e18; // Some of the total supply is already in the subscription account - vm.assume(fundingAmount <= totalSupplyJuels); - vm.assume(fundingAmount >= 0); - - s_linkToken.transferAndCall(address(s_functionsRouter), fundingAmount, abi.encode(s_subscriptionId)); + s_linkToken.transferAndCall(address(s_functionsRouter), totalSupplyJuels, abi.encode(s_subscriptionId)); uint96 subscriptionBalanceAfter = s_functionsRouter.getSubscription(s_subscriptionId).balance; - assertEq(fundingAmount, subscriptionBalanceAfter); + assertEq(totalSupplyJuels, subscriptionBalanceAfter); } } diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol index 450ec48d504..e121f7b881d 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsTermsOfServiceAllowList.t.sol @@ -2,14 +2,16 @@ pragma solidity ^0.8.19; import {TermsOfServiceAllowList} from "../../dev/v1_X/accessControl/TermsOfServiceAllowList.sol"; +import {TermsOfServiceAllowListConfig} from "../../dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol"; import {FunctionsClientTestHelper} from "./testhelpers/FunctionsClientTestHelper.sol"; import {FunctionsRoutesSetup, FunctionsOwnerAcceptTermsOfServiceSetup} from "./Setup.t.sol"; +import "forge-std/Vm.sol"; /// @notice #constructor contract FunctionsTermsOfServiceAllowList_Constructor is FunctionsRoutesSetup { function test_Constructor_Success() public { - assertEq(s_termsOfServiceAllowList.typeAndVersion(), "Functions Terms of Service Allow List v1.0.0"); + assertEq(s_termsOfServiceAllowList.typeAndVersion(), "Functions Terms of Service Allow List v1.1.0"); assertEq(s_termsOfServiceAllowList.owner(), OWNER_ADDRESS); } } @@ -21,7 +23,7 @@ contract FunctionsTermsOfServiceAllowList_GetConfig is FunctionsRoutesSetup { vm.stopPrank(); vm.startPrank(STRANGER_ADDRESS); - TermsOfServiceAllowList.Config memory config = s_termsOfServiceAllowList.getConfig(); + TermsOfServiceAllowListConfig memory config = s_termsOfServiceAllowList.getConfig(); assertEq(config.enabled, getTermsOfServiceConfig().enabled); assertEq(config.signerPublicKey, getTermsOfServiceConfig().signerPublicKey); } @@ -36,14 +38,14 @@ contract FunctionsTermsOfServiceAllowList_UpdateConfig is FunctionsRoutesSetup { vm.expectRevert("Only callable by owner"); s_termsOfServiceAllowList.updateConfig( - TermsOfServiceAllowList.Config({enabled: true, signerPublicKey: STRANGER_ADDRESS}) + TermsOfServiceAllowListConfig({enabled: true, signerPublicKey: STRANGER_ADDRESS}) ); } - event ConfigUpdated(TermsOfServiceAllowList.Config config); + event ConfigUpdated(TermsOfServiceAllowListConfig config); function test_UpdateConfig_Success() public { - TermsOfServiceAllowList.Config memory configToSet = TermsOfServiceAllowList.Config({ + TermsOfServiceAllowListConfig memory configToSet = TermsOfServiceAllowListConfig({ enabled: false, signerPublicKey: TOS_SIGNER }); @@ -58,7 +60,7 @@ contract FunctionsTermsOfServiceAllowList_UpdateConfig is FunctionsRoutesSetup { s_termsOfServiceAllowList.updateConfig(configToSet); - TermsOfServiceAllowList.Config memory config = s_termsOfServiceAllowList.getConfig(); + TermsOfServiceAllowListConfig memory config = s_termsOfServiceAllowList.getConfig(); assertEq(config.enabled, configToSet.enabled); assertEq(config.signerPublicKey, configToSet.signerPublicKey); } @@ -156,7 +158,7 @@ contract FunctionsTermsOfServiceAllowList_AcceptTermsOfService is FunctionsRoute function testAcceptTermsOfService_InvalidSigner_vuln() public { // Set the signer as the zero address - TermsOfServiceAllowList.Config memory allowListConfig; + TermsOfServiceAllowListConfig memory allowListConfig; allowListConfig.enabled = true; allowListConfig.signerPublicKey = address(0); s_termsOfServiceAllowList.updateConfig(allowListConfig); @@ -197,11 +199,12 @@ contract FunctionsTermsOfServiceAllowList_AcceptTermsOfService is FunctionsRoute assertTrue(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0))); - // Event emitted even though adding existing item into EnumerableSet set does nothing - // TODO: handle differently in contract - vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); - emit AddedAccess(STRANGER_ADDRESS); + // Check the addedAccess is not emitted, given the recipient was already in the list + vm.recordLogs(); s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); + Vm.Log[] memory entries = vm.getRecordedLogs(); + assertEq(entries.length, 0); + assertTrue(s_termsOfServiceAllowList.hasAccess(STRANGER_ADDRESS, new bytes(0))); } @@ -244,6 +247,69 @@ contract FunctionsTermsOfServiceAllowList_GetAllAllowedSenders is FunctionsOwner } } +/// @notice #getAllowedSendersCount +contract FunctionsTermsOfServiceAllowList_GetAllowedSendersCount is FunctionsOwnerAcceptTermsOfServiceSetup { + function test_GetAllowedSendersCount_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint96 allowedSendersCount = s_termsOfServiceAllowList.getAllowedSendersCount(); + // One allowed sender was made during setup + assertEq(allowedSendersCount, 1); + } +} + +/// @notice #getAllowedSendersInRange +contract FunctionsTermsOfServiceAllowList_GetAllowedSendersInRange is FunctionsOwnerAcceptTermsOfServiceSetup { + function test_GetAllowedSendersInRange_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + address[] memory expectedSenders = new address[](1); + expectedSenders[0] = OWNER_ADDRESS; + + assertEq(s_termsOfServiceAllowList.getAllowedSendersInRange(0, 0), expectedSenders); + } + + function test_GetAllowedSendersInRange_RevertIfAllowedSendersIsEmpty() public { + // setup a new empty s_termsOfServiceAllowList + FunctionsRoutesSetup.setUp(); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 AllowedSendersCount = s_termsOfServiceAllowList.getAllowedSendersCount(); + uint64 expected = 0; + assertEq(AllowedSendersCount, expected); + + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + s_termsOfServiceAllowList.getAllowedSendersInRange(0, 0); + } + + function test_GetAllowedSendersInRange_RevertIfStartIsAfterEnd() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + + s_termsOfServiceAllowList.getAllowedSendersInRange(1, 0); + } + + function test_GetAllowedSendersInRange_RevertIfEndIsAfterLastAllowedSender() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 AllowedSendersCount = s_termsOfServiceAllowList.getAllowedSendersCount(); + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + s_termsOfServiceAllowList.getAllowedSendersInRange(1, AllowedSendersCount + 1); + } +} + /// @notice #hasAccess contract FunctionsTermsOfServiceAllowList_HasAccess is FunctionsRoutesSetup { function test_HasAccess_FalseWhenEnabled() public { @@ -258,7 +324,7 @@ contract FunctionsTermsOfServiceAllowList_HasAccess is FunctionsRoutesSetup { function test_HasAccess_TrueWhenDisabled() public { // Disable allow list, which opens all access s_termsOfServiceAllowList.updateConfig( - TermsOfServiceAllowList.Config({enabled: false, signerPublicKey: TOS_SIGNER}) + TermsOfServiceAllowListConfig({enabled: false, signerPublicKey: TOS_SIGNER}) ); // Send as stranger @@ -370,3 +436,78 @@ contract FunctionsTermsOfServiceAllowList_UnblockSender is FunctionsRoutesSetup s_termsOfServiceAllowList.acceptTermsOfService(STRANGER_ADDRESS, STRANGER_ADDRESS, r, s, v); } } + +/// @notice #getBlockedSendersCount +contract FunctionsTermsOfServiceAllowList_GetBlockedSendersCount is FunctionsRoutesSetup { + function setUp() public virtual override { + FunctionsRoutesSetup.setUp(); + + s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS); + } + + function test_GetBlockedSendersCount_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint96 blockedSendersCount = s_termsOfServiceAllowList.getBlockedSendersCount(); + // One blocked sender was made during setup + assertEq(blockedSendersCount, 1); + } +} + +/// @notice #getBlockedSendersInRange +contract FunctionsTermsOfServiceAllowList_GetBlockedSendersInRange is FunctionsRoutesSetup { + function setUp() public virtual override { + FunctionsRoutesSetup.setUp(); + + s_termsOfServiceAllowList.blockSender(STRANGER_ADDRESS); + } + + function test_GetBlockedSendersInRange_Success() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + address[] memory expectedBlockedSenders = new address[](1); + expectedBlockedSenders[0] = STRANGER_ADDRESS; + + assertEq(s_termsOfServiceAllowList.getBlockedSendersInRange(0, 0), expectedBlockedSenders); + } + + function test_GetBlockedSendersInRange_RevertIfAllowedSendersIsEmpty() public { + // setup a new empty s_termsOfServiceBlockList + FunctionsRoutesSetup.setUp(); + + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 BlockedSendersCount = s_termsOfServiceAllowList.getBlockedSendersCount(); + uint64 expected = 0; + assertEq(BlockedSendersCount, expected); + + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + s_termsOfServiceAllowList.getBlockedSendersInRange(0, 0); + } + + function test_GetBlockedSendersInRange_RevertIfStartIsAfterEnd() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + + s_termsOfServiceAllowList.getBlockedSendersInRange(1, 0); + } + + function test_GetBlockedSendersInRange_RevertIfEndIsAfterLastAllowedSender() public { + // Send as stranger + vm.stopPrank(); + vm.startPrank(STRANGER_ADDRESS); + + uint64 BlockedSendersCount = s_termsOfServiceAllowList.getBlockedSendersCount(); + vm.expectRevert(TermsOfServiceAllowList.InvalidCalldata.selector); + s_termsOfServiceAllowList.getBlockedSendersInRange(1, BlockedSendersCount + 1); + } +} diff --git a/contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol b/contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol index 41ee663e8b0..0e131f9b89c 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol @@ -9,7 +9,9 @@ import {FunctionsBilling} from "../../dev/v1_X/FunctionsBilling.sol"; import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; import {MockV3Aggregator} from "../../../tests/MockV3Aggregator.sol"; import {TermsOfServiceAllowList} from "../../dev/v1_X/accessControl/TermsOfServiceAllowList.sol"; +import {TermsOfServiceAllowListConfig} from "../../dev/v1_X/accessControl/interfaces/ITermsOfServiceAllowList.sol"; import {MockLinkToken} from "../../../mocks/MockLinkToken.sol"; +import {FunctionsBillingConfig} from "../../dev/v1_X/interfaces/IFunctionsBilling.sol"; import "forge-std/Vm.sol"; @@ -64,9 +66,9 @@ contract FunctionsRouterSetup is BaseTest { }); } - function getCoordinatorConfig() public view returns (FunctionsBilling.Config memory) { + function getCoordinatorConfig() public view returns (FunctionsBillingConfig memory) { return - FunctionsBilling.Config({ + FunctionsBillingConfig({ feedStalenessSeconds: 24 * 60 * 60, // 1 day gasOverheadAfterCallback: 93_942, gasOverheadBeforeCallback: 105_000, @@ -79,8 +81,8 @@ contract FunctionsRouterSetup is BaseTest { }); } - function getTermsOfServiceConfig() public view returns (TermsOfServiceAllowList.Config memory) { - return TermsOfServiceAllowList.Config({enabled: true, signerPublicKey: TOS_SIGNER}); + function getTermsOfServiceConfig() public view returns (TermsOfServiceAllowListConfig memory) { + return TermsOfServiceAllowListConfig({enabled: true, signerPublicKey: TOS_SIGNER}); } } diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorHarness.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorHarness.sol index c1b6d5d0b14..15d9790f617 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorHarness.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorHarness.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.19; import {FunctionsCoordinator} from "../../../dev/v1_X/FunctionsCoordinator.sol"; import {FunctionsBilling} from "../../../dev/v1_X/FunctionsBilling.sol"; import {FunctionsResponse} from "../../../dev/v1_X/libraries/FunctionsResponse.sol"; +import {FunctionsBillingConfig} from "../../../dev/v1_X/interfaces/IFunctionsBilling.sol"; /// @title Functions Coordinator Test Harness /// @notice Contract to expose internal functions for testing purposes @@ -13,7 +14,7 @@ contract FunctionsCoordinatorHarness is FunctionsCoordinator { constructor( address router, - FunctionsBilling.Config memory config, + FunctionsBillingConfig memory config, address linkToNativeFeed ) FunctionsCoordinator(router, config, linkToNativeFeed) { s_linkToNativeFeed_HARNESS = linkToNativeFeed; diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol index 5e57e62e599..1a7d721d63a 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorTestHelper.sol @@ -3,11 +3,12 @@ pragma solidity ^0.8.19; import {FunctionsCoordinator} from "../../../dev/v1_X/FunctionsCoordinator.sol"; import {FunctionsBilling} from "../../../dev/v1_X/FunctionsBilling.sol"; +import {FunctionsBillingConfig} from "../../../dev/v1_X/interfaces/IFunctionsBilling.sol"; contract FunctionsCoordinatorTestHelper is FunctionsCoordinator { constructor( address router, - FunctionsBilling.Config memory config, + FunctionsBillingConfig memory config, address linkToNativeFeed ) FunctionsCoordinator(router, config, linkToNativeFeed) {} diff --git a/contracts/src/v0.8/l2ep/README.md b/contracts/src/v0.8/l2ep/README.md new file mode 100644 index 00000000000..21a537c4fe7 --- /dev/null +++ b/contracts/src/v0.8/l2ep/README.md @@ -0,0 +1,148 @@ +# Overview + +This folder contains the source code and tests for the Layer 2 +Emergency Protocol (L2EP) contracts. It is organized as follows: + +```text +. +├─/dev (stores the latest source code for L2EP) +├─/test (stores the Foundry tests for L2EP) +``` + +## The `/dev` Folder + +The `/dev` folder contains subfolders for each chain that +has an L2EP solution implemented for it (e.g. `/scroll`, `/arbitrum`, +`/optimism`). It also contains a subfolder named `/interfaces`, +which stores shared interface types between all the supported +contracts. The top-level contracts (e.g. `CrossDomainOwnable.sol`) +serve as either abstract or parent contracts that are meant +to be reused for each indiviudal chain. + +## The `/test` Folder + +This folder is arranged as follows: + +- `/mocks`: used for both Foundry test cases and Hardhat test cases (NOTE: +Hardhat test cases should be considered deprecated at this point) + +- `/[version]`: test cases for a specific version of the L2EP contracts + +### Testing Conventions and Methodology + +By convention, each testing file should end in `.t.sol` (this is a standard +that other projects have also adopted). Each testing file in this folder +follows a similar structure. + +```text +TestFile.t.sol + | + |--- Base Contract (inherits L2EPTest contract) + | + |--- Child Contract 1 (inherits base contract) + | | + | |--- Test Function + | | + | |--- ... + | + | + |--- Child Contract 2 (inherits base contract) + | | + | |--- Test Function + | | + | |--- ... + | + | + ... +``` + +All test files contain a base contract defined at the top of the file. This +base contract inherits from a contract called `L2EPTest`. The `L2EPTest` +contract and base contracts have no test cases. Instead, the `L2EPTest` +contract is meant to store data/functions that will be reused among all +the base contracts. Similarly, the base contract is meant to store data +and/or functions that will be reused by any contracts that inherit it. +As such, each test file will define separate child contracts, and each +will inherit from the base contract + define its own set of tests. + +The base contract defines a `setUp` function which is automatically called +exactly once before ***each*** of the tests are run in an inheriting contract. +The `setUp` function typically deploys a fresh set of test contracts so that +tests can run independently of each other. Alongside the `setUp` function, +the base contract can also define variables, constants, events, etc. that +are meant to be reused per test. + +The name of the base contract follows the following convention: + +```text +Test +``` + +The child contract names follow a similar convention: + +```text +_ +``` + +Each test function within the child contract complies +with the following naming pattern: + +```text +test_ +``` + +### Running Foundry Tests + +#### Usage + +First make sure you are in the contracts directory: + +```sh +# Assuming you are currently in the /chainlink directory +cd ./contracts +``` + +If you already have foundry installed, you can use the following command +to run all L2EP tests: + +```sh +FOUNDRY_PROFILE=l2ep forge test -vvv +``` + +To run a specific L2EP test, you can use a variation of the following command: + +```sh +FOUNDRY_PROFILE=l2ep forge test -vvv --match-path ./src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol +``` + +Or alternatively: + +```sh +FOUNDRY_PROFILE=l2ep forge test -vvv --match-contract ScrollSequencerUptimeFeed +``` + +If you prefer, you can also export `FOUNDRY_PROFILE` so that it doesn't need +to be provided before every command: + +```sh +# Export foundry profile +export FOUNDRY_PROFILE=l2ep + +# Run all tests +forge test -vvv + +# Run all tests and generate a gas snapshot +make snapshot +``` + +A full list of flags for `forge test` can be found [here](https://book.getfoundry.sh/reference/forge/forge-test). + +#### Coverage + +First ensure that the correct files are being evaluated. For example, if only +v1 contracts are, being evaluated then temporarily change the L2EP profile in +`./foundry.toml`. + +```sh +forge coverage +``` diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol index 5250fbda278..63952ab7ba6 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumSequencerUptimeFeed.sol @@ -287,6 +287,8 @@ contract ArbitrumSequencerUptimeFeed is roundId = _roundId; updatedAt = startedAt; answeredInRound = roundId; + + return (roundId, answer, startedAt, updatedAt, answeredInRound); } /// @inheritdoc AggregatorV3Interface @@ -305,5 +307,7 @@ contract ArbitrumSequencerUptimeFeed is startedAt = feedState.latestTimestamp; updatedAt = startedAt; answeredInRound = roundId; + + return (roundId, answer, startedAt, updatedAt, answeredInRound); } } diff --git a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol index 2043ffa6287..66fee5053ee 100644 --- a/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol +++ b/contracts/src/v0.8/l2ep/dev/arbitrum/ArbitrumValidator.sol @@ -204,6 +204,8 @@ contract ArbitrumValidator is TypeAndVersionInterface, AggregatorValidatorInterf message ); emit L2WithdrawalRequested(id, amount, refundAddr); + + return id; } /** diff --git a/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol b/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol new file mode 100644 index 00000000000..f0f716d6f02 --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/interfaces/ScrollSequencerUptimeFeedInterface.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +interface ScrollSequencerUptimeFeedInterface { + function updateStatus(bool status, uint64 timestamp) external; +} diff --git a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol index fcf6093e3cd..947b1b0bf5d 100644 --- a/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol +++ b/contracts/src/v0.8/l2ep/dev/optimism/OptimismSequencerUptimeFeed.sol @@ -245,6 +245,7 @@ contract OptimismSequencerUptimeFeed is } else { revert NoDataPresent(); } + return (roundId, answer, startedAt, updatedAt, answeredInRound); } /// @inheritdoc AggregatorV3Interface @@ -262,5 +263,6 @@ contract OptimismSequencerUptimeFeed is startedAt = feedState.startedAt; updatedAt = feedState.updatedAt; answeredInRound = roundId; + return (roundId, answer, startedAt, updatedAt, answeredInRound); } } diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol new file mode 100644 index 00000000000..f18f7c3270b --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; + +import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; +import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; + +import {IScrollMessenger} from "@scroll-tech/contracts/libraries/IScrollMessenger.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; + +/// @title ScrollCrossDomainForwarder - L1 xDomain account representation +/// @notice L2 Contract which receives messages from a specific L1 address and transparently forwards them to the destination. +/// @dev Any other L2 contract which uses this contract's address as a privileged position, +/// can be considered to be owned by the `l1Owner` +contract ScrollCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwarder { + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "ScrollCrossDomainForwarder 1.0.0"; + + address internal immutable i_scrollCrossDomainMessenger; + + /// @param crossDomainMessengerAddr the xDomain bridge messenger (Scroll bridge L2) contract address + /// @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn + constructor(IScrollMessenger crossDomainMessengerAddr, address l1OwnerAddr) CrossDomainOwnable(l1OwnerAddr) { + // solhint-disable-next-line custom-errors + require(address(crossDomainMessengerAddr) != address(0), "Invalid xDomain Messenger address"); + i_scrollCrossDomainMessenger = address(crossDomainMessengerAddr); + } + + /// @dev forwarded only if L2 Messenger calls with `xDomainMessageSender` being the L1 owner address + /// @inheritdoc ForwarderInterface + function forward(address target, bytes memory data) external override onlyL1Owner { + Address.functionCall(target, data, "Forwarder call reverted"); + } + + /// @notice This is always the address of the Scroll Cross Domain Messenger contract + function crossDomainMessenger() external view returns (address) { + return address(i_scrollCrossDomainMessenger); + } + + /// @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. + modifier onlyL1Owner() override { + // solhint-disable-next-line custom-errors + require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors + require( + IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == l1Owner(), + "xDomain sender is not the L1 owner" + ); + _; + } + + /// @notice The call MUST come from the proposed L1 owner (via cross-chain message.) Reverts otherwise. + modifier onlyProposedL1Owner() override { + // solhint-disable-next-line custom-errors + require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors + require( + IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == s_l1PendingOwner, + "Must be proposed L1 owner" + ); + _; + } +} diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol new file mode 100644 index 00000000000..00ef9219b26 --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {DelegateForwarderInterface} from "../interfaces/DelegateForwarderInterface.sol"; +// solhint-disable-next-line no-unused-import +import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol"; + +import {CrossDomainForwarder} from "../CrossDomainForwarder.sol"; +import {CrossDomainOwnable} from "../CrossDomainOwnable.sol"; + +import {IScrollMessenger} from "@scroll-tech/contracts/libraries/IScrollMessenger.sol"; +import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol"; + +/// @title ScrollCrossDomainGovernor - L1 xDomain account representation (with delegatecall support) for Scroll +/// @notice L2 Contract which receives messages from a specific L1 address and transparently forwards them to the destination. +/// @dev Any other L2 contract which uses this contract's address as a privileged position, +/// can be considered to be simultaneously owned by the `l1Owner` and L2 `owner` +contract ScrollCrossDomainGovernor is DelegateForwarderInterface, TypeAndVersionInterface, CrossDomainForwarder { + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "ScrollCrossDomainGovernor 1.0.0"; + + address internal immutable i_scrollCrossDomainMessenger; + + /// @param crossDomainMessengerAddr the xDomain bridge messenger (Scroll bridge L2) contract address + /// @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn + constructor(IScrollMessenger crossDomainMessengerAddr, address l1OwnerAddr) CrossDomainOwnable(l1OwnerAddr) { + // solhint-disable-next-line custom-errors + require(address(crossDomainMessengerAddr) != address(0), "Invalid xDomain Messenger address"); + i_scrollCrossDomainMessenger = address(crossDomainMessengerAddr); + } + + /// @inheritdoc ForwarderInterface + /// @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner + function forward(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner { + Address.functionCall(target, data, "Governor call reverted"); + } + + /// @inheritdoc DelegateForwarderInterface + /// @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner + function forwardDelegate(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner { + Address.functionDelegateCall(target, data, "Governor delegatecall reverted"); + } + + /// @notice The address of the Scroll Cross Domain Messenger contract + function crossDomainMessenger() external view returns (address) { + return address(i_scrollCrossDomainMessenger); + } + + /// @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise. + modifier onlyL1Owner() override { + // solhint-disable-next-line custom-errors + require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors + require( + IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == l1Owner(), + "xDomain sender is not the L1 owner" + ); + _; + } + + /// @notice The call MUST come from either the L1 owner (via cross-chain message) or the L2 owner. Reverts otherwise. + modifier onlyLocalOrCrossDomainOwner() { + // 1. The delegatecall MUST come from either the L1 owner (via cross-chain message) or the L2 owner + // solhint-disable-next-line custom-errors + require( + msg.sender == i_scrollCrossDomainMessenger || msg.sender == owner(), + "Sender is not the L2 messenger or owner" + ); + // 2. The L2 Messenger's caller MUST be the L1 Owner + if (msg.sender == i_scrollCrossDomainMessenger) { + // solhint-disable-next-line custom-errors + require( + IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == l1Owner(), + "xDomain sender is not the L1 owner" + ); + } + _; + } + + /// @notice The call MUST come from the proposed L1 owner (via cross-chain message.) Reverts otherwise. + modifier onlyProposedL1Owner() override { + // solhint-disable-next-line custom-errors + require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger"); + // solhint-disable-next-line custom-errors + require( + IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == s_l1PendingOwner, + "Must be proposed L1 owner" + ); + _; + } +} diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol new file mode 100644 index 00000000000..9df2b61238a --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {ScrollSequencerUptimeFeedInterface} from "../interfaces/ScrollSequencerUptimeFeedInterface.sol"; +import {AggregatorInterface} from "../../../shared/interfaces/AggregatorInterface.sol"; +import {AggregatorV3Interface} from "../../../shared/interfaces/AggregatorV3Interface.sol"; +import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; + +import {SimpleReadAccessController} from "../../../shared/access/SimpleReadAccessController.sol"; + +import {IL2ScrollMessenger} from "@scroll-tech/contracts/L2/IL2ScrollMessenger.sol"; + +/// @title ScrollSequencerUptimeFeed - L2 sequencer uptime status aggregator +/// @notice L2 contract that receives status updates, and records a new answer if the status changed +contract ScrollSequencerUptimeFeed is + AggregatorV2V3Interface, + ScrollSequencerUptimeFeedInterface, + TypeAndVersionInterface, + SimpleReadAccessController +{ + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "ScrollSequencerUptimeFeed 1.0.0"; + + /// @dev Round info (for uptime history) + struct Round { + bool status; + uint64 startedAt; + uint64 updatedAt; + } + + /// @dev Packed state struct to save sloads + struct FeedState { + uint80 latestRoundId; + bool latestStatus; + uint64 startedAt; + uint64 updatedAt; + } + + /// @notice Sender is not the L2 messenger + error InvalidSender(); + /// @notice Replacement for AggregatorV3Interface "No data present" + error NoDataPresent(); + /// @notice Address must not be the zero address + error ZeroAddress(); + + event L1SenderTransferred(address indexed from, address indexed to); + /// @dev Emitted when an `updateStatus` call is ignored due to unchanged status or stale timestamp + event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); + /// @dev Emitted when a updateStatus is called without the status changing + event RoundUpdated(int256 status, uint64 updatedAt); + + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + uint8 public constant override decimals = 0; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override description = "L2 Sequencer Uptime Status Feed"; + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + uint256 public constant override version = 1; + + /// @dev L1 address + address private s_l1Sender; + /// @dev s_latestRoundId == 0 means this contract is uninitialized. + FeedState private s_feedState = FeedState({latestRoundId: 0, latestStatus: false, startedAt: 0, updatedAt: 0}); + mapping(uint80 roundId => Round round) private s_rounds; + + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + IL2ScrollMessenger private immutable s_l2CrossDomainMessenger; + + /// @param l1SenderAddress Address of the L1 contract that is permissioned to call this contract + /// @param l2CrossDomainMessengerAddr Address of the L2CrossDomainMessenger contract + /// @param initialStatus The initial status of the feed + constructor(address l1SenderAddress, address l2CrossDomainMessengerAddr, bool initialStatus) { + if (l2CrossDomainMessengerAddr == address(0)) { + revert ZeroAddress(); + } + + _setL1Sender(l1SenderAddress); + s_l2CrossDomainMessenger = IL2ScrollMessenger(l2CrossDomainMessengerAddr); + + // Initialise roundId == 1 as the first round + _recordRound(1, initialStatus, uint64(block.timestamp)); + } + + /// @notice Check if a roundId is valid in this current contract state + /// @dev Mainly used for AggregatorV2V3Interface functions + /// @param roundId Round ID to check + function _isValidRound(uint256 roundId) private view returns (bool) { + return roundId > 0 && roundId <= type(uint80).max && s_feedState.latestRoundId >= roundId; + } + + /// @return L1 sender address + function l1Sender() public view virtual returns (address) { + return s_l1Sender; + } + + /// @notice Set the allowed L1 sender for this contract to a new L1 sender + /// @dev Can be disabled by setting the L1 sender as `address(0)`. Accessible only by owner. + /// @param to new L1 sender that will be allowed to call `updateStatus` on this contract + function transferL1Sender(address to) external virtual onlyOwner { + _setL1Sender(to); + } + + /// @notice internal method that stores the L1 sender + function _setL1Sender(address to) private { + address from = s_l1Sender; + if (from != to) { + s_l1Sender = to; + emit L1SenderTransferred(from, to); + } + } + + /// @dev Returns an AggregatorV2V3Interface compatible answer from status flag + /// @param status The status flag to convert to an aggregator-compatible answer + function _getStatusAnswer(bool status) private pure returns (int256) { + return status ? int256(1) : int256(0); + } + + /// @notice Helper function to record a round and set the latest feed state. + /// @param roundId The round ID to record + /// @param status Sequencer status + /// @param timestamp The L1 block timestamp of status update + function _recordRound(uint80 roundId, bool status, uint64 timestamp) private { + s_feedState = FeedState(roundId, status, timestamp, uint64(block.timestamp)); + s_rounds[roundId] = Round(status, timestamp, uint64(block.timestamp)); + + emit NewRound(roundId, msg.sender, timestamp); + emit AnswerUpdated(_getStatusAnswer(status), roundId, timestamp); + } + + /// @notice Helper function to update when a round was last updated + /// @param roundId The round ID to update + /// @param status Sequencer status + function _updateRound(uint80 roundId, bool status) private { + s_feedState.updatedAt = uint64(block.timestamp); + s_rounds[roundId].updatedAt = uint64(block.timestamp); + emit RoundUpdated(_getStatusAnswer(status), uint64(block.timestamp)); + } + + /// @notice Record a new status and timestamp if it has changed since the last round. + /// @dev This function will revert if not called from `l1Sender` via the L1->L2 messenger. + /// + /// @param status Sequencer status + /// @param timestamp Block timestamp of status update + function updateStatus(bool status, uint64 timestamp) external override { + FeedState memory feedState = s_feedState; + + if ( + msg.sender != address(s_l2CrossDomainMessenger) || s_l2CrossDomainMessenger.xDomainMessageSender() != s_l1Sender + ) { + revert InvalidSender(); + } + + // Ignore if latest recorded timestamp is newer + if (feedState.startedAt > timestamp) { + emit UpdateIgnored(feedState.latestStatus, feedState.startedAt, status, timestamp); + return; + } + + if (feedState.latestStatus == status) { + _updateRound(feedState.latestRoundId, status); + } else { + feedState.latestRoundId += 1; + _recordRound(feedState.latestRoundId, status, timestamp); + } + } + + /// @inheritdoc AggregatorInterface + function latestAnswer() external view override checkAccess returns (int256) { + return _getStatusAnswer(s_feedState.latestStatus); + } + + /// @inheritdoc AggregatorInterface + function latestTimestamp() external view override checkAccess returns (uint256) { + return s_feedState.startedAt; + } + + /// @inheritdoc AggregatorInterface + function latestRound() external view override checkAccess returns (uint256) { + return s_feedState.latestRoundId; + } + + /// @inheritdoc AggregatorInterface + function getAnswer(uint256 roundId) external view override checkAccess returns (int256) { + if (!_isValidRound(roundId)) { + revert NoDataPresent(); + } + + return _getStatusAnswer(s_rounds[uint80(roundId)].status); + } + + /// @inheritdoc AggregatorInterface + function getTimestamp(uint256 roundId) external view override checkAccess returns (uint256) { + if (!_isValidRound(roundId)) { + revert NoDataPresent(); + } + + return s_rounds[uint80(roundId)].startedAt; + } + + /// @inheritdoc AggregatorV3Interface + function getRoundData( + uint80 _roundId + ) + public + view + override + checkAccess + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + if (!_isValidRound(_roundId)) { + revert NoDataPresent(); + } + + Round memory round = s_rounds[_roundId]; + + return (_roundId, _getStatusAnswer(round.status), uint256(round.startedAt), uint256(round.updatedAt), _roundId); + } + + /// @inheritdoc AggregatorV3Interface + function latestRoundData() + external + view + override + checkAccess + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + FeedState memory feedState = s_feedState; + + return ( + feedState.latestRoundId, + _getStatusAnswer(feedState.latestStatus), + feedState.startedAt, + feedState.updatedAt, + feedState.latestRoundId + ); + } +} diff --git a/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol b/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol new file mode 100644 index 00000000000..31a5f0764ef --- /dev/null +++ b/contracts/src/v0.8/l2ep/dev/scroll/ScrollValidator.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {AggregatorValidatorInterface} from "../../../shared/interfaces/AggregatorValidatorInterface.sol"; +import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol"; +import {ScrollSequencerUptimeFeedInterface} from "../interfaces/ScrollSequencerUptimeFeedInterface.sol"; + +import {SimpleWriteAccessController} from "../../../shared/access/SimpleWriteAccessController.sol"; + +import {IL1ScrollMessenger} from "@scroll-tech/contracts/L1/IL1ScrollMessenger.sol"; + +/// @title ScrollValidator - makes cross chain call to update the Sequencer Uptime Feed on L2 +contract ScrollValidator is TypeAndVersionInterface, AggregatorValidatorInterface, SimpleWriteAccessController { + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + address public immutable L1_CROSS_DOMAIN_MESSENGER_ADDRESS; + // solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i + address public immutable L2_UPTIME_FEED_ADDR; + + // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables + string public constant override typeAndVersion = "ScrollValidator 1.0.0"; + int256 private constant ANSWER_SEQ_OFFLINE = 1; + uint32 private s_gasLimit; + + /// @notice emitted when gas cost to spend on L2 is updated + /// @param gasLimit updated gas cost + event GasLimitUpdated(uint32 gasLimit); + + /// @param l1CrossDomainMessengerAddress address the L1CrossDomainMessenger contract address + /// @param l2UptimeFeedAddr the address of the ScrollSequencerUptimeFeed contract address + /// @param gasLimit the gasLimit to use for sending a message from L1 to L2 + constructor(address l1CrossDomainMessengerAddress, address l2UptimeFeedAddr, uint32 gasLimit) { + // solhint-disable-next-line custom-errors + require(l1CrossDomainMessengerAddress != address(0), "Invalid xDomain Messenger address"); + // solhint-disable-next-line custom-errors + require(l2UptimeFeedAddr != address(0), "Invalid ScrollSequencerUptimeFeed contract address"); + L1_CROSS_DOMAIN_MESSENGER_ADDRESS = l1CrossDomainMessengerAddress; + L2_UPTIME_FEED_ADDR = l2UptimeFeedAddr; + s_gasLimit = gasLimit; + } + + /// @notice sets the new gas cost to spend when sending cross chain message + /// @param gasLimit the updated gas cost + function setGasLimit(uint32 gasLimit) external onlyOwner { + s_gasLimit = gasLimit; + emit GasLimitUpdated(gasLimit); + } + + /// @notice fetches the gas cost of sending a cross chain message + function getGasLimit() external view returns (uint32) { + return s_gasLimit; + } + + /// @notice validate method sends an xDomain L2 tx to update Uptime Feed contract on L2. + /// @dev A message is sent using the L1CrossDomainMessenger. This method is accessed controlled. + /// @param currentAnswer new aggregator answer - value of 1 considers the sequencer offline. + function validate( + uint256 /* previousRoundId */, + int256 /* previousAnswer */, + uint256 /* currentRoundId */, + int256 currentAnswer + ) external override checkAccess returns (bool) { + // Make the xDomain call + IL1ScrollMessenger(L1_CROSS_DOMAIN_MESSENGER_ADDRESS).sendMessage( + L2_UPTIME_FEED_ADDR, + 0, + abi.encodeWithSelector( + ScrollSequencerUptimeFeedInterface.updateStatus.selector, + currentAnswer == ANSWER_SEQ_OFFLINE, + uint64(block.timestamp) + ), + s_gasLimit + ); + + // return success + return true; + } +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol b/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol new file mode 100644 index 00000000000..c4e2f710300 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/MockAggregatorV2V3.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import {AggregatorV2V3Interface} from "../../../shared/interfaces/AggregatorV2V3Interface.sol"; + +contract MockAggregatorV2V3 is AggregatorV2V3Interface { + function latestAnswer() external pure returns (int256) { + return 0; + } + + function latestTimestamp() external pure returns (uint256) { + return 0; + } + + function latestRound() external pure returns (uint256) { + return 0; + } + + function getAnswer(uint256) external pure returns (int256) { + return 0; + } + + function getTimestamp(uint256 roundId) external pure returns (uint256) { + return roundId; + } + + function decimals() external pure returns (uint8) { + return 0; + } + + function description() external pure returns (string memory) { + return ""; + } + + function version() external pure returns (uint256) { + return 0; + } + + function getRoundData( + uint80 + ) + external + pure + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (0, 0, 0, 0, 0); + } + + function latestRoundData() + external + pure + returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (73786976294838220258, 96800000000, 163826896, 1638268960, 73786976294838220258); + } +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/optimism/MockOVMCrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/optimism/MockOVMCrossDomainMessenger.sol new file mode 100644 index 00000000000..3a45cba347a --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/optimism/MockOVMCrossDomainMessenger.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.7.6 <0.9.0; + +import {iOVM_CrossDomainMessenger} from "../../../../vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol"; + +import {Address} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; + +contract MockOVMCrossDomainMessenger is iOVM_CrossDomainMessenger { + address internal s_mockMessageSender; + + constructor(address sender) { + s_mockMessageSender = sender; + } + + function xDomainMessageSender() external view override returns (address) { + return s_mockMessageSender; + } + + function _setMockMessageSender(address sender) external { + s_mockMessageSender = sender; + } + + /** + * Sends a cross domain message to the target messenger. + * @param _target Target contract address. + * @param _message Message to send to the target. + */ + function sendMessage(address _target, bytes calldata _message, uint32) external override { + Address.functionCall(_target, _message, "sendMessage reverted"); + } +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollCrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollCrossDomainMessenger.sol new file mode 100644 index 00000000000..37244910b81 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollCrossDomainMessenger.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.16; + +import {IScrollMessenger} from "@scroll-tech/contracts/libraries/IScrollMessenger.sol"; + +import {Address} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; + +contract MockScrollCrossDomainMessenger is IScrollMessenger { + address internal s_mockMessageSender; + + constructor(address sender) { + s_mockMessageSender = sender; + } + + function xDomainMessageSender() external view override returns (address) { + return s_mockMessageSender; + } + + function _setMockMessageSender(address sender) external { + s_mockMessageSender = sender; + } + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param _target The address of account who receive the message. + /// @param _message The content of the message. + function sendMessage(address _target, uint256, bytes calldata _message, uint256) external payable override { + Address.functionCall(_target, _message, "sendMessage reverted"); + } + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param _target The address of account who receive the message. + /// @param _message The content of the message. + function sendMessage(address _target, uint256, bytes calldata _message, uint256, address) external payable override { + Address.functionCall(_target, _message, "sendMessage reverted"); + } +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol new file mode 100644 index 00000000000..e63847d6557 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import {IL1ScrollMessenger} from "@scroll-tech/contracts/L1/IL1ScrollMessenger.sol"; + +contract MockScrollL1CrossDomainMessenger is IL1ScrollMessenger { + uint256 private s_nonce; + + function xDomainMessageSender() public pure returns (address) { + return address(0); + } + + function sendMessage( + address _target, + uint256 _value, + bytes calldata _message, + uint256 _gasLimit + ) external payable override { + emit SentMessage(msg.sender, _target, _value, s_nonce, _gasLimit, _message); + s_nonce++; + } + + function sendMessage( + address _target, + uint256 _value, + bytes calldata _message, + uint256 _gasLimit, + address + ) external payable override { + emit SentMessage(msg.sender, _target, _value, s_nonce, _gasLimit, _message); + s_nonce++; + } + + function relayMessageWithProof( + address from, + address to, + uint256 value, + uint256 nonce, + bytes memory message, + L2MessageProof memory proof + ) external override {} + + function replayMessage( + address from, + address to, + uint256 value, + uint256 messageNonce, + bytes memory message, + uint32 newGasLimit, + address refundAddress + ) external payable override {} + + function dropMessage( + address from, + address to, + uint256 value, + uint256 messageNonce, + bytes memory message + ) external override {} +} diff --git a/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol new file mode 100644 index 00000000000..66400b7d305 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import {IL2ScrollMessenger} from "@scroll-tech/contracts/L2/IL2ScrollMessenger.sol"; + +contract MockScrollL2CrossDomainMessenger is IL2ScrollMessenger { + uint256 private s_nonce; + address private s_sender; + + function xDomainMessageSender() public view returns (address) { + return s_sender; + } + + function sendMessage( + address _target, + uint256 _value, + bytes calldata _message, + uint256 _gasLimit + ) external payable override { + emit SentMessage(msg.sender, _target, _value, s_nonce, _gasLimit, _message); + s_nonce++; + } + + function sendMessage( + address _target, + uint256 _value, + bytes calldata _message, + uint256 _gasLimit, + address + ) external payable override { + emit SentMessage(msg.sender, _target, _value, s_nonce, _gasLimit, _message); + s_nonce++; + } + + function relayMessage( + address from, + address to, + uint256 value, + uint256 nonce, + bytes calldata message + ) external override {} + + /// Needed for backwards compatibility in Hardhat tests + function setSender(address newSender) external { + s_sender = newSender; + } + + /// Needed for backwards compatibility in Hardhat tests + receive() external payable {} +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/L2EPTest.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/L2EPTest.t.sol new file mode 100644 index 00000000000..561e32be1a2 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/L2EPTest.t.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {Greeter} from "../../../tests/Greeter.sol"; + +import {MultiSend} from "../../../vendor/MultiSend.sol"; +import {Test} from "forge-std/Test.sol"; + +contract L2EPTest is Test { + /// Helper variable(s) + address internal s_strangerAddr = vm.addr(0x1); + address internal s_l1OwnerAddr = vm.addr(0x2); + address internal s_eoaValidator = vm.addr(0x3); + address internal s_deployerAddr = vm.addr(0x4); + + /// @param expectedGasUsage - the expected gas usage + /// @param startGasUsage - the gas usage before the code of interest is run + /// @param finalGasUsage - the gas usage after the code of interest is run + /// @param deviation - the amount of gas that the actual usage is allowed to deviate by (e.g. (expectedGas - deviation) <= actualGasUsage <= (expectedGas + deviation)) + function assertGasUsageIsCloseTo( + uint256 expectedGasUsage, + uint256 startGasUsage, + uint256 finalGasUsage, + uint256 deviation + ) public { + uint256 gasUsed = (startGasUsage - finalGasUsage) * tx.gasprice; + assertLe(gasUsed, expectedGasUsage + deviation); + assertGe(gasUsed, expectedGasUsage - deviation); + } + + /// @param selector - the function selector + /// @param greeterAddr - the address of the Greeter contract + /// @param message - the new greeting message, which will be passed as an argument to Greeter#setGreeting + /// @return a 2-layer encoding such that decoding the first layer provides the CrossDomainForwarder#forward + /// function selector and the corresponding arguments to the forward function, and decoding the + /// second layer provides the Greeter#setGreeting function selector and the corresponding + /// arguments to the set greeting function (which in this case is the input message) + function encodeCrossDomainSetGreetingMsg( + bytes4 selector, + address greeterAddr, + string memory message + ) public pure returns (bytes memory) { + return abi.encodeWithSelector(selector, greeterAddr, abi.encodeWithSelector(Greeter.setGreeting.selector, message)); + } + + /// @param selector - the function selector + /// @param multiSendAddr - the address of the MultiSend contract + /// @param encodedTxs - an encoded list of transactions (e.g. abi.encodePacked(encodeMultiSendTx("some data"), ...)) + /// @return a 2-layer encoding such that decoding the first layer provides the CrossDomainGoverner#forwardDelegate + /// function selector and the corresponding arguments to the forwardDelegate function, and decoding the + /// second layer provides the MultiSend#multiSend function selector and the corresponding + /// arguments to the multiSend function (which in this case is the input encodedTxs) + function encodeCrossDomainMultiSendMsg( + bytes4 selector, + address multiSendAddr, + bytes memory encodedTxs + ) public pure returns (bytes memory) { + return + abi.encodeWithSelector(selector, multiSendAddr, abi.encodeWithSelector(MultiSend.multiSend.selector, encodedTxs)); + } + + /// @param greeterAddr - the address of the greeter contract + /// @param data - the transaction data string + /// @return an encoded transaction structured as specified in the MultiSend#multiSend comments + function encodeMultiSendTx(address greeterAddr, bytes memory data) public pure returns (bytes memory) { + bytes memory txData = abi.encodeWithSelector(Greeter.setGreeting.selector, data); + return + abi.encodePacked( + uint8(0), // operation + greeterAddr, // to + uint256(0), // value + uint256(txData.length), // data length + txData // data as bytes + ); + } + + /// @param l1Address - Address on L1 + /// @return an Arbitrum L2 address + function toArbitrumL2AliasAddress(address l1Address) public pure returns (address) { + return address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111)); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol new file mode 100644 index 00000000000..be3851c5b5d --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {ArbitrumCrossDomainForwarder} from "../../../dev/arbitrum/ArbitrumCrossDomainForwarder.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ArbitrumCrossDomainForwarderTest is L2EPTest { + /// Helper variable(s) + address internal s_crossDomainMessengerAddr = toArbitrumL2AliasAddress(s_l1OwnerAddr); + address internal s_newOwnerCrossDomainMessengerAddr = toArbitrumL2AliasAddress(s_strangerAddr); + + /// Contracts + ArbitrumCrossDomainForwarder internal s_arbitrumCrossDomainForwarder; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_arbitrumCrossDomainForwarder = new ArbitrumCrossDomainForwarder(s_l1OwnerAddr); + s_greeter = new Greeter(address(s_arbitrumCrossDomainForwarder)); + vm.stopPrank(); + } +} + +contract ArbitrumCrossDomainForwarder_Constructor is ArbitrumCrossDomainForwarderTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_arbitrumCrossDomainForwarder.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_arbitrumCrossDomainForwarder.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_arbitrumCrossDomainForwarder.crossDomainMessenger(), s_crossDomainMessengerAddr); + + // it should set the typeAndVersion correctly + assertEq(s_arbitrumCrossDomainForwarder.typeAndVersion(), "ArbitrumCrossDomainForwarder 1.0.0"); + } +} + +contract ArbitrumCrossDomainForwarder_Forward is ArbitrumCrossDomainForwarderTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_arbitrumCrossDomainForwarder.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_arbitrumCrossDomainForwarder.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting) + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_arbitrumCrossDomainForwarder.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, "") + ); + } +} + +contract ArbitrumCrossDomainForwarder_TransferL1Ownership is ArbitrumCrossDomainForwarderTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_arbitrumCrossDomainForwarder.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_arbitrumCrossDomainForwarder.l1Owner(), s_strangerAddr); + + // Sends the message + s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_arbitrumCrossDomainForwarder.l1Owner(), address(0)); + + // Sends the message + s_arbitrumCrossDomainForwarder.transferL1Ownership(address(0)); + } +} + +contract ArbitrumCrossDomainForwarder_AcceptL1Ownership is ArbitrumCrossDomainForwarderTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_arbitrumCrossDomainForwarder.acceptL1Ownership(); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Request ownership transfer + vm.startPrank(s_crossDomainMessengerAddr); + s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + vm.startPrank(s_newOwnerCrossDomainMessengerAddr); + s_arbitrumCrossDomainForwarder.acceptL1Ownership(); + + // Asserts that the ownership was actually transferred + assertEq(s_arbitrumCrossDomainForwarder.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainGovernor.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainGovernor.t.sol new file mode 100644 index 00000000000..c5b8adaf7d2 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainGovernor.t.sol @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {ArbitrumCrossDomainGovernor} from "../../../dev/arbitrum/ArbitrumCrossDomainGovernor.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +import {MultiSend} from "../../../../vendor/MultiSend.sol"; + +contract ArbitrumCrossDomainGovernorTest is L2EPTest { + /// Helper variable(s) + address internal s_crossDomainMessengerAddr = toArbitrumL2AliasAddress(s_l1OwnerAddr); + address internal s_newOwnerCrossDomainMessengerAddr = toArbitrumL2AliasAddress(s_strangerAddr); + + /// Contracts + ArbitrumCrossDomainGovernor internal s_arbitrumCrossDomainGovernor; + MultiSend internal s_multiSend; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_arbitrumCrossDomainGovernor = new ArbitrumCrossDomainGovernor(s_l1OwnerAddr); + s_greeter = new Greeter(address(s_arbitrumCrossDomainGovernor)); + s_multiSend = new MultiSend(); + vm.stopPrank(); + } +} + +contract ArbitrumCrossDomainGovernor_Constructor is ArbitrumCrossDomainGovernorTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_arbitrumCrossDomainGovernor.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_arbitrumCrossDomainGovernor.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_arbitrumCrossDomainGovernor.crossDomainMessenger(), s_crossDomainMessengerAddr); + + // it should set the typeAndVersion correctly + assertEq(s_arbitrumCrossDomainGovernor.typeAndVersion(), "ArbitrumCrossDomainGovernor 1.0.0"); + } +} + +contract ArbitrumCrossDomainGovernor_Forward is ArbitrumCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_arbitrumCrossDomainGovernor.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_arbitrumCrossDomainGovernor.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting) + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_arbitrumCrossDomainGovernor.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting) + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_arbitrumCrossDomainGovernor.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, "") + ); + } +} + +contract ArbitrumCrossDomainGovernor_ForwardDelegate is ArbitrumCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_arbitrumCrossDomainGovernor.forwardDelegate(address(s_multiSend), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_CallableByCrossDomainMessengerAddressOrL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends the message + s_arbitrumCrossDomainGovernor.forwardDelegate( + address(s_multiSend), + abi.encodeWithSelector( + MultiSend.multiSend.selector, + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ) + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Sends the message + s_arbitrumCrossDomainGovernor.forwardDelegate( + address(s_multiSend), + abi.encodeWithSelector( + MultiSend.multiSend.selector, + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ) + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should revert batch when one call fails + function test_RevertsBatchWhenOneCallFails() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Governor delegatecall reverted"); + s_arbitrumCrossDomainGovernor.forwardDelegate( + address(s_multiSend), + abi.encodeWithSelector( + MultiSend.multiSend.selector, + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "")) + ) + ); + + // Checks that the greeter message is unchanged + assertEq(s_greeter.greeting(), ""); + } + + /// @notice it should bubble up revert when contract call reverts + function test_BubbleUpRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Greeter: revert triggered"); + s_arbitrumCrossDomainGovernor.forwardDelegate( + address(s_greeter), + abi.encodeWithSelector(Greeter.triggerRevert.selector) + ); + } +} + +contract ArbitrumCrossDomainGovernor_TransferL1Ownership is ArbitrumCrossDomainGovernorTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_arbitrumCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_arbitrumCrossDomainGovernor.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_arbitrumCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_arbitrumCrossDomainGovernor.l1Owner(), s_strangerAddr); + + // Sends the message + s_arbitrumCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_arbitrumCrossDomainGovernor.l1Owner(), address(0)); + + // Sends the message + s_arbitrumCrossDomainGovernor.transferL1Ownership(address(0)); + } +} + +contract ArbitrumCrossDomainGovernor_AcceptL1Ownership is ArbitrumCrossDomainGovernorTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_crossDomainMessengerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_arbitrumCrossDomainGovernor.acceptL1Ownership(); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Request ownership transfer + vm.startPrank(s_crossDomainMessengerAddr); + s_arbitrumCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + vm.startPrank(s_newOwnerCrossDomainMessengerAddr); + s_arbitrumCrossDomainGovernor.acceptL1Ownership(); + + // Asserts that the ownership was actually transferred + assertEq(s_arbitrumCrossDomainGovernor.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumSequencerUptimeFeed.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumSequencerUptimeFeed.t.sol new file mode 100644 index 00000000000..3b9df3bf910 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumSequencerUptimeFeed.t.sol @@ -0,0 +1,444 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {SimpleWriteAccessController} from "../../../../shared/access/SimpleWriteAccessController.sol"; +import {ArbitrumSequencerUptimeFeed} from "../../../dev/arbitrum/ArbitrumSequencerUptimeFeed.sol"; +import {MockAggregatorV2V3} from "../../mocks/MockAggregatorV2V3.sol"; +import {FeedConsumer} from "../../../../tests/FeedConsumer.sol"; +import {Flags} from "../../../dev/Flags.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ArbitrumSequencerUptimeFeedTest is L2EPTest { + /// Constants + uint256 internal constant GAS_USED_DEVIATION = 100; + + /// Helper variable(s) + address internal s_l2MessengerAddr = toArbitrumL2AliasAddress(s_l1OwnerAddr); + + /// L2EP contracts + ArbitrumSequencerUptimeFeed internal s_arbitrumSequencerUptimeFeed; + SimpleWriteAccessController internal s_accessController; + MockAggregatorV2V3 internal s_l1GasFeed; + Flags internal s_flags; + + /// Events + event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); + event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt); + event RoundUpdated(int256 status, uint64 updatedAt); + event Initialized(); + + /// Setup + function setUp() public { + vm.startPrank(s_deployerAddr, s_deployerAddr); + + s_accessController = new SimpleWriteAccessController(); + s_flags = new Flags(address(s_accessController), address(s_accessController)); + s_arbitrumSequencerUptimeFeed = new ArbitrumSequencerUptimeFeed(address(s_flags), s_l1OwnerAddr); + + s_accessController.addAccess(address(s_arbitrumSequencerUptimeFeed)); + s_accessController.addAccess(address(s_flags)); + s_accessController.addAccess(s_deployerAddr); + s_flags.addAccess(address(s_arbitrumSequencerUptimeFeed)); + + vm.expectEmit(); + emit Initialized(); + s_arbitrumSequencerUptimeFeed.initialize(); + + vm.stopPrank(); + } +} + +contract ArbitrumSequencerUptimeFeed_Constants is ArbitrumSequencerUptimeFeedTest { + /// @notice it should have the correct value for FLAG_L2_SEQ_OFFLINE' + function test_InitialState() public { + assertEq(s_arbitrumSequencerUptimeFeed.FLAG_L2_SEQ_OFFLINE(), 0xa438451D6458044c3c8CD2f6f31c91ac882A6d91); + } +} + +contract ArbitrumSequencerUptimeFeed_UpdateStatus is ArbitrumSequencerUptimeFeedTest { + /// @notice it should revert if called by an address that is not the L2 Cross Domain Messenger + function test_RevertIfNotL2CrossDomainMessengerAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(ArbitrumSequencerUptimeFeed.InvalidSender.selector); + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should update status when status has changed and incoming timestamp is newer than the latest + function test_UpdateStatusWhenStatusChangeAndTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp(); + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_arbitrumSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, newer timestamp should update + timestamp = timestamp + 200; + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_arbitrumSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_arbitrumSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should update status when status has changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenStatusChangeAndNoTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Fetches the latest timestamp + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_arbitrumSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, same timestamp should update + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_arbitrumSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_arbitrumSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should ignore out-of-order updates + function test_IgnoreOutOfOrderUpdates() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 10000; + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_arbitrumSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Update with different status, but stale timestamp, should be ignored + timestamp = timestamp - 1000; + vm.expectEmit(false, false, false, false); + emit UpdateIgnored(true, 0, true, 0); // arguments are dummy values + // TODO: how can we check that an AnswerUpdated event was NOT emitted + s_arbitrumSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + } +} + +contract ArbitrumSequencerUptimeFeed_AggregatorV3Interface is ArbitrumSequencerUptimeFeedTest { + /// @notice it should return valid answer from getRoundData and latestRoundData + function test_AggregatorV3Interface() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables + uint80 roundId; + int256 answer; + uint256 startedAt; + uint256 updatedAt; + uint80 answeredInRound; + + // Checks initial state + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_arbitrumSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Submits status update with different status and newer timestamp, should update + uint256 timestamp = startedAt + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_arbitrumSequencerUptimeFeed.getRoundData(2); + assertEq(roundId, 2); + assertEq(answer, 1); + assertEq(answeredInRound, roundId); + assertEq(startedAt, timestamp); + assertLe(updatedAt, startedAt); + + // Saves round 2 data + uint80 roundId2 = roundId; + int256 answer2 = answer; + uint256 startedAt2 = startedAt; + uint256 updatedAt2 = updatedAt; + uint80 answeredInRound2 = answeredInRound; + + // Checks that last round is still returning the correct data + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_arbitrumSequencerUptimeFeed.getRoundData(1); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Assert latestRoundData corresponds to latest round id + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_arbitrumSequencerUptimeFeed.latestRoundData(); + assertEq(roundId2, roundId); + assertEq(answer2, answer); + assertEq(startedAt2, startedAt); + assertEq(updatedAt2, updatedAt); + assertEq(answeredInRound2, answeredInRound); + } + + /// @notice it should revert from #getRoundData when round does not yet exist (future roundId) + function test_Return0WhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + ( + uint80 roundId, + int256 answer, + uint256 startedAt, + uint256 updatedAt, + uint80 answeredInRound + ) = s_arbitrumSequencerUptimeFeed.getRoundData(2); + + // Validates round data + assertEq(roundId, 2); + assertEq(answer, 0); + assertEq(startedAt, 0); + assertEq(updatedAt, 0); + assertEq(answeredInRound, 2); + } +} + +contract ArbitrumSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions is ArbitrumSequencerUptimeFeedTest { + /// @notice it should disallow reads on AggregatorV2V3Interface functions when consuming contract is not whitelisted + function test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_arbitrumSequencerUptimeFeed)); + + // Sanity - consumer is not whitelisted + assertEq(s_arbitrumSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_arbitrumSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), false); + + // Asserts reads are not possible from consuming contract + vm.expectRevert("No access"); + feedConsumer.latestAnswer(); + vm.expectRevert("No access"); + feedConsumer.latestRoundData(); + } + + /// @notice it should allow reads on AggregatorV2V3Interface functions when consuming contract is whitelisted + function test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_arbitrumSequencerUptimeFeed)); + + // Whitelist consumer + vm.startPrank(s_deployerAddr, s_deployerAddr); + s_arbitrumSequencerUptimeFeed.addAccess(address(feedConsumer)); + + // Sanity - consumer is whitelisted + assertEq(s_arbitrumSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_arbitrumSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), true); + + // Asserts reads are possible from consuming contract + (uint80 roundId, int256 answer, , , ) = feedConsumer.latestRoundData(); + assertEq(feedConsumer.latestAnswer(), 0); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract ArbitrumSequencerUptimeFeed_GasCosts is ArbitrumSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for updates + function test_GasCosts() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Assert initial conditions + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp(); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 0); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed; + uint256 gasStart; + uint256 gasFinal; + + // measures gas used for no update + expectedGasUsed = 5507; // NOTE: used to be 28300 in hardhat tests + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.updateStatus(false, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 0); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + + // measures gas used for update + expectedGasUsed = 68198; // NOTE: used to be 93015 in hardhat tests + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_arbitrumSequencerUptimeFeed.latestAnswer(), 1); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} + +contract ArbitrumSequencerUptimeFeed_AggregatorInterfaceGasCosts is ArbitrumSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for getRoundData(uint80) + function test_GasUsageForGetRoundData() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 4658; // NOTE: used to be 31157 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.getRoundData(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRoundData() + function test_GasUsageForLatestRoundData() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 2154; // NOTE: used to be 28523 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.latestRoundData(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestAnswer() + function test_GasUsageForLatestAnswer() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1722; // NOTE: used to be 28329 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.latestAnswer(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestTimestamp() + function test_GasUsageForLatestTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1652; // NOTE: used to be 28229 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.latestTimestamp(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRound() + function test_GasUsageForLatestRound() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1632; // NOTE: used to be 28245 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.latestRound(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getAnswer() + function test_GasUsageForGetAnswer() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 4059; // NOTE: used to be 30799 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.getAnswer(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getTimestamp() + function test_GasUsageForGetTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l2MessengerAddr, s_l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 4024; // NOTE: used to be 30753 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_arbitrumSequencerUptimeFeed.latestTimestamp() + 1000; + s_arbitrumSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_arbitrumSequencerUptimeFeed.getTimestamp(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumValidator.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumValidator.t.sol new file mode 100644 index 00000000000..504635540ce --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumValidator.t.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {AccessControllerInterface} from "../../../../shared/interfaces/AccessControllerInterface.sol"; + +import {SimpleWriteAccessController} from "../../../../shared/access/SimpleWriteAccessController.sol"; +import {ArbitrumSequencerUptimeFeed} from "../../../dev/arbitrum/ArbitrumSequencerUptimeFeed.sol"; +import {ArbitrumValidator} from "../../../dev/arbitrum/ArbitrumValidator.sol"; +import {MockArbitrumInbox} from "../../../../tests/MockArbitrumInbox.sol"; +import {MockAggregatorV2V3} from "../../mocks/MockAggregatorV2V3.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ArbitrumValidatorTest is L2EPTest { + /// Helper constants + address internal constant L2_SEQ_STATUS_RECORDER_ADDRESS = 0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b; + uint256 internal constant GAS_PRICE_BID = 1000000; + uint256 internal constant BASE_FEE = 14000000000; + uint256 internal constant MAX_GAS = 1000000; + + /// L2EP contracts + AccessControllerInterface internal s_accessController; + MockArbitrumInbox internal s_mockArbitrumInbox; + ArbitrumValidator internal s_arbitrumValidator; + MockAggregatorV2V3 internal s_l1GasFeed; + + /// Events + event RetryableTicketNoRefundAliasRewriteCreated( + address destAddr, + uint256 arbTxCallValue, + uint256 maxSubmissionCost, + address submissionRefundAddress, + address valueRefundAddress, + uint256 maxGas, + uint256 gasPriceBid, + bytes data + ); + + /// Setup + function setUp() public { + s_accessController = new SimpleWriteAccessController(); + s_mockArbitrumInbox = new MockArbitrumInbox(); + s_l1GasFeed = new MockAggregatorV2V3(); + s_arbitrumValidator = new ArbitrumValidator( + address(s_mockArbitrumInbox), + L2_SEQ_STATUS_RECORDER_ADDRESS, + address(s_accessController), + MAX_GAS, + GAS_PRICE_BID, + BASE_FEE, + address(s_l1GasFeed), + ArbitrumValidator.PaymentStrategy.L1 + ); + } +} + +contract ArbitrumValidator_Validate is ArbitrumValidatorTest { + /// @notice it post sequencer offline + function test_PostSequencerOffline() public { + // Gives access to the s_eoaValidator + s_arbitrumValidator.addAccess(s_eoaValidator); + + // Gets the ArbitrumValidator L2 address + address arbitrumValidatorL2Addr = toArbitrumL2AliasAddress(address(s_arbitrumValidator)); + + // Sets block.timestamp to a later date, funds the ArbitrumValidator contract, and sets msg.sender and tx.origin + uint256 futureTimestampInSeconds = block.timestamp + 5000; + vm.warp(futureTimestampInSeconds); + vm.deal(address(s_arbitrumValidator), 1 ether); + vm.startPrank(s_eoaValidator); + + // Sets up the expected event data + vm.expectEmit(); + emit RetryableTicketNoRefundAliasRewriteCreated( + L2_SEQ_STATUS_RECORDER_ADDRESS, // destAddr + 0, // arbTxCallValue + 25312000000000, // maxSubmissionCost + arbitrumValidatorL2Addr, // submissionRefundAddress + arbitrumValidatorL2Addr, // valueRefundAddress + MAX_GAS, // maxGas + GAS_PRICE_BID, // gasPriceBid + abi.encodeWithSelector(ArbitrumSequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds) // data + ); + + // Runs the function (which produces the event to test) + s_arbitrumValidator.validate(0, 0, 1, 1); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainForwarder.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainForwarder.t.sol new file mode 100644 index 00000000000..d5c482dce98 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainForwarder.t.sol @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {OptimismCrossDomainForwarder} from "../../../dev/optimism/OptimismCrossDomainForwarder.sol"; +import {MockOVMCrossDomainMessenger} from "../../mocks/optimism/MockOVMCrossDomainMessenger.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract OptimismCrossDomainForwarderTest is L2EPTest { + /// Contracts + MockOVMCrossDomainMessenger internal s_mockOptimismCrossDomainMessenger; + OptimismCrossDomainForwarder internal s_optimismCrossDomainForwarder; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_mockOptimismCrossDomainMessenger = new MockOVMCrossDomainMessenger(s_l1OwnerAddr); + s_optimismCrossDomainForwarder = new OptimismCrossDomainForwarder( + s_mockOptimismCrossDomainMessenger, + s_l1OwnerAddr + ); + s_greeter = new Greeter(address(s_optimismCrossDomainForwarder)); + vm.stopPrank(); + } +} + +contract OptimismCrossDomainForwarder_Constructor is OptimismCrossDomainForwarderTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_optimismCrossDomainForwarder.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_optimismCrossDomainForwarder.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_optimismCrossDomainForwarder.crossDomainMessenger(), address(s_mockOptimismCrossDomainMessenger)); + + // it should set the typeAndVersion correctly + assertEq(s_optimismCrossDomainForwarder.typeAndVersion(), "OptimismCrossDomainForwarder 1.0.0"); + } +} + +contract OptimismCrossDomainForwarder_Forward is OptimismCrossDomainForwarderTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_optimismCrossDomainForwarder.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + encodeCrossDomainSetGreetingMsg(s_optimismCrossDomainForwarder.forward.selector, address(s_greeter), greeting), // message + 0 // gas limit + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + encodeCrossDomainSetGreetingMsg(s_optimismCrossDomainForwarder.forward.selector, address(s_greeter), ""), // message + 0 // gas limit + ); + } +} + +contract OptimismCrossDomainForwarder_TransferL1Ownership is OptimismCrossDomainForwarderTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_optimismCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_optimismCrossDomainForwarder.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_optimismCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_optimismCrossDomainForwarder.l1Owner(), s_strangerAddr); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + abi.encodeWithSelector(s_optimismCrossDomainForwarder.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_optimismCrossDomainForwarder.l1Owner(), address(0)); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + abi.encodeWithSelector(s_optimismCrossDomainForwarder.transferL1Ownership.selector, address(0)), // message + 0 // gas limit + ); + } +} + +contract OptimismCrossDomainForwarder_AcceptL1Ownership is OptimismCrossDomainForwarderTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + abi.encodeWithSelector(s_optimismCrossDomainForwarder.acceptL1Ownership.selector), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Request ownership transfer + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + abi.encodeWithSelector(s_optimismCrossDomainForwarder.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Sets a mock message sender + s_mockOptimismCrossDomainMessenger._setMockMessageSender(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainForwarder), // target + abi.encodeWithSelector(s_optimismCrossDomainForwarder.acceptL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Asserts that the ownership was actually transferred + assertEq(s_optimismCrossDomainForwarder.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainGovernor.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainGovernor.t.sol new file mode 100644 index 00000000000..e1a5aef95a1 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismCrossDomainGovernor.t.sol @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {OptimismCrossDomainGovernor} from "../../../dev/optimism/OptimismCrossDomainGovernor.sol"; +import {MockOVMCrossDomainMessenger} from "../../mocks/optimism/MockOVMCrossDomainMessenger.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +import {MultiSend} from "../../../../vendor/MultiSend.sol"; + +contract OptimismCrossDomainGovernorTest is L2EPTest { + /// Contracts + MockOVMCrossDomainMessenger internal s_mockOptimismCrossDomainMessenger; + OptimismCrossDomainGovernor internal s_optimismCrossDomainGovernor; + MultiSend internal s_multiSend; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_mockOptimismCrossDomainMessenger = new MockOVMCrossDomainMessenger(s_l1OwnerAddr); + s_optimismCrossDomainGovernor = new OptimismCrossDomainGovernor(s_mockOptimismCrossDomainMessenger, s_l1OwnerAddr); + s_greeter = new Greeter(address(s_optimismCrossDomainGovernor)); + s_multiSend = new MultiSend(); + vm.stopPrank(); + } +} + +contract OptimismCrossDomainGovernor_Constructor is OptimismCrossDomainGovernorTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_optimismCrossDomainGovernor.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_optimismCrossDomainGovernor.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_optimismCrossDomainGovernor.crossDomainMessenger(), address(s_mockOptimismCrossDomainMessenger)); + + // it should set the typeAndVersion correctly + assertEq(s_optimismCrossDomainGovernor.typeAndVersion(), "OptimismCrossDomainGovernor 1.0.0"); + } +} + +contract OptimismCrossDomainGovernor_Forward is OptimismCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_optimismCrossDomainGovernor.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + encodeCrossDomainSetGreetingMsg(s_optimismCrossDomainGovernor.forward.selector, address(s_greeter), greeting), // message + 0 // gas limit + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + encodeCrossDomainSetGreetingMsg(s_optimismCrossDomainGovernor.forward.selector, address(s_greeter), ""), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_optimismCrossDomainGovernor.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting) + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), greeting); + } +} + +contract OptimismCrossDomainGovernor_ForwardDelegate is OptimismCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_optimismCrossDomainGovernor.forwardDelegate(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_CallableByCrossDomainMessengerAddressOrL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + encodeCrossDomainMultiSendMsg( + s_optimismCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + encodeCrossDomainMultiSendMsg( + s_optimismCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should revert batch when one call fails + function test_RevertsBatchWhenOneCallFails() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Governor delegatecall reverted"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + encodeCrossDomainMultiSendMsg( + s_optimismCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message is unchanged + assertEq(s_greeter.greeting(), ""); + } + + /// @notice it should bubble up revert when contract call reverts + function test_BubbleUpRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Greeter: revert triggered"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector( + OptimismCrossDomainGovernor.forwardDelegate.selector, + address(s_greeter), + abi.encodeWithSelector(Greeter.triggerRevert.selector) + ), // message + 0 // gas limit + ); + } +} + +contract OptimismCrossDomainGovernor_TransferL1Ownership is OptimismCrossDomainGovernorTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_optimismCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_optimismCrossDomainGovernor.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_optimismCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_optimismCrossDomainGovernor.l1Owner(), s_strangerAddr); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector(s_optimismCrossDomainGovernor.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_optimismCrossDomainGovernor.l1Owner(), address(0)); + + // Sends the message + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector(s_optimismCrossDomainGovernor.transferL1Ownership.selector, address(0)), // message + 0 // gas limit + ); + } +} + +contract OptimismCrossDomainGovernor_AcceptL1Ownership is OptimismCrossDomainGovernorTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector(s_optimismCrossDomainGovernor.acceptL1Ownership.selector), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Request ownership transfer + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector(s_optimismCrossDomainGovernor.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Sets a mock message sender + s_mockOptimismCrossDomainMessenger._setMockMessageSender(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + s_mockOptimismCrossDomainMessenger.sendMessage( + address(s_optimismCrossDomainGovernor), // target + abi.encodeWithSelector(s_optimismCrossDomainGovernor.acceptL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Asserts that the ownership was actually transferred + assertEq(s_optimismCrossDomainGovernor.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismSequencerUptimeFeed.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismSequencerUptimeFeed.t.sol new file mode 100644 index 00000000000..60598b9f952 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismSequencerUptimeFeed.t.sol @@ -0,0 +1,524 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockOptimismL1CrossDomainMessenger} from "../../../../tests/MockOptimismL1CrossDomainMessenger.sol"; +import {MockOptimismL2CrossDomainMessenger} from "../../../../tests/MockOptimismL2CrossDomainMessenger.sol"; +import {OptimismSequencerUptimeFeed} from "../../../dev/optimism/OptimismSequencerUptimeFeed.sol"; +import {FeedConsumer} from "../../../../tests/FeedConsumer.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract OptimismSequencerUptimeFeedTest is L2EPTest { + /// Constants + uint256 internal constant GAS_USED_DEVIATION = 100; + + /// L2EP contracts + MockOptimismL1CrossDomainMessenger internal s_mockOptimismL1CrossDomainMessenger; + MockOptimismL2CrossDomainMessenger internal s_mockOptimismL2CrossDomainMessenger; + OptimismSequencerUptimeFeed internal s_optimismSequencerUptimeFeed; + + /// Events + event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); + event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt); + event RoundUpdated(int256 status, uint64 updatedAt); + + /// Setup + function setUp() public { + // Deploys contracts + s_mockOptimismL1CrossDomainMessenger = new MockOptimismL1CrossDomainMessenger(); + s_mockOptimismL2CrossDomainMessenger = new MockOptimismL2CrossDomainMessenger(); + s_optimismSequencerUptimeFeed = new OptimismSequencerUptimeFeed( + s_l1OwnerAddr, + address(s_mockOptimismL2CrossDomainMessenger), + false + ); + + // Sets mock sender in mock L2 messenger contract + s_mockOptimismL2CrossDomainMessenger.setSender(s_l1OwnerAddr); + } +} + +contract OptimismSequencerUptimeFeed_Constructor is OptimismSequencerUptimeFeedTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Checks L1 sender + address actualL1Addr = s_optimismSequencerUptimeFeed.l1Sender(); + assertEq(actualL1Addr, s_l1OwnerAddr); + + // Checks latest round data + (uint80 roundId, int256 answer, , , ) = s_optimismSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract OptimismSequencerUptimeFeed_UpdateStatus is OptimismSequencerUptimeFeedTest { + /// @notice it should revert if called by an address that is not the L2 Cross Domain Messenger + function test_RevertIfNotL2CrossDomainMessengerAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(OptimismSequencerUptimeFeed.InvalidSender.selector); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should revert if called by an address that is not the L2 Cross Domain Messenger and is not the L1 sender + function test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Sets mock sender in mock L2 messenger contract + s_mockOptimismL2CrossDomainMessenger.setSender(s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(OptimismSequencerUptimeFeed.InvalidSender.selector); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should update status when status has not changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenNoChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Fetches the latest timestamp + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Stores the current round data before updating it + ( + uint80 roundIdBeforeUpdate, + int256 answerBeforeUpdate, + uint256 startedAtBeforeUpdate, + , + uint80 answeredInRoundBeforeUpdate + ) = s_optimismSequencerUptimeFeed.latestRoundData(); + + // Submit another status update with the same status + vm.expectEmit(); + emit RoundUpdated(1, uint64(block.timestamp)); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 200)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Stores the current round data after updating it + ( + uint80 roundIdAfterUpdate, + int256 answerAfterUpdate, + uint256 startedAtAfterUpdate, + uint256 updatedAtAfterUpdate, + uint80 answeredInRoundAfterUpdate + ) = s_optimismSequencerUptimeFeed.latestRoundData(); + + // Verifies the latest round data has been properly updated + assertEq(roundIdAfterUpdate, roundIdBeforeUpdate); + assertEq(answerAfterUpdate, answerBeforeUpdate); + assertEq(startedAtAfterUpdate, startedAtBeforeUpdate); + assertEq(answeredInRoundAfterUpdate, answeredInRoundBeforeUpdate); + assertEq(updatedAtAfterUpdate, block.timestamp); + } + + /// @notice it should update status when status has changed and incoming timestamp is newer than the latest + function test_UpdateStatusWhenStatusChangeAndTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp(); + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, newer timestamp should update + timestamp = timestamp + 200; + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should update status when status has changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenStatusChangeAndNoTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Fetches the latest timestamp + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, same timestamp should update + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should ignore out-of-order updates + function test_IgnoreOutOfOrderUpdates() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 10000; + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_optimismSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Update with different status, but stale timestamp, should be ignored + timestamp = timestamp - 1000; + vm.expectEmit(false, false, false, false); + emit UpdateIgnored(true, 0, true, 0); // arguments are dummy values + // TODO: how can we check that an AnswerUpdated event was NOT emitted + s_optimismSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + } +} + +contract OptimismSequencerUptimeFeed_AggregatorV3Interface is OptimismSequencerUptimeFeedTest { + /// @notice it should return valid answer from getRoundData and latestRoundData + function test_AggregatorV3Interface() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables + uint80 roundId; + int256 answer; + uint256 startedAt; + uint256 updatedAt; + uint80 answeredInRound; + + // Checks initial state + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_optimismSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Submits status update with different status and newer timestamp, should update + uint256 timestamp = startedAt + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_optimismSequencerUptimeFeed.getRoundData(2); + assertEq(roundId, 2); + assertEq(answer, 1); + assertEq(answeredInRound, roundId); + assertEq(startedAt, timestamp); + assertLe(updatedAt, startedAt); + + // Saves round 2 data + uint80 roundId2 = roundId; + int256 answer2 = answer; + uint256 startedAt2 = startedAt; + uint256 updatedAt2 = updatedAt; + uint80 answeredInRound2 = answeredInRound; + + // Checks that last round is still returning the correct data + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_optimismSequencerUptimeFeed.getRoundData(1); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Assert latestRoundData corresponds to latest round id + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_optimismSequencerUptimeFeed.latestRoundData(); + assertEq(roundId2, roundId); + assertEq(answer2, answer); + assertEq(startedAt2, startedAt); + assertEq(updatedAt2, updatedAt); + assertEq(answeredInRound2, answeredInRound); + } + + /// @notice it should revert from #getRoundData when round does not yet exist (future roundId) + function test_RevertGetRoundDataWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(OptimismSequencerUptimeFeed.NoDataPresent.selector); + s_optimismSequencerUptimeFeed.getRoundData(2); + } + + /// @notice it should revert from #getAnswer when round does not yet exist (future roundId) + function test_RevertGetAnswerWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(OptimismSequencerUptimeFeed.NoDataPresent.selector); + s_optimismSequencerUptimeFeed.getAnswer(2); + } + + /// @notice it should revert from #getTimestamp when round does not yet exist (future roundId) + function test_RevertGetTimestampWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(OptimismSequencerUptimeFeed.NoDataPresent.selector); + s_optimismSequencerUptimeFeed.getTimestamp(2); + } +} + +contract OptimismSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions is OptimismSequencerUptimeFeedTest { + /// @notice it should disallow reads on AggregatorV2V3Interface functions when consuming contract is not whitelisted + function test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_optimismSequencerUptimeFeed)); + + // Sanity - consumer is not whitelisted + assertEq(s_optimismSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_optimismSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), false); + + // Asserts reads are not possible from consuming contract + vm.expectRevert("No access"); + feedConsumer.latestAnswer(); + vm.expectRevert("No access"); + feedConsumer.latestRoundData(); + } + + /// @notice it should allow reads on AggregatorV2V3Interface functions when consuming contract is whitelisted + function test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_optimismSequencerUptimeFeed)); + + // Whitelist consumer + s_optimismSequencerUptimeFeed.addAccess(address(feedConsumer)); + + // Sanity - consumer is whitelisted + assertEq(s_optimismSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_optimismSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), true); + + // Asserts reads are possible from consuming contract + (uint80 roundId, int256 answer, , , ) = feedConsumer.latestRoundData(); + assertEq(feedConsumer.latestAnswer(), 0); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract OptimismSequencerUptimeFeed_GasCosts is OptimismSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for updates + function test_GasCosts() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Assert initial conditions + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp(); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 0); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed; + uint256 gasStart; + uint256 gasFinal; + + // measures gas used for no update + expectedGasUsed = 10197; // NOTE: used to be 38594 in hardhat tests + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.updateStatus(false, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 0); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + + // measures gas used for update + expectedGasUsed = 33348; // NOTE: used to be 60170 in hardhat tests + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_optimismSequencerUptimeFeed.latestAnswer(), 1); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} + +contract OptimismSequencerUptimeFeed_AggregatorInterfaceGasCosts is OptimismSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for getRoundData(uint80) + function test_GasUsageForGetRoundData() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 4504; // NOTE: used to be 30952 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.getRoundData(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRoundData() + function test_GasUsageForLatestRoundData() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 2154; // NOTE: used to be 28523 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.latestRoundData(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestAnswer() + function test_GasUsageForLatestAnswer() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1722; // NOTE: used to be 28329 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.latestAnswer(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestTimestamp() + function test_GasUsageForLatestTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1598; // NOTE: used to be 28229 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.latestTimestamp(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRound() + function test_GasUsageForLatestRound() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1632; // NOTE: used to be 28245 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.latestRound(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getAnswer() + function test_GasUsageForGetAnswer() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 3929; // NOTE: used to be 30682 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.getAnswer(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getTimestamp() + function test_GasUsageForGetTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockOptimismL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 3817; // NOTE: used to be 30570 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_optimismSequencerUptimeFeed.latestTimestamp() + 1000; + s_optimismSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_optimismSequencerUptimeFeed.getTimestamp(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismValidator.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismValidator.t.sol new file mode 100644 index 00000000000..9364396817a --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/optimism/OptimismValidator.t.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockOptimismL1CrossDomainMessenger} from "../../../../tests/MockOptimismL1CrossDomainMessenger.sol"; +import {MockOptimismL2CrossDomainMessenger} from "../../../../tests/MockOptimismL2CrossDomainMessenger.sol"; +import {OptimismSequencerUptimeFeed} from "../../../dev/optimism/OptimismSequencerUptimeFeed.sol"; +import {OptimismValidator} from "../../../dev/optimism/OptimismValidator.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract OptimismValidatorTest is L2EPTest { + /// Helper constants + address internal constant L2_SEQ_STATUS_RECORDER_ADDRESS = 0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b; + uint32 internal constant INIT_GAS_LIMIT = 1900000; + + /// L2EP contracts + MockOptimismL1CrossDomainMessenger internal s_mockOptimismL1CrossDomainMessenger; + MockOptimismL2CrossDomainMessenger internal s_mockOptimismL2CrossDomainMessenger; + OptimismSequencerUptimeFeed internal s_optimismSequencerUptimeFeed; + OptimismValidator internal s_optimismValidator; + + /// Events + event SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit); + + /// Setup + function setUp() public { + s_mockOptimismL1CrossDomainMessenger = new MockOptimismL1CrossDomainMessenger(); + s_mockOptimismL2CrossDomainMessenger = new MockOptimismL2CrossDomainMessenger(); + + s_optimismSequencerUptimeFeed = new OptimismSequencerUptimeFeed( + address(s_mockOptimismL1CrossDomainMessenger), + address(s_mockOptimismL2CrossDomainMessenger), + true + ); + + s_optimismValidator = new OptimismValidator( + address(s_mockOptimismL1CrossDomainMessenger), + address(s_optimismSequencerUptimeFeed), + INIT_GAS_LIMIT + ); + } +} + +contract OptimismValidator_SetGasLimit is OptimismValidatorTest { + /// @notice it correctly updates the gas limit + function test_CorrectlyUpdatesTheGasLimit() public { + uint32 newGasLimit = 2000000; + assertEq(s_optimismValidator.getGasLimit(), INIT_GAS_LIMIT); + s_optimismValidator.setGasLimit(newGasLimit); + assertEq(s_optimismValidator.getGasLimit(), newGasLimit); + } +} + +contract OptimismValidator_Validate is OptimismValidatorTest { + /// @notice it reverts if called by account with no access + function test_RevertsIfCalledByAnAccountWithNoAccess() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("No access"); + s_optimismValidator.validate(0, 0, 1, 1); + } + + /// @notice it posts sequencer status when there is not status change + function test_PostSequencerStatusWhenThereIsNotStatusChange() public { + // Gives access to the s_eoaValidator + s_optimismValidator.addAccess(s_eoaValidator); + + // Sets block.timestamp to a later date + uint256 futureTimestampInSeconds = block.timestamp + 5000; + vm.startPrank(s_eoaValidator); + vm.warp(futureTimestampInSeconds); + + // Sets up the expected event data + vm.expectEmit(false, false, false, true); + emit SentMessage( + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + address(s_optimismValidator), // sender + abi.encodeWithSelector(OptimismSequencerUptimeFeed.updateStatus.selector, false, futureTimestampInSeconds), // message + 0, // nonce + INIT_GAS_LIMIT // gas limit + ); + + // Runs the function (which produces the event to test) + s_optimismValidator.validate(0, 0, 0, 0); + } + + /// @notice it post sequencer offline + function test_PostSequencerOffline() public { + // Gives access to the s_eoaValidator + s_optimismValidator.addAccess(s_eoaValidator); + + // Sets block.timestamp to a later date + uint256 futureTimestampInSeconds = block.timestamp + 10000; + vm.startPrank(s_eoaValidator); + vm.warp(futureTimestampInSeconds); + + // Sets up the expected event data + vm.expectEmit(false, false, false, true); + emit SentMessage( + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + address(s_optimismValidator), // sender + abi.encodeWithSelector(OptimismSequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds), // message + 0, // nonce + INIT_GAS_LIMIT // gas limit + ); + + // Runs the function (which produces the event to test) + s_optimismValidator.validate(0, 0, 1, 1); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainForwarder.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainForwarder.t.sol new file mode 100644 index 00000000000..f921fa9242e --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainForwarder.t.sol @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockScrollCrossDomainMessenger} from "../../mocks/scroll/MockScrollCrossDomainMessenger.sol"; +import {ScrollCrossDomainForwarder} from "../../../dev/scroll/ScrollCrossDomainForwarder.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ScrollCrossDomainForwarderTest is L2EPTest { + /// Contracts + MockScrollCrossDomainMessenger internal s_mockScrollCrossDomainMessenger; + ScrollCrossDomainForwarder internal s_scrollCrossDomainForwarder; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_mockScrollCrossDomainMessenger = new MockScrollCrossDomainMessenger(s_l1OwnerAddr); + s_scrollCrossDomainForwarder = new ScrollCrossDomainForwarder(s_mockScrollCrossDomainMessenger, s_l1OwnerAddr); + s_greeter = new Greeter(address(s_scrollCrossDomainForwarder)); + vm.stopPrank(); + } +} + +contract ScrollCrossDomainForwarder_Constructor is ScrollCrossDomainForwarderTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_scrollCrossDomainForwarder.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_scrollCrossDomainForwarder.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_scrollCrossDomainForwarder.crossDomainMessenger(), address(s_mockScrollCrossDomainMessenger)); + + // it should set the typeAndVersion correctly + assertEq(s_scrollCrossDomainForwarder.typeAndVersion(), "ScrollCrossDomainForwarder 1.0.0"); + } +} + +contract ScrollCrossDomainForwarder_Forward is ScrollCrossDomainForwarderTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_scrollCrossDomainForwarder.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + encodeCrossDomainSetGreetingMsg(s_scrollCrossDomainForwarder.forward.selector, address(s_greeter), greeting), // message + 0 // gas limit + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + encodeCrossDomainSetGreetingMsg(s_scrollCrossDomainForwarder.forward.selector, address(s_greeter), ""), // message + 0 // gas limit + ); + } +} + +contract ScrollCrossDomainForwarder_TransferL1Ownership is ScrollCrossDomainForwarderTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_scrollCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_scrollCrossDomainForwarder.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_scrollCrossDomainForwarder.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_scrollCrossDomainForwarder.l1Owner(), s_strangerAddr); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainForwarder.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_scrollCrossDomainForwarder.l1Owner(), address(0)); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainForwarder.transferL1Ownership.selector, address(0)), // message + 0 // gas limit + ); + } +} + +contract ScrollCrossDomainForwarder_AcceptL1Ownership is ScrollCrossDomainForwarderTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainForwarder.acceptL1Ownership.selector), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Request ownership transfer + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainForwarder.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Sets a mock message sender + s_mockScrollCrossDomainMessenger._setMockMessageSender(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainForwarder), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainForwarder.acceptL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Asserts that the ownership was actually transferred + assertEq(s_scrollCrossDomainForwarder.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainGovernor.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainGovernor.t.sol new file mode 100644 index 00000000000..9c444604946 --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollCrossDomainGovernor.t.sol @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockScrollCrossDomainMessenger} from "../../mocks/scroll/MockScrollCrossDomainMessenger.sol"; +import {ScrollCrossDomainGovernor} from "../../../dev/scroll/ScrollCrossDomainGovernor.sol"; +import {Greeter} from "../../../../tests/Greeter.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +import {MultiSend} from "../../../../vendor/MultiSend.sol"; + +contract ScrollCrossDomainGovernorTest is L2EPTest { + /// Contracts + MockScrollCrossDomainMessenger internal s_mockScrollCrossDomainMessenger; + ScrollCrossDomainGovernor internal s_scrollCrossDomainGovernor; + MultiSend internal s_multiSend; + Greeter internal s_greeter; + + /// Events + event L1OwnershipTransferRequested(address indexed from, address indexed to); + event L1OwnershipTransferred(address indexed from, address indexed to); + + /// Setup + function setUp() public { + // Deploys contracts + vm.startPrank(s_l1OwnerAddr); + s_mockScrollCrossDomainMessenger = new MockScrollCrossDomainMessenger(s_l1OwnerAddr); + s_scrollCrossDomainGovernor = new ScrollCrossDomainGovernor(s_mockScrollCrossDomainMessenger, s_l1OwnerAddr); + s_greeter = new Greeter(address(s_scrollCrossDomainGovernor)); + s_multiSend = new MultiSend(); + vm.stopPrank(); + } +} + +contract ScrollCrossDomainGovernor_Constructor is ScrollCrossDomainGovernorTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // it should set the owner correctly + assertEq(s_scrollCrossDomainGovernor.owner(), s_l1OwnerAddr); + + // it should set the l1Owner correctly + assertEq(s_scrollCrossDomainGovernor.l1Owner(), s_l1OwnerAddr); + + // it should set the crossdomain messenger correctly + assertEq(s_scrollCrossDomainGovernor.crossDomainMessenger(), address(s_mockScrollCrossDomainMessenger)); + + // it should set the typeAndVersion correctly + assertEq(s_scrollCrossDomainGovernor.typeAndVersion(), "ScrollCrossDomainGovernor 1.0.0"); + } +} + +contract ScrollCrossDomainGovernor_Forward is ScrollCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_scrollCrossDomainGovernor.forward(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_Forward() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + encodeCrossDomainSetGreetingMsg(s_scrollCrossDomainGovernor.forward.selector, address(s_greeter), greeting), // message + 0 // gas limit + ); + + // Checks that the greeter got the message + assertEq(s_greeter.greeting(), greeting); + } + + /// @notice it should revert when contract call reverts + function test_ForwardRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message + vm.expectRevert("Invalid greeting length"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + encodeCrossDomainSetGreetingMsg(s_scrollCrossDomainGovernor.forward.selector, address(s_greeter), ""), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Defines the cross domain message to send + string memory greeting = "hello"; + + // Sends the message + s_scrollCrossDomainGovernor.forward( + address(s_greeter), + abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting) + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), greeting); + } +} + +contract ScrollCrossDomainGovernor_ForwardDelegate is ScrollCrossDomainGovernorTest { + /// @notice it should not be callable by unknown address + function test_NotCallableByUnknownAddress() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger or owner"); + s_scrollCrossDomainGovernor.forwardDelegate(address(s_greeter), abi.encode("")); + } + + /// @notice it should be callable by crossdomain messenger address / L1 owner + function test_CallableByCrossDomainMessengerAddressOrL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + encodeCrossDomainMultiSendMsg( + s_scrollCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should be callable by L2 owner + function test_CallableByL2Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_l1OwnerAddr); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + encodeCrossDomainMultiSendMsg( + s_scrollCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "bar")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message was updated + assertEq(s_greeter.greeting(), "bar"); + } + + /// @notice it should revert batch when one call fails + function test_RevertsBatchWhenOneCallFails() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Governor delegatecall reverted"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + encodeCrossDomainMultiSendMsg( + s_scrollCrossDomainGovernor.forwardDelegate.selector, + address(s_multiSend), + abi.encodePacked(encodeMultiSendTx(address(s_greeter), "foo"), encodeMultiSendTx(address(s_greeter), "")) + ), // message + 0 // gas limit + ); + + // Checks that the greeter message is unchanged + assertEq(s_greeter.greeting(), ""); + } + + /// @notice it should bubble up revert when contract call reverts + function test_BubbleUpRevert() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends an invalid message (empty transaction data is not allowed) + vm.expectRevert("Greeter: revert triggered"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector( + ScrollCrossDomainGovernor.forwardDelegate.selector, + address(s_greeter), + abi.encodeWithSelector(Greeter.triggerRevert.selector) + ), // message + 0 // gas limit + ); + } +} + +contract ScrollCrossDomainGovernor_TransferL1Ownership is ScrollCrossDomainGovernorTest { + /// @notice it should not be callable by non-owners + function test_NotCallableByNonOwners() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_scrollCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should not be callable by L2 owner + function test_NotCallableByL2Owner() public { + vm.startPrank(s_l1OwnerAddr); + assertEq(s_scrollCrossDomainGovernor.owner(), s_l1OwnerAddr); + vm.expectRevert("Sender is not the L2 messenger"); + s_scrollCrossDomainGovernor.transferL1Ownership(s_strangerAddr); + } + + /// @notice it should be callable by current L1 owner + function test_CallableByL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_scrollCrossDomainGovernor.l1Owner(), s_strangerAddr); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainGovernor.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by current L1 owner to zero address + function test_CallableByL1OwnerOrZeroAddress() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Defines the cross domain message to send + vm.expectEmit(); + emit L1OwnershipTransferRequested(s_scrollCrossDomainGovernor.l1Owner(), address(0)); + + // Sends the message + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainGovernor.transferL1Ownership.selector, address(0)), // message + 0 // gas limit + ); + } +} + +contract ScrollCrossDomainGovernor_AcceptL1Ownership is ScrollCrossDomainGovernorTest { + /// @notice it should not be callable by non pending-owners + function test_NotCallableByNonPendingOwners() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Sends the message + vm.expectRevert("Must be proposed L1 owner"); + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainGovernor.acceptL1Ownership.selector), // message + 0 // gas limit + ); + } + + /// @notice it should be callable by pending L1 owner + function test_CallableByPendingL1Owner() public { + // Sets msg.sender and tx.origin + vm.startPrank(s_strangerAddr); + + // Request ownership transfer + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainGovernor.transferL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Sets a mock message sender + s_mockScrollCrossDomainMessenger._setMockMessageSender(s_strangerAddr); + + // Prepares expected event payload + vm.expectEmit(); + emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr); + + // Accepts ownership transfer request + s_mockScrollCrossDomainMessenger.sendMessage( + address(s_scrollCrossDomainGovernor), // target + 0, // value + abi.encodeWithSelector(s_scrollCrossDomainGovernor.acceptL1Ownership.selector, s_strangerAddr), // message + 0 // gas limit + ); + + // Asserts that the ownership was actually transferred + assertEq(s_scrollCrossDomainGovernor.l1Owner(), s_strangerAddr); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol new file mode 100644 index 00000000000..520fbf6dfdc --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollSequencerUptimeFeed.t.sol @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockScrollL1CrossDomainMessenger} from "../../mocks/scroll/MockScrollL1CrossDomainMessenger.sol"; +import {MockScrollL2CrossDomainMessenger} from "../../mocks/scroll/MockScrollL2CrossDomainMessenger.sol"; +import {ScrollSequencerUptimeFeed} from "../../../dev/scroll/ScrollSequencerUptimeFeed.sol"; +import {FeedConsumer} from "../../../../tests/FeedConsumer.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ScrollSequencerUptimeFeedTest is L2EPTest { + /// Constants + uint256 internal constant GAS_USED_DEVIATION = 100; + + /// L2EP contracts + MockScrollL1CrossDomainMessenger internal s_mockScrollL1CrossDomainMessenger; + MockScrollL2CrossDomainMessenger internal s_mockScrollL2CrossDomainMessenger; + ScrollSequencerUptimeFeed internal s_scrollSequencerUptimeFeed; + + /// Events + event UpdateIgnored(bool latestStatus, uint64 latestTimestamp, bool incomingStatus, uint64 incomingTimestamp); + event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt); + event RoundUpdated(int256 status, uint64 updatedAt); + + /// Setup + function setUp() public { + // Deploys contracts + s_mockScrollL1CrossDomainMessenger = new MockScrollL1CrossDomainMessenger(); + s_mockScrollL2CrossDomainMessenger = new MockScrollL2CrossDomainMessenger(); + s_scrollSequencerUptimeFeed = new ScrollSequencerUptimeFeed( + s_l1OwnerAddr, + address(s_mockScrollL2CrossDomainMessenger), + false + ); + + // Sets mock sender in mock L2 messenger contract + s_mockScrollL2CrossDomainMessenger.setSender(s_l1OwnerAddr); + } +} + +contract ScrollSequencerUptimeFeed_Constructor is ScrollSequencerUptimeFeedTest { + /// @notice it should have been deployed with the correct initial state + function test_InitialState() public { + // L2 cross domain messenger address must not be the zero address + vm.expectRevert(ScrollSequencerUptimeFeed.ZeroAddress.selector); + new ScrollSequencerUptimeFeed(s_l1OwnerAddr, address(0), false); + + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Checks L1 sender + address actualL1Addr = s_scrollSequencerUptimeFeed.l1Sender(); + assertEq(actualL1Addr, s_l1OwnerAddr); + + // Checks latest round data + (uint80 roundId, int256 answer, , , ) = s_scrollSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract ScrollSequencerUptimeFeed_UpdateStatus is ScrollSequencerUptimeFeedTest { + /// @notice it should revert if called by an address that is not the L2 Cross Domain Messenger + function test_RevertIfNotL2CrossDomainMessengerAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(ScrollSequencerUptimeFeed.InvalidSender.selector); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should revert if called by an address that is not the L2 Cross Domain Messenger and is not the L1 sender + function test_RevertIfNotL2CrossDomainMessengerAddrAndNotL1SenderAddr() public { + // Sets msg.sender and tx.origin to an unauthorized address + vm.startPrank(s_strangerAddr, s_strangerAddr); + + // Sets mock sender in mock L2 messenger contract + s_mockScrollL2CrossDomainMessenger.setSender(s_strangerAddr); + + // Tries to update the status from an unauthorized account + vm.expectRevert(ScrollSequencerUptimeFeed.InvalidSender.selector); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(1)); + } + + /// @notice it should update status when status has not changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenNoChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Fetches the latest timestamp + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Stores the current round data before updating it + ( + uint80 roundIdBeforeUpdate, + int256 answerBeforeUpdate, + uint256 startedAtBeforeUpdate, + , + uint80 answeredInRoundBeforeUpdate + ) = s_scrollSequencerUptimeFeed.latestRoundData(); + + // Submit another status update with the same status + vm.expectEmit(); + emit RoundUpdated(1, uint64(block.timestamp)); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 200)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Stores the current round data after updating it + ( + uint80 roundIdAfterUpdate, + int256 answerAfterUpdate, + uint256 startedAtAfterUpdate, + uint256 updatedAtAfterUpdate, + uint80 answeredInRoundAfterUpdate + ) = s_scrollSequencerUptimeFeed.latestRoundData(); + + // Verifies the latest round data has been properly updated + assertEq(roundIdAfterUpdate, roundIdBeforeUpdate); + assertEq(answerAfterUpdate, answerBeforeUpdate); + assertEq(startedAtAfterUpdate, startedAtBeforeUpdate); + assertEq(answeredInRoundAfterUpdate, answeredInRoundBeforeUpdate); + assertEq(updatedAtAfterUpdate, block.timestamp); + } + + /// @notice it should update status when status has changed and incoming timestamp is newer than the latest + function test_UpdateStatusWhenStatusChangeAndTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp(); + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, newer timestamp should update + timestamp = timestamp + 200; + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should update status when status has changed and incoming timestamp is the same as latest + function test_UpdateStatusWhenStatusChangeAndNoTimeChange() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Fetches the latest timestamp + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp(); + + // Submits a status update + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Submit another status update, different status, same timestamp should update + vm.expectEmit(); + emit AnswerUpdated(0, 3, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 0); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + } + + /// @notice it should ignore out-of-order updates + function test_IgnoreOutOfOrderUpdates() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Submits a status update + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 10000; + vm.expectEmit(); + emit AnswerUpdated(1, 2, timestamp); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertEq(s_scrollSequencerUptimeFeed.latestTimestamp(), uint64(timestamp)); + + // Update with different status, but stale timestamp, should be ignored + timestamp = timestamp - 1000; + vm.expectEmit(false, false, false, false); + emit UpdateIgnored(true, 0, true, 0); // arguments are dummy values + // TODO: how can we check that an AnswerUpdated event was NOT emitted + s_scrollSequencerUptimeFeed.updateStatus(false, uint64(timestamp)); + } +} + +contract ScrollSequencerUptimeFeed_AggregatorV3Interface is ScrollSequencerUptimeFeedTest { + /// @notice it should return valid answer from getRoundData and latestRoundData + function test_AggregatorV3Interface() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables + uint80 roundId; + int256 answer; + uint256 startedAt; + uint256 updatedAt; + uint80 answeredInRound; + + // Checks initial state + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_scrollSequencerUptimeFeed.latestRoundData(); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Submits status update with different status and newer timestamp, should update + uint256 timestamp = startedAt + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_scrollSequencerUptimeFeed.getRoundData(2); + assertEq(roundId, 2); + assertEq(answer, 1); + assertEq(answeredInRound, roundId); + assertEq(startedAt, timestamp); + assertLe(updatedAt, startedAt); + + // Saves round 2 data + uint80 roundId2 = roundId; + int256 answer2 = answer; + uint256 startedAt2 = startedAt; + uint256 updatedAt2 = updatedAt; + uint80 answeredInRound2 = answeredInRound; + + // Checks that last round is still returning the correct data + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_scrollSequencerUptimeFeed.getRoundData(1); + assertEq(roundId, 1); + assertEq(answer, 0); + assertEq(answeredInRound, roundId); + assertEq(startedAt, updatedAt); + + // Assert latestRoundData corresponds to latest round id + (roundId, answer, startedAt, updatedAt, answeredInRound) = s_scrollSequencerUptimeFeed.latestRoundData(); + assertEq(roundId2, roundId); + assertEq(answer2, answer); + assertEq(startedAt2, startedAt); + assertEq(updatedAt2, updatedAt); + assertEq(answeredInRound2, answeredInRound); + } + + /// @notice it should revert from #getRoundData when round does not yet exist (future roundId) + function test_RevertGetRoundDataWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(ScrollSequencerUptimeFeed.NoDataPresent.selector); + s_scrollSequencerUptimeFeed.getRoundData(2); + } + + /// @notice it should revert from #getAnswer when round does not yet exist (future roundId) + function test_RevertGetAnswerWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(ScrollSequencerUptimeFeed.NoDataPresent.selector); + s_scrollSequencerUptimeFeed.getAnswer(2); + } + + /// @notice it should revert from #getTimestamp when round does not yet exist (future roundId) + function test_RevertGetTimestampWhenRoundDoesNotExistYet() public { + // Sets msg.sender and tx.origin to a valid address + vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr); + + // Gets data from a round that has not happened yet + vm.expectRevert(ScrollSequencerUptimeFeed.NoDataPresent.selector); + s_scrollSequencerUptimeFeed.getTimestamp(2); + } +} + +contract ScrollSequencerUptimeFeed_ProtectReadsOnAggregatorV2V3InterfaceFunctions is ScrollSequencerUptimeFeedTest { + /// @notice it should disallow reads on AggregatorV2V3Interface functions when consuming contract is not whitelisted + function test_AggregatorV2V3InterfaceDisallowReadsIfConsumingContractIsNotWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_scrollSequencerUptimeFeed)); + + // Sanity - consumer is not whitelisted + assertEq(s_scrollSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_scrollSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), false); + + // Asserts reads are not possible from consuming contract + vm.expectRevert("No access"); + feedConsumer.latestAnswer(); + vm.expectRevert("No access"); + feedConsumer.latestRoundData(); + } + + /// @notice it should allow reads on AggregatorV2V3Interface functions when consuming contract is whitelisted + function test_AggregatorV2V3InterfaceAllowReadsIfConsumingContractIsWhitelisted() public { + // Deploys a FeedConsumer contract + FeedConsumer feedConsumer = new FeedConsumer(address(s_scrollSequencerUptimeFeed)); + + // Whitelist consumer + s_scrollSequencerUptimeFeed.addAccess(address(feedConsumer)); + + // Sanity - consumer is whitelisted + assertEq(s_scrollSequencerUptimeFeed.checkEnabled(), true); + assertEq(s_scrollSequencerUptimeFeed.hasAccess(address(feedConsumer), abi.encode("")), true); + + // Asserts reads are possible from consuming contract + (uint80 roundId, int256 answer, , , ) = feedConsumer.latestRoundData(); + assertEq(feedConsumer.latestAnswer(), 0); + assertEq(roundId, 1); + assertEq(answer, 0); + } +} + +contract ScrollSequencerUptimeFeed_GasCosts is ScrollSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for updates + function test_GasCosts() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Assert initial conditions + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp(); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 0); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed; + uint256 gasStart; + uint256 gasFinal; + + // measures gas used for no update + expectedGasUsed = 10197; // NOTE: used to be 38594 in hardhat tests + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.updateStatus(false, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 0); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + + // measures gas used for update + expectedGasUsed = 31644; // NOTE: used to be 58458 in hardhat tests + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp + 1000)); + gasFinal = gasleft(); + assertEq(s_scrollSequencerUptimeFeed.latestAnswer(), 1); + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} + +contract ScrollSequencerUptimeFeed_AggregatorInterfaceGasCosts is ScrollSequencerUptimeFeedTest { + /// @notice it should consume a known amount of gas for getRoundData(uint80) + function test_GasUsageForGetRoundData() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 4504; // NOTE: used to be 30952 in hardhat tesst + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.getRoundData(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRoundData() + function test_GasUsageForLatestRoundData() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 2154; // NOTE: used to be 28523 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.latestRoundData(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestAnswer() + function test_GasUsageForLatestAnswer() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1566; // NOTE: used to be 28229 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.latestAnswer(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestTimestamp() + function test_GasUsageForLatestTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1459; // NOTE: used to be 28129 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.latestTimestamp(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for latestRound() + function test_GasUsageForLatestRound() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 1470; // NOTE: used to be 28145 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.latestRound(); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getAnswer() + function test_GasUsageForGetAnswer() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 3929; // NOTE: used to be 30682 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.getAnswer(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } + + /// @notice it should consume a known amount of gas for getTimestamp() + function test_GasUsageForGetTimestamp() public { + // Sets msg.sender and tx.origin to a valid address + address l2MessengerAddr = address(s_mockScrollL2CrossDomainMessenger); + vm.startPrank(l2MessengerAddr, l2MessengerAddr); + + // Defines helper variables for measuring gas usage + uint256 expectedGasUsed = 3817; // NOTE: used to be 30570 in hardhat tests + uint256 gasStart; + uint256 gasFinal; + + // Initializes a round + uint256 timestamp = s_scrollSequencerUptimeFeed.latestTimestamp() + 1000; + s_scrollSequencerUptimeFeed.updateStatus(true, uint64(timestamp)); + + // Measures gas usage + gasStart = gasleft(); + s_scrollSequencerUptimeFeed.getTimestamp(1); + gasFinal = gasleft(); + + // Checks that gas usage is within expected range + assertGasUsageIsCloseTo(expectedGasUsed, gasStart, gasFinal, GAS_USED_DEVIATION); + } +} diff --git a/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollValidator.t.sol b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollValidator.t.sol new file mode 100644 index 00000000000..969c78c72ef --- /dev/null +++ b/contracts/src/v0.8/l2ep/test/v1_0_0/scroll/ScrollValidator.t.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MockScrollL1CrossDomainMessenger} from "../../mocks/scroll/MockScrollL1CrossDomainMessenger.sol"; +import {MockScrollL2CrossDomainMessenger} from "../../mocks/scroll/MockScrollL2CrossDomainMessenger.sol"; +import {ScrollSequencerUptimeFeed} from "../../../dev/scroll/ScrollSequencerUptimeFeed.sol"; +import {ScrollValidator} from "../../../dev/scroll/ScrollValidator.sol"; +import {L2EPTest} from "../L2EPTest.t.sol"; + +contract ScrollValidatorTest is L2EPTest { + /// Helper constants + address internal constant L2_SEQ_STATUS_RECORDER_ADDRESS = 0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b; + uint32 internal constant INIT_GAS_LIMIT = 1900000; + + /// L2EP contracts + MockScrollL1CrossDomainMessenger internal s_mockScrollL1CrossDomainMessenger; + MockScrollL2CrossDomainMessenger internal s_mockScrollL2CrossDomainMessenger; + ScrollSequencerUptimeFeed internal s_scrollSequencerUptimeFeed; + ScrollValidator internal s_scrollValidator; + + /// https://github.com/scroll-tech/scroll/blob/03089eaeee1193ff44c532c7038611ae123e7ef3/contracts/src/libraries/IScrollMessenger.sol#L22 + event SentMessage( + address indexed sender, + address indexed target, + uint256 value, + uint256 messageNonce, + uint256 gasLimit, + bytes message + ); + + /// Setup + function setUp() public { + s_mockScrollL1CrossDomainMessenger = new MockScrollL1CrossDomainMessenger(); + s_mockScrollL2CrossDomainMessenger = new MockScrollL2CrossDomainMessenger(); + + s_scrollSequencerUptimeFeed = new ScrollSequencerUptimeFeed( + address(s_mockScrollL1CrossDomainMessenger), + address(s_mockScrollL2CrossDomainMessenger), + true + ); + + s_scrollValidator = new ScrollValidator( + address(s_mockScrollL1CrossDomainMessenger), + address(s_scrollSequencerUptimeFeed), + INIT_GAS_LIMIT + ); + } +} + +contract ScrollValidator_SetGasLimit is ScrollValidatorTest { + /// @notice it correctly updates the gas limit + function test_CorrectlyUpdatesTheGasLimit() public { + uint32 newGasLimit = 2000000; + assertEq(s_scrollValidator.getGasLimit(), INIT_GAS_LIMIT); + s_scrollValidator.setGasLimit(newGasLimit); + assertEq(s_scrollValidator.getGasLimit(), newGasLimit); + } +} + +contract ScrollValidator_Validate is ScrollValidatorTest { + /// @notice it reverts if called by account with no access + function test_RevertsIfCalledByAnAccountWithNoAccess() public { + vm.startPrank(s_strangerAddr); + vm.expectRevert("No access"); + s_scrollValidator.validate(0, 0, 1, 1); + } + + /// @notice it posts sequencer status when there is not status change + function test_PostSequencerStatusWhenThereIsNotStatusChange() public { + // Gives access to the s_eoaValidator + s_scrollValidator.addAccess(s_eoaValidator); + + // Sets block.timestamp to a later date + uint256 futureTimestampInSeconds = block.timestamp + 5000; + vm.startPrank(s_eoaValidator); + vm.warp(futureTimestampInSeconds); + + // Sets up the expected event data + vm.expectEmit(false, false, false, true); + emit SentMessage( + address(s_scrollValidator), // sender + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + 0, // value + 0, // nonce + INIT_GAS_LIMIT, // gas limit + abi.encodeWithSelector(ScrollSequencerUptimeFeed.updateStatus.selector, false, futureTimestampInSeconds) // message + ); + + // Runs the function (which produces the event to test) + s_scrollValidator.validate(0, 0, 0, 0); + } + + /// @notice it post sequencer offline + function test_PostSequencerOffline() public { + // Gives access to the s_eoaValidator + s_scrollValidator.addAccess(s_eoaValidator); + + // Sets block.timestamp to a later date + uint256 futureTimestampInSeconds = block.timestamp + 10000; + vm.startPrank(s_eoaValidator); + vm.warp(futureTimestampInSeconds); + + // Sets up the expected event data + vm.expectEmit(false, false, false, true); + emit SentMessage( + address(s_scrollValidator), // sender + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + 0, // value + 0, // nonce + INIT_GAS_LIMIT, // gas limit + abi.encodeWithSelector(ScrollSequencerUptimeFeed.updateStatus.selector, true, futureTimestampInSeconds) // message + ); + + // Runs the function (which produces the event to test) + s_scrollValidator.validate(0, 0, 1, 1); + } +} diff --git a/contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol b/contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol index 9691cfb7fea..53f79b6dc42 100644 --- a/contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol +++ b/contracts/src/v0.8/llo-feeds/libraries/ByteUtil.sol @@ -16,6 +16,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint256 read from the byte array. */ + // solhint-disable-next-line chainlink-solidity/explicit-returns function _readUint256(bytes memory data, uint256 offset) internal pure returns (uint256 result) { //bounds check if (offset + 32 > data.length) revert MalformedData(); @@ -32,6 +33,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint192 read from the byte array. */ + // solhint-disable-next-line chainlink-solidity/explicit-returns function _readUint192(bytes memory data, uint256 offset) internal pure returns (uint256 result) { //bounds check if (offset + 24 > data.length) revert MalformedData(); @@ -50,6 +52,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint32 read from the byte array. */ + // solhint-disable-next-line chainlink-solidity/explicit-returns function _readUint32(bytes memory data, uint256 offset) internal pure returns (uint256 result) { //bounds check if (offset + 4 > data.length) revert MalformedData(); @@ -68,6 +71,7 @@ library ByteUtil { * @param offset Position to start reading from. * @return result The uint32 read from the byte array. */ + // solhint-disable-next-line chainlink-solidity/explicit-returns function _readAddress(bytes memory data, uint256 offset) internal pure returns (address result) { //bounds check if (offset + 20 > data.length) revert MalformedData(); diff --git a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol index c8451bf03ce..26295b27d16 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/Operator.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/Operator.sol @@ -318,7 +318,8 @@ contract Operator is AuthorizedReceiver, ConfirmedOwner, LinkTokenReceiver, Oper for (uint256 i = 0; i < receivers.length; ++i) { uint256 sendAmount = amounts[i]; valueRemaining = valueRemaining - sendAmount; - receivers[i].transfer(sendAmount); + (bool success, ) = receivers[i].call{value: sendAmount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); } require(valueRemaining == 0, "Too much ETH sent"); } diff --git a/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol b/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol index 62ace2451c5..0ff4bb6562e 100644 --- a/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol +++ b/contracts/src/v0.8/operatorforwarder/dev/OperatorFactory.sol @@ -34,7 +34,7 @@ contract OperatorFactory { } // @notice creates a new Operator contract with the msg.sender as owner and a - // new Operator Forwarder with the Operator as the owner + // new Operator Forwarder with the OperatorFactory as the owner function deployNewOperatorAndForwarder() external returns (address, address) { Operator operator = new Operator(linkToken, msg.sender); s_created[address(operator)] = true; diff --git a/contracts/src/v0.8/shared/test/helpers/ChainReaderTestContract.sol b/contracts/src/v0.8/shared/test/helpers/ChainReaderTestContract.sol new file mode 100644 index 00000000000..050f5fb390e --- /dev/null +++ b/contracts/src/v0.8/shared/test/helpers/ChainReaderTestContract.sol @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8; + +struct TestStruct { + int32 Field; + string DifferentField; + uint8 OracleId; + uint8[32] OracleIds; + address Account; + address[] Accounts; + int192 BigField; + MidLevelTestStruct NestedStruct; +} + +struct MidLevelTestStruct { + bytes2 FixedBytes; + InnerTestStruct Inner; +} + +struct InnerTestStruct { + int64 IntVal; + string S; +} + +contract LatestValueHolder { + event Triggered( + int32 indexed field, + string differentField, + uint8 oracleId, + uint8[32] oracleIds, + address Account, + address[] Accounts, + int192 bigField, + MidLevelTestStruct nestedStruct + ); + + event TriggeredEventWithDynamicTopic(string indexed fieldHash, string field); + + // First topic is event hash + event TriggeredWithFourTopics(int32 indexed field1, int32 indexed field2, int32 indexed field3); + + TestStruct[] private s_seen; + uint64[] private s_arr; + + constructor() { + // See chain_reader_interface_tests.go in chainlink-relay + s_arr.push(3); + s_arr.push(4); + } + + function addTestStruct( + int32 field, + string calldata differentField, + uint8 oracleId, + uint8[32] calldata oracleIds, + address account, + address[] calldata accounts, + int192 bigField, + MidLevelTestStruct calldata nestedStruct + ) public { + s_seen.push(TestStruct(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct)); + } + + function returnSeen( + int32 field, + string calldata differentField, + uint8 oracleId, + uint8[32] calldata oracleIds, + address account, + address[] calldata accounts, + int192 bigField, + MidLevelTestStruct calldata nestedStruct + ) public pure returns (TestStruct memory) { + return TestStruct(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct); + } + + function getElementAtIndex(uint256 i) public view returns (TestStruct memory) { + // See chain_reader_interface_tests.go in chainlink-relay + return s_seen[i - 1]; + } + + function getPrimitiveValue() public pure returns (uint64) { + // See chain_reader_interface_tests.go in chainlink-relay + return 3; + } + + function getDifferentPrimitiveValue() public pure returns (uint64) { + // See chain_reader_interface_tests.go in chainlink-relay + return 1990; + } + + function getSliceValue() public view returns (uint64[] memory) { + return s_arr; + } + + function triggerEvent( + int32 field, + string calldata differentField, + uint8 oracleId, + uint8[32] calldata oracleIds, + address account, + address[] calldata accounts, + int192 bigField, + MidLevelTestStruct calldata nestedStruct + ) public { + emit Triggered(field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct); + } + + function triggerEventWithDynamicTopic(string calldata field) public { + emit TriggeredEventWithDynamicTopic(field, field); + } + + // first topic is the event signature + function triggerWithFourTopics(int32 field1, int32 field2, int32 field3) public { + emit TriggeredWithFourTopics(field1, field2, field3); + } +} diff --git a/contracts/src/v0.8/tests/LogEmitter.sol b/contracts/src/v0.8/tests/LogEmitter.sol index d3f950c5ccb..37306cc2bc5 100644 --- a/contracts/src/v0.8/tests/LogEmitter.sol +++ b/contracts/src/v0.8/tests/LogEmitter.sol @@ -5,6 +5,7 @@ contract LogEmitter { event Log1(uint256); event Log2(uint256 indexed); event Log3(string); + event Log4(uint256 indexed, uint256 indexed); function EmitLog1(uint256[] memory v) public { for (uint256 i = 0; i < v.length; i++) { @@ -23,4 +24,10 @@ contract LogEmitter { emit Log3(v[i]); } } + + function EmitLog4(uint256 v, uint256 w, uint256 c) public { + for (uint256 i = 0; i < c; i++) { + emit Log4(v, w); + } + } } diff --git a/contracts/src/v0.8/tests/MockArbitrumInbox.sol b/contracts/src/v0.8/tests/MockArbitrumInbox.sol index cd85ed4d6ea..445a361b309 100644 --- a/contracts/src/v0.8/tests/MockArbitrumInbox.sol +++ b/contracts/src/v0.8/tests/MockArbitrumInbox.sol @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + import {IInbox} from "../vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IInbox.sol"; import {IBridge} from "../vendor/arb-bridge-eth/v0.8.0-custom/contracts/bridge/interfaces/IBridge.sol"; @@ -13,46 +16,46 @@ contract MockArbitrumInbox is IInbox { bytes data ); - function sendL2Message(bytes calldata messageData) external override returns (uint256) { + function sendL2Message(bytes calldata /* messageData */) external pure override returns (uint256) { return 0; } function sendUnsignedTransaction( - uint256 maxGas, - uint256 gasPriceBid, - uint256 nonce, - address destAddr, - uint256 amount, - bytes calldata data - ) external override returns (uint256) { + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + uint256 /* nonce */, + address /* destAddr */, + uint256 /* amount */, + bytes calldata /* data */ + ) external pure override returns (uint256) { return 0; } function sendContractTransaction( - uint256 maxGas, - uint256 gasPriceBid, - address destAddr, - uint256 amount, - bytes calldata data - ) external override returns (uint256) { + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + address /* destAddr */, + uint256 /* amount */, + bytes calldata /* data */ + ) external pure override returns (uint256) { return 0; } function sendL1FundedUnsignedTransaction( - uint256 maxGas, - uint256 gasPriceBid, - uint256 nonce, - address destAddr, - bytes calldata data + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + uint256 /* nonce */, + address /* destAddr */, + bytes calldata /* data */ ) external payable override returns (uint256) { return 0; } function sendL1FundedContractTransaction( - uint256 maxGas, - uint256 gasPriceBid, - address destAddr, - bytes calldata data + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + address /* destAddr */, + bytes calldata /* data */ ) external payable override returns (uint256) { return 0; } @@ -81,32 +84,32 @@ contract MockArbitrumInbox is IInbox { } function createRetryableTicket( - address destAddr, - uint256 arbTxCallValue, - uint256 maxSubmissionCost, - address submissionRefundAddress, - address valueRefundAddress, - uint256 maxGas, - uint256 gasPriceBid, - bytes calldata data + address /* destAddr */, + uint256 /* arbTxCallValue */, + uint256 /* maxSubmissionCost */, + address /* submissionRefundAddress */, + address /* valueRefundAddress */, + uint256 /* maxGas */, + uint256 /* gasPriceBid */, + bytes calldata /* data */ ) external payable override returns (uint256) { return 0; } - function depositEth(address destAddr) external payable override returns (uint256) { + function depositEth(address /* destAddr */) external payable override returns (uint256) { return 0; } function depositEthRetryable( - address destAddr, - uint256 maxSubmissionCost, - uint256 maxGas, - uint256 maxGasPrice + address /* destAddr */, + uint256 /* maxSubmissionCost */, + uint256 /* maxGas */, + uint256 /* maxGasPrice */ ) external payable override returns (uint256) { return 0; } - function bridge() external view override returns (IBridge) { + function bridge() external pure override returns (IBridge) { return IBridge(address(0)); } diff --git a/contracts/src/v0.8/tests/MockOptimismL1CrossDomainMessenger.sol b/contracts/src/v0.8/tests/MockOptimismL1CrossDomainMessenger.sol index 3184e7bb4a5..a92ff8fb556 100644 --- a/contracts/src/v0.8/tests/MockOptimismL1CrossDomainMessenger.sol +++ b/contracts/src/v0.8/tests/MockOptimismL1CrossDomainMessenger.sol @@ -8,7 +8,7 @@ contract MockOptimismL1CrossDomainMessenger is IL1CrossDomainMessenger { uint256 private s_nonce; // slither-disable-next-line external-function - function xDomainMessageSender() public view returns (address) { + function xDomainMessageSender() public pure returns (address) { return address(0); } diff --git a/contracts/src/v0.8/tests/VRFLogEmitter.sol b/contracts/src/v0.8/tests/VRFLogEmitter.sol new file mode 100644 index 00000000000..18b99605ac9 --- /dev/null +++ b/contracts/src/v0.8/tests/VRFLogEmitter.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract VRFLogEmitter { + event RandomWordsRequested( + bytes32 indexed keyHash, + uint256 requestId, + uint256 preSeed, + uint64 indexed subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords, + address indexed sender + ); + event RandomWordsFulfilled(uint256 indexed requestId, uint256 outputSeed, uint96 payment, bool success); + + function emitRandomWordsRequested( + bytes32 keyHash, + uint256 requestId, + uint256 preSeed, + uint64 subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords, + address sender + ) public { + emit RandomWordsRequested( + keyHash, + requestId, + preSeed, + subId, + minimumRequestConfirmations, + callbackGasLimit, + numWords, + sender + ); + } + + function emitRandomWordsFulfilled(uint256 requestId, uint256 outputSeed, uint96 payment, bool success) public { + emit RandomWordsFulfilled(requestId, outputSeed, payment, success); + } +} diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol index 970ddf6b7e6..38b6fb57983 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/Paymaster.sol @@ -103,6 +103,7 @@ contract Paymaster is IPaymaster, ConfirmedOwner { extraCost = directFundingData.topupAmount; } } + return extraCost; } /// @dev Deducts user subscription balance after execution. @@ -116,6 +117,7 @@ contract Paymaster is IPaymaster, ConfirmedOwner { function _getCostJuels(uint256 costWei) internal view returns (uint256 costJuels) { costJuels = (1e18 * costWei) / uint256(_getFeedData()); + return costJuels; } function _getFeedData() internal view returns (int256) { diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol index 47587e278f4..35d666a2d3d 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/SCALibrary.sol @@ -31,6 +31,7 @@ library SCALibrary { hashOfEncoding ) ); + return fullHash; } function _recoverSignature(bytes memory signature, bytes32 fullHash) internal pure returns (address) { diff --git a/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol b/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol index 35719345ecd..bb0f2dbde63 100644 --- a/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol +++ b/contracts/src/v0.8/transmission/dev/ERC-4337/SmartContractAccountFactory.sol @@ -27,5 +27,7 @@ contract SmartContractAccountFactory { } emit ContractCreated(scaAddress); + + return scaAddress; } } diff --git a/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol b/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol index c33df49d16b..014f296f077 100644 --- a/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol +++ b/contracts/src/v0.8/transmission/dev/testhelpers/SmartContractAccountHelper.sol @@ -18,6 +18,7 @@ library SmartContractAccountHelper { SCA.executeTransactionFromEntryPoint.selector, abi.encode(endContract, value, block.timestamp + deadline, data) ); + return encoding; } function getFullHashForSigning(bytes32 userOpHash, address scaAddress) public view returns (bytes32) { @@ -29,6 +30,7 @@ library SmartContractAccountHelper { address entryPoint ) public pure returns (bytes memory initCode) { initCode = bytes.concat(INITIALIZE_CODE, abi.encode(owner, entryPoint)); + return initCode; } function getInitCode( @@ -46,6 +48,7 @@ library SmartContractAccountHelper { initializeCodeWithConstructor ) ); + return initCode; } /// @dev Computes the smart contract address that results from a CREATE2 operation, per EIP-1014. diff --git a/contracts/src/v0.8/vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol b/contracts/src/v0.8/vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol index 6d74788e352..8b5aad82e5d 100644 --- a/contracts/src/v0.8/vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol +++ b/contracts/src/v0.8/vendor/@eth-optimism/contracts/v0.4.7/contracts/optimistic-ethereum/iOVM/bridge/messaging/iOVM_CrossDomainMessenger.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity >=0.7.6 <0.9.0; /** @@ -28,9 +29,5 @@ interface iOVM_CrossDomainMessenger { * @param _message Message to send to the target. * @param _gasLimit Gas limit for the provided message. */ - function sendMessage( - address _target, - bytes calldata _message, - uint32 _gasLimit - ) external; + function sendMessage(address _target, bytes calldata _message, uint32 _gasLimit) external; } diff --git a/contracts/src/v0.8/vendor/MockScrollCrossDomainMessenger.sol b/contracts/src/v0.8/vendor/MockScrollCrossDomainMessenger.sol new file mode 100644 index 00000000000..bb5390b945d --- /dev/null +++ b/contracts/src/v0.8/vendor/MockScrollCrossDomainMessenger.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.16; + +import "./openzeppelin-solidity/v4.8.3/contracts/utils/Address.sol"; + +/// sourced from: https://github.com/scroll-tech/scroll/blob/develop/contracts/src/libraries/IScrollMessenger.sol +interface IScrollMessenger { + /// ********** + /// * Events * + /// ********** + + /// @notice Emitted when a cross domain message is sent. + /// @param sender The address of the sender who initiates the message. + /// @param target The address of target contract to call. + /// @param value The amount of value passed to the target contract. + /// @param messageNonce The nonce of the message. + /// @param gasLimit The optional gas limit passed to L1 or L2. + /// @param message The calldata passed to the target contract. + event SentMessage( + address indexed sender, + address indexed target, + uint256 value, + uint256 messageNonce, + uint256 gasLimit, + bytes message + ); + + /// @notice Emitted when a cross domain message is relayed successfully. + /// @param messageHash The hash of the message. + event RelayedMessage(bytes32 indexed messageHash); + + /// @notice Emitted when a cross domain message is failed to relay. + /// @param messageHash The hash of the message. + event FailedRelayedMessage(bytes32 indexed messageHash); + + /// ************************* + /// * Public View Functions * + /// ************************* + + /// @notice Return the sender of a cross domain message. + function xDomainMessageSender() external view returns (address); + + /// ***************************** + /// * Public Mutating Functions * + /// ***************************** + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param target The address of account who receive the message. + /// @param value The amount of ether passed when call target contract. + /// @param message The content of the message. + /// @param gasLimit Gas limit required to complete the message relay on corresponding chain. + function sendMessage(address target, uint256 value, bytes calldata message, uint256 gasLimit) external payable; + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param target The address of account who receive the message. + /// @param value The amount of ether passed when call target contract. + /// @param message The content of the message. + /// @param gasLimit Gas limit required to complete the message relay on corresponding chain. + /// @param refundAddress The address of account who will receive the refunded fee. + function sendMessage( + address target, + uint256 value, + bytes calldata message, + uint256 gasLimit, + address refundAddress + ) external payable; +} + +contract MockScrollCrossDomainMessenger is IScrollMessenger { + address internal mockMessageSender; + + constructor(address sender) { + mockMessageSender = sender; + } + + function xDomainMessageSender() external view override returns (address) { + return mockMessageSender; + } + + function _setMockMessageSender(address sender) external { + mockMessageSender = sender; + } + + /// ***************************** + /// * Public Mutating Functions * + /// ***************************** + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param _target The address of account who receive the message. + /// @param _message The content of the message. + function sendMessage(address _target, uint256, bytes calldata _message, uint256) external payable override { + Address.functionCall(_target, _message, "sendMessage reverted"); + } + + /// @notice Send cross chain message from L1 to L2 or L2 to L1. + /// @param _target The address of account who receive the message. + /// @param _message The content of the message. + function sendMessage(address _target, uint256, bytes calldata _message, uint256, address) external payable override { + Address.functionCall(_target, _message, "sendMessage reverted"); + } +} diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/AccessControl.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/AccessControl.sol new file mode 100644 index 00000000000..4e388f9d83d --- /dev/null +++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/AccessControl.sol @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControl.sol"; +import "../utils/Context.sol"; +import "../utils/Strings.sol"; +import "../utils/introspection/ERC165.sol"; + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * in the external API and be unique. The best way to achieve this is by + * using `public constant` hash digests: + * + * ``` + * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); + * ``` + * + * Roles can be used to represent a set of permissions. To restrict access to a + * function call, use {hasRole}: + * + * ``` + * function foo() public { + * require(hasRole(MY_ROLE, msg.sender)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to + * grant and revoke this role. Extra precautions should be taken to secure + * accounts that have been granted it. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address => bool) members; + bytes32 adminRole; + } + + mapping(bytes32 => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with a standardized message including the required role. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + * + * _Available since v4.1._ + */ + modifier onlyRole(bytes32 role) { + _checkRole(role); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual override returns (bool) { + return _roles[role].members[account]; + } + + /** + * @dev Revert with a standard message if `_msgSender()` is missing `role`. + * Overriding this function changes the behavior of the {onlyRole} modifier. + * + * Format of the revert message is described in {_checkRole}. + * + * _Available since v4.6._ + */ + function _checkRole(bytes32 role) internal view virtual { + _checkRole(role, _msgSender()); + } + + /** + * @dev Revert with a standard message if `account` is missing `role`. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert( + string( + abi.encodePacked( + "AccessControl: account ", + Strings.toHexString(account), + " is missing role ", + Strings.toHexString(uint256(role), 32) + ) + ) + ); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleGranted} event. + */ + function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleRevoked} event. + */ + function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + * + * May emit a {RoleRevoked} event. + */ + function renounceRole(bytes32 role, address account) public virtual override { + require(account == _msgSender(), "AccessControl: can only renounce roles for self"); + + _revokeRole(role, account); + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. Note that unlike {grantRole}, this function doesn't perform any + * checks on the calling account. + * + * May emit a {RoleGranted} event. + * + * [WARNING] + * ==== + * This function should only be called from the constructor when setting + * up the initial roles for the system. + * + * Using this function in any other way is effectively circumventing the admin + * system imposed by {AccessControl}. + * ==== + * + * NOTE: This function is deprecated in favor of {_grantRole}. + */ + function _setupRole(bytes32 role, address account) internal virtual { + _grantRole(role, account); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Grants `role` to `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleGranted} event. + */ + function _grantRole(bytes32 role, address account) internal virtual { + if (!hasRole(role, account)) { + _roles[role].members[account] = true; + emit RoleGranted(role, account, _msgSender()); + } + } + + /** + * @dev Revokes `role` from `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleRevoked} event. + */ + function _revokeRole(bytes32 role, address account) internal virtual { + if (hasRole(role, account)) { + _roles[role].members[account] = false; + emit RoleRevoked(role, account, _msgSender()); + } + } +} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/IAccessControl.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/IAccessControl.sol new file mode 100644 index 00000000000..efb82a3cb5e --- /dev/null +++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/access/IAccessControl.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + +pragma solidity ^0.8.0; + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} \ No newline at end of file diff --git a/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol new file mode 100644 index 00000000000..c682b07a65b --- /dev/null +++ b/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/ERC165.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} \ No newline at end of file diff --git a/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol b/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol index a18c6e03798..20fd806b0cc 100644 --- a/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol +++ b/contracts/src/v0.8/vrf/KeepersVRFConsumer.sol @@ -61,6 +61,7 @@ contract KeepersVRFConsumer is KeeperCompatibleInterface, VRFConsumerBaseV2 { * @return upkeepNeeded true if and only if at least UPKEEP_INTERVAL seconds have elapsed since the last upkeep or since construction * of the contract. */ + // solhint-disable-next-line chainlink-solidity/explicit-returns function checkUpkeep( bytes calldata /* checkData */ ) external view override returns (bool upkeepNeeded, bytes memory /* performData */) { diff --git a/contracts/src/v0.8/vrf/VRF.sol b/contracts/src/v0.8/vrf/VRF.sol index a19fc39ec3e..f7d62a272bc 100644 --- a/contracts/src/v0.8/vrf/VRF.sol +++ b/contracts/src/v0.8/vrf/VRF.sol @@ -205,6 +205,7 @@ contract VRF { while (x_ >= FIELD_SIZE) { x_ = uint256(keccak256(abi.encodePacked(x_))); } + return x_; } // Hash b to a random point which hopefully lies on secp256k1. The y ordinate @@ -223,6 +224,7 @@ contract VRF { p[1] = FIELD_SIZE - p[1]; } } + return p; } // Domain-separation tag for initial hash in _hashToCurve. Corresponds to @@ -248,6 +250,7 @@ contract VRF { while (!_isOnCurve(rv)) { rv = _newCandidateSecp256k1Point(abi.encodePacked(rv[0])); } + return rv; } /** ********************************************************************* @@ -294,6 +297,7 @@ contract VRF { uint256 num2 = mulmod(FIELD_SIZE - x2, z1, FIELD_SIZE); (x3, z3) = (addmod(num1, num2, FIELD_SIZE), mulmod(z1, z2, FIELD_SIZE)); } + return (x3, z3); } // Returns x1/z1*x2/z2=(x1x2)/(z1z2), in projective coordinates on P¹(𝔽ₙ) @@ -304,6 +308,7 @@ contract VRF { uint256 z2 ) internal pure returns (uint256 x3, uint256 z3) { (x3, z3) = (mulmod(x1, x2, FIELD_SIZE), mulmod(z1, z2, FIELD_SIZE)); + return (x3, z3); } /** ************************************************************************** @@ -385,6 +390,7 @@ contract VRF { sz = dx; } } + return (sx, sy, sz); } // p1+p2, as affine points on secp256k1. @@ -577,5 +583,6 @@ contract VRF { proof.zInv ); output = uint256(keccak256(abi.encode(VRF_RANDOM_OUTPUT_HASH_PREFIX, proof.gamma))); + return output; } } diff --git a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol index 5acd3e74358..5dfb51a4b13 100644 --- a/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol +++ b/contracts/src/v0.8/vrf/VRFCoordinatorV2.sol @@ -491,6 +491,7 @@ contract VRFCoordinatorV2 is VRF, ConfirmedOwner, TypeAndVersionInterface, VRFCo // The seed actually used by the VRF machinery, mixing in the blockhash uint256 actualSeed = uint256(keccak256(abi.encodePacked(proof.seed, blockHash))); randomness = VRF._randomValueFromVRFProof(proof, actualSeed); // Reverts on failure + return (keyHash, requestId, randomness); } /* diff --git a/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol b/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol index d7cc5b86c5a..9d4acecdef9 100644 --- a/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol +++ b/contracts/src/v0.8/vrf/dev/SubscriptionAPI.sol @@ -83,8 +83,8 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr // A discrepancy with this contract's native balance indicates someone // sent native using transfer and so we may need to use recoverNativeFunds. uint96 public s_totalNativeBalance; - mapping(address => uint96) /* oracle */ /* LINK balance */ internal s_withdrawableTokens; - mapping(address => uint96) /* oracle */ /* native balance */ internal s_withdrawableNative; + uint96 internal s_withdrawableTokens; + uint96 internal s_withdrawableNative; event SubscriptionCreated(uint256 indexed subId, address owner); event SubscriptionFunded(uint256 indexed subId, uint256 oldBalance, uint256 newBalance); @@ -204,18 +204,19 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr } /* - * @notice Oracle withdraw LINK earned through fulfilling requests + * @notice withdraw LINK earned through fulfilling requests * @param recipient where to send the funds * @param amount amount to withdraw */ - function oracleWithdraw(address recipient, uint96 amount) external nonReentrant { + function withdraw(address recipient) external nonReentrant onlyOwner { if (address(LINK) == address(0)) { revert LinkNotSet(); } - if (s_withdrawableTokens[msg.sender] < amount) { + if (s_withdrawableTokens == 0) { revert InsufficientBalance(); } - s_withdrawableTokens[msg.sender] -= amount; + uint96 amount = s_withdrawableTokens; + s_withdrawableTokens -= amount; s_totalBalance -= amount; if (!LINK.transfer(recipient, amount)) { revert InsufficientBalance(); @@ -223,16 +224,17 @@ abstract contract SubscriptionAPI is ConfirmedOwner, IERC677Receiver, IVRFSubscr } /* - * @notice Oracle withdraw native earned through fulfilling requests + * @notice withdraw native earned through fulfilling requests * @param recipient where to send the funds * @param amount amount to withdraw */ - function oracleWithdrawNative(address payable recipient, uint96 amount) external nonReentrant { - if (s_withdrawableNative[msg.sender] < amount) { + function withdrawNative(address payable recipient) external nonReentrant onlyOwner { + if (s_withdrawableNative == 0) { revert InsufficientBalance(); } // Prevent re-entrancy by updating state before transfer. - s_withdrawableNative[msg.sender] -= amount; + uint96 amount = s_withdrawableNative; + s_withdrawableNative -= amount; s_totalNativeBalance -= amount; (bool sent, ) = recipient.call{value: amount}(""); if (!sent) { diff --git a/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol b/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol index e0e46fe67b7..a265cea4ed9 100644 --- a/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol +++ b/contracts/src/v0.8/vrf/dev/VRFCoordinatorV2_5.sol @@ -44,11 +44,11 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { address sender; bytes extraArgs; } - mapping(bytes32 => address) /* keyHash */ /* oracle */ public s_provingKeys; + mapping(bytes32 => bool) /* keyHash */ /* exists */ public s_provingKeys; bytes32[] public s_provingKeyHashes; mapping(uint256 => bytes32) /* requestID */ /* commitment */ public s_requestCommitments; - event ProvingKeyRegistered(bytes32 keyHash, address indexed oracle); - event ProvingKeyDeregistered(bytes32 keyHash, address indexed oracle); + event ProvingKeyRegistered(bytes32 keyHash); + event ProvingKeyDeregistered(bytes32 keyHash); event RandomWordsRequested( bytes32 indexed keyHash, uint256 requestId, @@ -94,28 +94,26 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { } /** - * @notice Registers a proving key to an oracle. - * @param oracle address of the oracle + * @notice Registers a proving key to. * @param publicProvingKey key that oracle can use to submit vrf fulfillments */ - function registerProvingKey(address oracle, uint256[2] calldata publicProvingKey) external onlyOwner { + function registerProvingKey(uint256[2] calldata publicProvingKey) external onlyOwner { bytes32 kh = hashOfKey(publicProvingKey); - if (s_provingKeys[kh] != address(0)) { + if (s_provingKeys[kh]) { revert ProvingKeyAlreadyRegistered(kh); } - s_provingKeys[kh] = oracle; + s_provingKeys[kh] = true; s_provingKeyHashes.push(kh); - emit ProvingKeyRegistered(kh, oracle); + emit ProvingKeyRegistered(kh); } /** - * @notice Deregisters a proving key to an oracle. + * @notice Deregisters a proving key. * @param publicProvingKey key that oracle can use to submit vrf fulfillments */ function deregisterProvingKey(uint256[2] calldata publicProvingKey) external onlyOwner { bytes32 kh = hashOfKey(publicProvingKey); - address oracle = s_provingKeys[kh]; - if (oracle == address(0)) { + if (!s_provingKeys[kh]) { revert NoSuchProvingKey(kh); } delete s_provingKeys[kh]; @@ -127,7 +125,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { s_provingKeyHashes.pop(); } } - emit ProvingKeyDeregistered(kh, oracle); + emit ProvingKeyDeregistered(kh); } /** @@ -355,8 +353,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { ) internal view returns (Output memory) { bytes32 keyHash = hashOfKey(proof.pk); // Only registered proving keys are permitted. - address oracle = s_provingKeys[keyHash]; - if (oracle == address(0)) { + if (!s_provingKeys[keyHash]) { revert NoSuchProvingKey(keyHash); } uint256 requestId = uint256(keccak256(abi.encode(keyHash, proof.seed))); @@ -423,7 +420,7 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { 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. + // decrement the subscription balance and increment the withdrawable balance. uint96 payment = _calculatePaymentAmount( startGas, s_config.gasAfterPaymentCalculation, @@ -435,13 +432,13 @@ contract VRFCoordinatorV2_5 is VRF, SubscriptionAPI, IVRFCoordinatorV2Plus { revert InsufficientBalance(); } s_subscriptions[rc.subId].nativeBalance -= payment; - s_withdrawableNative[s_provingKeys[output.keyHash]] += payment; + s_withdrawableNative += payment; } else { if (s_subscriptions[rc.subId].balance < payment) { revert InsufficientBalance(); } s_subscriptions[rc.subId].balance -= payment; - s_withdrawableTokens[s_provingKeys[output.keyHash]] += payment; + s_withdrawableTokens += payment; } // Include payment in the event for tracking costs. diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol b/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol index 02cb15e38a4..ded916699b8 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/ExposedVRFCoordinatorV2_5.sol @@ -50,19 +50,19 @@ contract ExposedVRFCoordinatorV2_5 is VRFCoordinatorV2_5 { s_totalNativeBalance = newBalance; } - function setWithdrawableTokensTestingOnlyXXX(address oracle, uint96 newBalance) external { - s_withdrawableTokens[oracle] = newBalance; + function setWithdrawableTokensTestingOnlyXXX(uint96 newBalance) external { + s_withdrawableTokens = newBalance; } - function getWithdrawableTokensTestingOnlyXXX(address oracle) external view returns (uint96) { - return s_withdrawableTokens[oracle]; + function getWithdrawableTokensTestingOnlyXXX() external view returns (uint96) { + return s_withdrawableTokens; } - function setWithdrawableNativeTestingOnlyXXX(address oracle, uint96 newBalance) external { - s_withdrawableNative[oracle] = newBalance; + function setWithdrawableNativeTestingOnlyXXX(uint96 newBalance) external { + s_withdrawableNative = newBalance; } - function getWithdrawableNativeTestingOnlyXXX(address oracle) external view returns (uint96) { - return s_withdrawableNative[oracle]; + function getWithdrawableNativeTestingOnlyXXX() external view returns (uint96) { + return s_withdrawableNative; } } diff --git a/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol index 4837411955c..ca29adac87c 100644 --- a/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol +++ b/contracts/src/v0.8/vrf/dev/testhelpers/VRFCoordinatorV2PlusUpgradedVersion.sol @@ -56,11 +56,11 @@ contract VRFCoordinatorV2PlusUpgradedVersion is bytes extraArgs; } - mapping(bytes32 => address) /* keyHash */ /* oracle */ internal s_provingKeys; + mapping(bytes32 => bool) /* keyHash */ /* exists */ internal s_provingKeys; bytes32[] public s_provingKeyHashes; mapping(uint256 => bytes32) /* requestID */ /* commitment */ public s_requestCommitments; - event ProvingKeyRegistered(bytes32 keyHash, address indexed oracle); + event ProvingKeyRegistered(bytes32 keyHash); event RandomWordsRequested( bytes32 indexed keyHash, uint256 requestId, @@ -108,17 +108,16 @@ contract VRFCoordinatorV2PlusUpgradedVersion is /** * @notice Registers a proving key to an oracle. - * @param oracle address of the oracle * @param publicProvingKey key that oracle can use to submit vrf fulfillments */ - function registerProvingKey(address oracle, uint256[2] calldata publicProvingKey) external onlyOwner { + function registerProvingKey(uint256[2] calldata publicProvingKey) external onlyOwner { bytes32 kh = hashOfKey(publicProvingKey); - if (s_provingKeys[kh] != address(0)) { + if (s_provingKeys[kh]) { revert ProvingKeyAlreadyRegistered(kh); } - s_provingKeys[kh] = oracle; + s_provingKeys[kh] = true; s_provingKeyHashes.push(kh); - emit ProvingKeyRegistered(kh, oracle); + emit ProvingKeyRegistered(kh); } /** @@ -346,8 +345,7 @@ contract VRFCoordinatorV2PlusUpgradedVersion is ) internal view returns (Output memory) { bytes32 keyHash = hashOfKey(proof.pk); // Only registered proving keys are permitted. - address oracle = s_provingKeys[keyHash]; - if (oracle == address(0)) { + if (!s_provingKeys[keyHash]) { revert NoSuchProvingKey(keyHash); } uint256 requestId = uint256(keccak256(abi.encode(keyHash, proof.seed))); @@ -426,13 +424,13 @@ contract VRFCoordinatorV2PlusUpgradedVersion is revert InsufficientBalance(); } s_subscriptions[rc.subId].nativeBalance -= payment; - s_withdrawableNative[s_provingKeys[output.keyHash]] += payment; + s_withdrawableNative += payment; } else { if (s_subscriptions[rc.subId].balance < payment) { revert InsufficientBalance(); } s_subscriptions[rc.subId].balance -= payment; - s_withdrawableTokens[s_provingKeys[output.keyHash]] += payment; + s_withdrawableTokens += payment; } // Include payment in the event for tracking costs. diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorTestV2.sol b/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorTestV2.sol new file mode 100644 index 00000000000..04d09e2b9c4 --- /dev/null +++ b/contracts/src/v0.8/vrf/testhelpers/VRFCoordinatorTestV2.sol @@ -0,0 +1,837 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; +import {BlockhashStoreInterface} from "../interfaces/BlockhashStoreInterface.sol"; +import {AggregatorV3Interface} from "../../shared/interfaces/AggregatorV3Interface.sol"; +import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; +import {TypeAndVersionInterface} from "../../interfaces/TypeAndVersionInterface.sol"; +import {IERC677Receiver} from "../../shared/interfaces/IERC677Receiver.sol"; +import {VRF} from "../VRF.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; + +contract VRFCoordinatorTestV2 is + VRF, + ConfirmedOwner, + TypeAndVersionInterface, + VRFCoordinatorV2Interface, + IERC677Receiver +{ + LinkTokenInterface public immutable LINK; + AggregatorV3Interface public immutable LINK_ETH_FEED; + BlockhashStoreInterface public immutable BLOCKHASH_STORE; + + // We need to maintain a list of consuming addresses. + // This bound ensures we are able to loop over them as needed. + // Should a user require more consumers, they can use multiple subscriptions. + uint16 public constant MAX_CONSUMERS = 100; + + error TooManyConsumers(); + error InsufficientBalance(); + error InvalidConsumer(uint64 subId, address consumer); + error InvalidSubscription(); + error OnlyCallableFromLink(); + error InvalidCalldata(); + error MustBeSubOwner(address owner); + error PendingRequestExists(); + error MustBeRequestedOwner(address proposedOwner); + error BalanceInvariantViolated(uint256 internalBalance, uint256 externalBalance); // Should never happen + event FundsRecovered(address to, uint256 amount); + // We use the subscription struct (1 word) + // at fulfillment time. + struct Subscription { + // There are only 1e9*1e18 = 1e27 juels in existence, so the balance can fit in uint96 (2^96 ~ 7e28) + uint96 balance; // Common link balance used for all consumer requests. + uint64 reqCount; // For fee tiers + } + // We use the config for the mgmt APIs + struct SubscriptionConfig { + address owner; // Owner can fund/withdraw/cancel the sub. + address requestedOwner; // For safely transferring sub ownership. + // Maintains the list of keys in s_consumers. + // We do this for 2 reasons: + // 1. To be able to clean up all keys from s_consumers when canceling a subscription. + // 2. To be able to return the list of all consumers in getSubscription. + // Note that we need the s_consumers map to be able to directly check if a + // consumer is valid without reading all the consumers from storage. + address[] consumers; + } + // Note a nonce of 0 indicates an the consumer is not assigned to that subscription. + mapping(address => mapping(uint64 => uint64)) /* consumer */ /* subId */ /* nonce */ private s_consumers; + mapping(uint64 => SubscriptionConfig) /* subId */ /* subscriptionConfig */ private s_subscriptionConfigs; + mapping(uint64 => Subscription) /* subId */ /* subscription */ private s_subscriptions; + // We make the sub count public so that its possible to + // get all the current subscriptions via getSubscription. + uint64 private s_currentSubId; + // s_totalBalance tracks the total link sent to/from + // this contract through onTokenTransfer, cancelSubscription and oracleWithdraw. + // A discrepancy with this contract's link balance indicates someone + // sent tokens using transfer and so we may need to use recoverFunds. + uint96 private s_totalBalance; + event SubscriptionCreated(uint64 indexed subId, address owner); + event SubscriptionFunded(uint64 indexed subId, uint256 oldBalance, uint256 newBalance); + event SubscriptionConsumerAdded(uint64 indexed subId, address consumer); + event SubscriptionConsumerRemoved(uint64 indexed subId, address consumer); + event SubscriptionCanceled(uint64 indexed subId, address to, uint256 amount); + event SubscriptionOwnerTransferRequested(uint64 indexed subId, address from, address to); + event SubscriptionOwnerTransferred(uint64 indexed subId, address from, address to); + + // Set this maximum to 200 to give us a 56 block window to fulfill + // the request before requiring the block hash feeder. + uint16 public constant MAX_REQUEST_CONFIRMATIONS = 200; + uint32 public constant MAX_NUM_WORDS = 500; + // 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; + error InvalidRequestConfirmations(uint16 have, uint16 min, uint16 max); + error GasLimitTooBig(uint32 have, uint32 want); + error NumWordsTooBig(uint32 have, uint32 want); + error ProvingKeyAlreadyRegistered(bytes32 keyHash); + error NoSuchProvingKey(bytes32 keyHash); + error InvalidLinkWeiPrice(int256 linkWei); + error InsufficientGasForConsumer(uint256 have, uint256 want); + error NoCorrespondingRequest(); + error IncorrectCommitment(); + error BlockhashNotInStore(uint256 blockNum); + error PaymentTooLarge(); + error Reentrant(); + + struct RequestCommitment { + uint64 blockNum; + uint64 subId; + uint32 callbackGasLimit; + uint32 numWords; + address sender; + } + mapping(bytes32 => address) /* keyHash */ /* oracle */ private s_provingKeys; + bytes32[] private s_provingKeyHashes; + mapping(address => uint96) /* oracle */ /* LINK balance */ private s_withdrawableTokens; + mapping(uint256 => bytes32) /* requestID */ /* commitment */ private s_requestCommitments; + event ProvingKeyRegistered(bytes32 keyHash, address indexed oracle); + event ProvingKeyDeregistered(bytes32 keyHash, address indexed oracle); + event RandomWordsRequested( + bytes32 indexed keyHash, + uint256 requestId, + uint256 preSeed, + uint64 indexed subId, + uint16 minimumRequestConfirmations, + uint32 callbackGasLimit, + uint32 numWords, + address indexed sender + ); + event RandomWordsFulfilled(uint256 indexed requestId, uint256 outputSeed, uint96 payment, bool success); + + struct Config { + uint16 minimumRequestConfirmations; + uint32 maxGasLimit; + // Reentrancy protection. + bool reentrancyLock; + // stalenessSeconds is how long before we consider the feed price to be stale + // and fallback to fallbackWeiPerUnitLink. + uint32 stalenessSeconds; + // Gas to cover oracle payment after we calculate the payment. + // We make it configurable in case those operations are repriced. + uint32 gasAfterPaymentCalculation; + } + int256 private s_fallbackWeiPerUnitLink; + Config private s_config; + FeeConfig private s_feeConfig; + struct FeeConfig { + // Flat fee charged per fulfillment in millionths of link + // So fee range is [0, 2^32/10^6]. + uint32 fulfillmentFlatFeeLinkPPMTier1; + uint32 fulfillmentFlatFeeLinkPPMTier2; + uint32 fulfillmentFlatFeeLinkPPMTier3; + uint32 fulfillmentFlatFeeLinkPPMTier4; + uint32 fulfillmentFlatFeeLinkPPMTier5; + uint24 reqsForTier2; + uint24 reqsForTier3; + uint24 reqsForTier4; + uint24 reqsForTier5; + } + event ConfigSet( + uint16 minimumRequestConfirmations, + uint32 maxGasLimit, + uint32 stalenessSeconds, + uint32 gasAfterPaymentCalculation, + int256 fallbackWeiPerUnitLink, + FeeConfig feeConfig + ); + + constructor(address link, address blockhashStore, address linkEthFeed) ConfirmedOwner(msg.sender) { + LINK = LinkTokenInterface(link); + LINK_ETH_FEED = AggregatorV3Interface(linkEthFeed); + BLOCKHASH_STORE = BlockhashStoreInterface(blockhashStore); + } + + /** + * @notice Registers a proving key to an oracle. + * @param oracle address of the oracle + * @param publicProvingKey key that oracle can use to submit vrf fulfillments + */ + function registerProvingKey(address oracle, uint256[2] calldata publicProvingKey) external onlyOwner { + bytes32 kh = hashOfKey(publicProvingKey); + if (s_provingKeys[kh] != address(0)) { + revert ProvingKeyAlreadyRegistered(kh); + } + s_provingKeys[kh] = oracle; + s_provingKeyHashes.push(kh); + emit ProvingKeyRegistered(kh, oracle); + } + + /** + * @notice Deregisters a proving key to an oracle. + * @param publicProvingKey key that oracle can use to submit vrf fulfillments + */ + function deregisterProvingKey(uint256[2] calldata publicProvingKey) external onlyOwner { + bytes32 kh = hashOfKey(publicProvingKey); + address oracle = s_provingKeys[kh]; + if (oracle == address(0)) { + revert NoSuchProvingKey(kh); + } + delete s_provingKeys[kh]; + for (uint256 i = 0; i < s_provingKeyHashes.length; i++) { + if (s_provingKeyHashes[i] == kh) { + bytes32 last = s_provingKeyHashes[s_provingKeyHashes.length - 1]; + // Copy last element and overwrite kh to be deleted with it + s_provingKeyHashes[i] = last; + s_provingKeyHashes.pop(); + } + } + emit ProvingKeyDeregistered(kh, oracle); + } + + /** + * @notice Returns the proving key hash key associated with this public key + * @param publicKey the key to return the hash of + */ + function hashOfKey(uint256[2] memory publicKey) public pure returns (bytes32) { + return keccak256(abi.encode(publicKey)); + } + + /** + * @notice Sets the configuration of the vrfv2 coordinator + * @param minimumRequestConfirmations global min for request confirmations + * @param maxGasLimit global max for request gas limit + * @param stalenessSeconds if the eth/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 eth/link price in the case of a stale feed + * @param feeConfig fee tier configuration + */ + function setConfig( + uint16 minimumRequestConfirmations, + uint32 maxGasLimit, + uint32 stalenessSeconds, + uint32 gasAfterPaymentCalculation, + int256 fallbackWeiPerUnitLink, + FeeConfig memory feeConfig + ) external onlyOwner { + if (minimumRequestConfirmations > MAX_REQUEST_CONFIRMATIONS) { + revert InvalidRequestConfirmations( + minimumRequestConfirmations, + minimumRequestConfirmations, + MAX_REQUEST_CONFIRMATIONS + ); + } + if (fallbackWeiPerUnitLink <= 0) { + revert InvalidLinkWeiPrice(fallbackWeiPerUnitLink); + } + s_config = Config({ + minimumRequestConfirmations: minimumRequestConfirmations, + maxGasLimit: maxGasLimit, + stalenessSeconds: stalenessSeconds, + gasAfterPaymentCalculation: gasAfterPaymentCalculation, + reentrancyLock: false + }); + s_feeConfig = feeConfig; + s_fallbackWeiPerUnitLink = fallbackWeiPerUnitLink; + emit ConfigSet( + minimumRequestConfirmations, + maxGasLimit, + stalenessSeconds, + gasAfterPaymentCalculation, + fallbackWeiPerUnitLink, + s_feeConfig + ); + } + + function getConfig() + external + view + returns ( + uint16 minimumRequestConfirmations, + uint32 maxGasLimit, + uint32 stalenessSeconds, + uint32 gasAfterPaymentCalculation + ) + { + return ( + s_config.minimumRequestConfirmations, + s_config.maxGasLimit, + s_config.stalenessSeconds, + s_config.gasAfterPaymentCalculation + ); + } + + function getFeeConfig() + external + view + returns ( + uint32 fulfillmentFlatFeeLinkPPMTier1, + uint32 fulfillmentFlatFeeLinkPPMTier2, + uint32 fulfillmentFlatFeeLinkPPMTier3, + uint32 fulfillmentFlatFeeLinkPPMTier4, + uint32 fulfillmentFlatFeeLinkPPMTier5, + uint24 reqsForTier2, + uint24 reqsForTier3, + uint24 reqsForTier4, + uint24 reqsForTier5 + ) + { + return ( + s_feeConfig.fulfillmentFlatFeeLinkPPMTier1, + s_feeConfig.fulfillmentFlatFeeLinkPPMTier2, + s_feeConfig.fulfillmentFlatFeeLinkPPMTier3, + s_feeConfig.fulfillmentFlatFeeLinkPPMTier4, + s_feeConfig.fulfillmentFlatFeeLinkPPMTier5, + s_feeConfig.reqsForTier2, + s_feeConfig.reqsForTier3, + s_feeConfig.reqsForTier4, + s_feeConfig.reqsForTier5 + ); + } + + function getTotalBalance() external view returns (uint256) { + return s_totalBalance; + } + + function getFallbackWeiPerUnitLink() external view returns (int256) { + return s_fallbackWeiPerUnitLink; + } + + /** + * @notice Owner cancel subscription, sends remaining link directly to the subscription owner. + * @param subId subscription id + * @dev notably can be called even if there are pending requests, outstanding ones may fail onchain + */ + function ownerCancelSubscription(uint64 subId) external onlyOwner { + if (s_subscriptionConfigs[subId].owner == address(0)) { + revert InvalidSubscription(); + } + cancelSubscriptionHelper(subId, s_subscriptionConfigs[subId].owner); + } + + /** + * @notice Recover link sent with transfer instead of transferAndCall. + * @param to address to send link to + */ + function recoverFunds(address to) external onlyOwner { + uint256 externalBalance = LINK.balanceOf(address(this)); + uint256 internalBalance = uint256(s_totalBalance); + if (internalBalance > externalBalance) { + revert BalanceInvariantViolated(internalBalance, externalBalance); + } + if (internalBalance < externalBalance) { + uint256 amount = externalBalance - internalBalance; + LINK.transfer(to, amount); + emit FundsRecovered(to, amount); + } + // If the balances are equal, nothing to be done. + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function getRequestConfig() external view override returns (uint16, uint32, bytes32[] memory) { + return (s_config.minimumRequestConfirmations, s_config.maxGasLimit, s_provingKeyHashes); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function requestRandomWords( + bytes32 keyHash, + uint64 subId, + uint16 requestConfirmations, + uint32 callbackGasLimit, + uint32 numWords + ) external override nonReentrant returns (uint256) { + // Input validation using the subscription storage. + 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. + uint64 currentNonce = s_consumers[msg.sender][subId]; + if (currentNonce == 0) { + revert InvalidConsumer(subId, msg.sender); + } + // Input validation using the config storage word. + if ( + requestConfirmations < s_config.minimumRequestConfirmations || requestConfirmations > MAX_REQUEST_CONFIRMATIONS + ) { + revert InvalidRequestConfirmations( + requestConfirmations, + s_config.minimumRequestConfirmations, + MAX_REQUEST_CONFIRMATIONS + ); + } + // No lower bound on the requested gas limit. A user could request 0 + // and they would simply be billed for the proof verification and wouldn't be + // able to do anything with the random value. + if (callbackGasLimit > s_config.maxGasLimit) { + revert GasLimitTooBig(callbackGasLimit, s_config.maxGasLimit); + } + if (numWords > MAX_NUM_WORDS) { + revert NumWordsTooBig(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. + uint64 nonce = currentNonce + 1; + (uint256 requestId, uint256 preSeed) = computeRequestId(keyHash, msg.sender, subId, nonce); + + s_requestCommitments[requestId] = keccak256( + abi.encode(requestId, block.number, subId, callbackGasLimit, numWords, msg.sender) + ); + emit RandomWordsRequested( + keyHash, + requestId, + preSeed, + subId, + requestConfirmations, + callbackGasLimit, + numWords, + msg.sender + ); + s_consumers[msg.sender][subId] = nonce; + + return requestId; + } + + /** + * @notice Get request commitment + * @param requestId id of request + * @dev used to determine if a request is fulfilled or not + */ + function getCommitment(uint256 requestId) external view returns (bytes32) { + return s_requestCommitments[requestId]; + } + + function computeRequestId( + bytes32 keyHash, + address sender, + uint64 subId, + uint64 nonce + ) private pure returns (uint256, uint256) { + uint256 preSeed = uint256(keccak256(abi.encode(keyHash, sender, subId, nonce))); + return (uint256(keccak256(abi.encode(keyHash, preSeed))), preSeed); + } + + /** + * @dev calls target address with exactly gasAmount gas and data as calldata + * or reverts if at least gasAmount gas is not available. + */ + function callWithExactGas(uint256 gasAmount, address target, bytes memory data) private returns (bool success) { + // solhint-disable-next-line no-inline-assembly + assembly { + let g := gas() + // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow + // The gas actually passed to the callee is min(gasAmount, 63//64*gas available). + // We want to ensure that we revert if gasAmount > 63//64*gas available + // as we do not want to provide them with less, however that check itself costs + // gas. GAS_FOR_CALL_EXACT_CHECK ensures we have at least enough gas to be able + // to revert if gasAmount > 63//64*gas available. + if lt(g, GAS_FOR_CALL_EXACT_CHECK) { + revert(0, 0) + } + g := sub(g, GAS_FOR_CALL_EXACT_CHECK) + // if g - g//64 <= gasAmount, revert + // (we subtract g//64 because of EIP-150) + if iszero(gt(sub(g, div(g, 64)), gasAmount)) { + revert(0, 0) + } + // solidity calls check that a contract actually exists at the destination, so we do the same + if iszero(extcodesize(target)) { + revert(0, 0) + } + // call and return whether we succeeded. ignore return data + // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) + success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0) + } + return success; + } + + function getRandomnessFromProof( + Proof memory proof, + RequestCommitment memory rc + ) private view returns (bytes32 keyHash, uint256 requestId, uint256 randomness) { + keyHash = hashOfKey(proof.pk); + // Only registered proving keys are permitted. + address oracle = s_provingKeys[keyHash]; + if (oracle == address(0)) { + revert NoSuchProvingKey(keyHash); + } + requestId = uint256(keccak256(abi.encode(keyHash, proof.seed))); + bytes32 commitment = s_requestCommitments[requestId]; + if (commitment == 0) { + revert NoCorrespondingRequest(); + } + if ( + commitment != keccak256(abi.encode(requestId, rc.blockNum, rc.subId, rc.callbackGasLimit, rc.numWords, rc.sender)) + ) { + revert IncorrectCommitment(); + } + + bytes32 blockHash = blockhash(rc.blockNum); + if (blockHash == bytes32(0)) { + blockHash = BLOCKHASH_STORE.getBlockhash(rc.blockNum); + if (blockHash == bytes32(0)) { + revert BlockhashNotInStore(rc.blockNum); + } + } + + // The seed actually used by the VRF machinery, mixing in the blockhash + uint256 actualSeed = uint256(keccak256(abi.encodePacked(proof.seed, blockHash))); + randomness = VRF._randomValueFromVRFProof(proof, actualSeed); // Reverts on failure + } + + /* + * @notice Compute fee based on the request count + * @param reqCount number of requests + * @return feePPM fee in LINK PPM + */ + function getFeeTier(uint64 reqCount) public view returns (uint32) { + FeeConfig memory fc = s_feeConfig; + if (0 <= reqCount && reqCount <= fc.reqsForTier2) { + return fc.fulfillmentFlatFeeLinkPPMTier1; + } + if (fc.reqsForTier2 < reqCount && reqCount <= fc.reqsForTier3) { + return fc.fulfillmentFlatFeeLinkPPMTier2; + } + if (fc.reqsForTier3 < reqCount && reqCount <= fc.reqsForTier4) { + return fc.fulfillmentFlatFeeLinkPPMTier3; + } + if (fc.reqsForTier4 < reqCount && reqCount <= fc.reqsForTier5) { + return fc.fulfillmentFlatFeeLinkPPMTier4; + } + return fc.fulfillmentFlatFeeLinkPPMTier5; + } + + /* + * @notice Fulfill a randomness request + * @param proof contains the proof and randomness + * @param rc request commitment pre-image, committed to at request time + * @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) external nonReentrant returns (uint96) { + uint256 startGas = gasleft(); + (bytes32 keyHash, uint256 requestId, uint256 randomness) = getRandomnessFromProof(proof, rc); + + uint256[] memory randomWords = new uint256[](rc.numWords); + for (uint256 i = 0; i < rc.numWords; i++) { + randomWords[i] = uint256(keccak256(abi.encode(randomness, i))); + } + + delete s_requestCommitments[requestId]; + VRFConsumerBaseV2 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; + bool success = callWithExactGas(rc.callbackGasLimit, rc.sender, resp); + s_config.reentrancyLock = false; + + // Increment the req count for fee tier selection. + uint64 reqCount = s_subscriptions[rc.subId].reqCount; + s_subscriptions[rc.subId].reqCount += 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. + // We also add the flat link fee to the payment amount. + // Its specified in millionths of link, if s_config.fulfillmentFlatFeeLinkPPM = 1 + // 1 link / 1e6 = 1e18 juels / 1e6 = 1e12 juels. + uint96 payment = calculatePaymentAmount( + startGas, + s_config.gasAfterPaymentCalculation, + getFeeTier(reqCount), + tx.gasprice + ); + if (s_subscriptions[rc.subId].balance < payment) { + revert InsufficientBalance(); + } + s_subscriptions[rc.subId].balance -= payment; + s_withdrawableTokens[s_provingKeys[keyHash]] += payment; + // Include payment in the event for tracking costs. + emit RandomWordsFulfilled(requestId, randomness, payment, success); + return payment; + } + + // Get the amount of gas used for fulfillment + function calculatePaymentAmount( + uint256 startGas, + uint256 gasAfterPaymentCalculation, + uint32 fulfillmentFlatFeeLinkPPM, + uint256 weiPerUnitGas + ) internal view returns (uint96) { + int256 weiPerUnitLink; + weiPerUnitLink = getFeedData(); + if (weiPerUnitLink <= 0) { + revert InvalidLinkWeiPrice(weiPerUnitLink); + } + // (1e18 juels/link) (wei/gas * gas) / (wei/link) = juels + uint256 paymentNoFee = (1e18 * weiPerUnitGas * (gasAfterPaymentCalculation + startGas - gasleft())) / + uint256(weiPerUnitLink); + uint256 fee = 1e12 * uint256(fulfillmentFlatFeeLinkPPM); + if (paymentNoFee > (1e27 - fee)) { + revert PaymentTooLarge(); // Payment + fee cannot be more than all of the link in existence. + } + return uint96(paymentNoFee + fee); + } + + function getFeedData() private view returns (int256) { + uint32 stalenessSeconds = s_config.stalenessSeconds; + bool staleFallback = stalenessSeconds > 0; + uint256 timestamp; + int256 weiPerUnitLink; + (, weiPerUnitLink, , timestamp, ) = LINK_ETH_FEED.latestRoundData(); + // solhint-disable-next-line not-rely-on-time + if (staleFallback && stalenessSeconds < block.timestamp - timestamp) { + weiPerUnitLink = s_fallbackWeiPerUnitLink; + } + return weiPerUnitLink; + } + + /* + * @notice Oracle withdraw LINK earned through fulfilling requests + * @param recipient where to send the funds + * @param amount amount to withdraw + */ + function oracleWithdraw(address recipient, uint96 amount) external nonReentrant { + if (s_withdrawableTokens[msg.sender] < amount) { + revert InsufficientBalance(); + } + s_withdrawableTokens[msg.sender] -= amount; + s_totalBalance -= amount; + if (!LINK.transfer(recipient, amount)) { + revert InsufficientBalance(); + } + } + + function onTokenTransfer(address /* sender */, uint256 amount, bytes calldata data) external override nonReentrant { + if (msg.sender != address(LINK)) { + revert OnlyCallableFromLink(); + } + if (data.length != 32) { + revert InvalidCalldata(); + } + uint64 subId = abi.decode(data, (uint64)); + if (s_subscriptionConfigs[subId].owner == address(0)) { + revert InvalidSubscription(); + } + // We do not check that the msg.sender is the subscription owner, + // anyone can fund a subscription. + uint256 oldBalance = s_subscriptions[subId].balance; + s_subscriptions[subId].balance += uint96(amount); + s_totalBalance += uint96(amount); + emit SubscriptionFunded(subId, oldBalance, oldBalance + amount); + } + + function getCurrentSubId() external view returns (uint64) { + return s_currentSubId; + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function getSubscription( + uint64 subId + ) external view override returns (uint96 balance, uint64 reqCount, address owner, address[] memory consumers) { + if (s_subscriptionConfigs[subId].owner == address(0)) { + revert InvalidSubscription(); + } + return ( + s_subscriptions[subId].balance, + s_subscriptions[subId].reqCount, + s_subscriptionConfigs[subId].owner, + s_subscriptionConfigs[subId].consumers + ); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function createSubscription() external override nonReentrant returns (uint64) { + s_currentSubId++; + uint64 currentSubId = s_currentSubId; + address[] memory consumers = new address[](0); + s_subscriptions[currentSubId] = Subscription({balance: 0, reqCount: 0}); + s_subscriptionConfigs[currentSubId] = SubscriptionConfig({ + owner: msg.sender, + requestedOwner: address(0), + consumers: consumers + }); + + emit SubscriptionCreated(currentSubId, msg.sender); + return currentSubId; + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function requestSubscriptionOwnerTransfer( + uint64 subId, + address newOwner + ) external override onlySubOwner(subId) nonReentrant { + // Proposing to address(0) would never be claimable so don't need to check. + if (s_subscriptionConfigs[subId].requestedOwner != newOwner) { + s_subscriptionConfigs[subId].requestedOwner = newOwner; + emit SubscriptionOwnerTransferRequested(subId, msg.sender, newOwner); + } + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function acceptSubscriptionOwnerTransfer(uint64 subId) external override nonReentrant { + if (s_subscriptionConfigs[subId].owner == address(0)) { + revert InvalidSubscription(); + } + if (s_subscriptionConfigs[subId].requestedOwner != msg.sender) { + revert MustBeRequestedOwner(s_subscriptionConfigs[subId].requestedOwner); + } + address oldOwner = s_subscriptionConfigs[subId].owner; + s_subscriptionConfigs[subId].owner = msg.sender; + s_subscriptionConfigs[subId].requestedOwner = address(0); + emit SubscriptionOwnerTransferred(subId, oldOwner, msg.sender); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function removeConsumer(uint64 subId, address consumer) external override onlySubOwner(subId) nonReentrant { + if (s_consumers[consumer][subId] == 0) { + revert InvalidConsumer(subId, consumer); + } + // 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++) { + if (consumers[i] == consumer) { + address last = consumers[lastConsumerIndex]; + // Storage write to preserve last element + s_subscriptionConfigs[subId].consumers[i] = last; + // Storage remove last element + s_subscriptionConfigs[subId].consumers.pop(); + break; + } + } + delete s_consumers[consumer][subId]; + emit SubscriptionConsumerRemoved(subId, consumer); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function addConsumer(uint64 subId, address consumer) external override onlySubOwner(subId) nonReentrant { + // Already maxed, cannot add any more consumers. + if (s_subscriptionConfigs[subId].consumers.length == MAX_CONSUMERS) { + revert TooManyConsumers(); + } + if (s_consumers[consumer][subId] != 0) { + // Idempotence - do nothing if already added. + // Ensures uniqueness in s_subscriptions[subId].consumers. + return; + } + // Initialize the nonce to 1, indicating the consumer is allocated. + s_consumers[consumer][subId] = 1; + s_subscriptionConfigs[subId].consumers.push(consumer); + + emit SubscriptionConsumerAdded(subId, consumer); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + */ + function cancelSubscription(uint64 subId, address to) external override onlySubOwner(subId) nonReentrant { + if (pendingRequestExists(subId)) { + revert PendingRequestExists(); + } + cancelSubscriptionHelper(subId, to); + } + + function cancelSubscriptionHelper(uint64 subId, address to) private nonReentrant { + SubscriptionConfig memory subConfig = s_subscriptionConfigs[subId]; + Subscription memory sub = s_subscriptions[subId]; + uint96 balance = sub.balance; + // Note bounded by MAX_CONSUMERS; + // If no consumers, does nothing. + for (uint256 i = 0; i < subConfig.consumers.length; i++) { + delete s_consumers[subConfig.consumers[i]][subId]; + } + delete s_subscriptionConfigs[subId]; + delete s_subscriptions[subId]; + s_totalBalance -= balance; + if (!LINK.transfer(to, uint256(balance))) { + revert InsufficientBalance(); + } + emit SubscriptionCanceled(subId, to, balance); + } + + /** + * @inheritdoc VRFCoordinatorV2Interface + * @dev Looping is bounded to MAX_CONSUMERS*(number of keyhashes). + * @dev Used to disable subscription canceling while outstanding request are present. + */ + function pendingRequestExists(uint64 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] + ); + if (s_requestCommitments[reqId] != 0) { + return true; + } + } + } + return false; + } + + modifier onlySubOwner(uint64 subId) { + address owner = s_subscriptionConfigs[subId].owner; + if (owner == address(0)) { + revert InvalidSubscription(); + } + if (msg.sender != owner) { + revert MustBeSubOwner(owner); + } + _; + } + + modifier nonReentrant() { + if (s_config.reentrancyLock) { + revert Reentrant(); + } + _; + } + + /** + * @notice The type and version of this contract + * @return Type and version string + */ + function typeAndVersion() external pure virtual override returns (string memory) { + return "VRFCoordinatorV2 1.0.0"; + } +} diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFMockETHLINKAggregator.sol b/contracts/src/v0.8/vrf/testhelpers/VRFMockETHLINKAggregator.sol new file mode 100644 index 00000000000..86c77202434 --- /dev/null +++ b/contracts/src/v0.8/vrf/testhelpers/VRFMockETHLINKAggregator.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../../shared/interfaces/AggregatorV3Interface.sol"; + +contract VRFMockETHLINKAggregator is AggregatorV3Interface { + int256 public answer; + uint256 private blockTimestampDeduction = 0; + + constructor(int256 _answer) public { + answer = _answer; + } + + function decimals() external view override returns (uint8) { + return 18; + } + + function description() external view override returns (string memory) { + return "VRFMockETHLINKAggregator"; + } + + function version() external view override returns (uint256) { + return 1; + } + + function getRoundData( + uint80 _roundId + ) + external + view + override + returns (uint80 roundId, int256 ans, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, answer, getDeductedBlockTimestamp(), getDeductedBlockTimestamp(), 1); + } + + function latestRoundData() + external + view + override + returns (uint80 roundId, int256 ans, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) + { + return (1, answer, getDeductedBlockTimestamp(), getDeductedBlockTimestamp(), 1); + } + + function getDeductedBlockTimestamp() internal view returns (uint256) { + return block.timestamp - blockTimestampDeduction; + } + + function setBlockTimestampDeduction(uint256 _blockTimestampDeduction) external { + blockTimestampDeduction = _blockTimestampDeduction; + } +} diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol index d364e5002b4..fa44b3eee30 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2LoadTestWithMetrics.sol @@ -3,16 +3,16 @@ pragma solidity ^0.8.0; import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface.sol"; import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; -import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; /** * @title The VRFLoadTestExternalSubOwner contract. * @notice Allows making many VRF V2 randomness requests in a single transaction for load testing. */ -contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { +contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2 { VRFCoordinatorV2Interface public immutable COORDINATOR; - + LinkTokenInterface public LINKTOKEN; uint256 public s_responseCount; uint256 public s_requestCount; uint256 public s_averageFulfillmentInMillions = 0; // in millions for better precision @@ -21,6 +21,8 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { uint256 public s_lastRequestId; mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made + event SubscriptionCreatedFundedAndConsumerAdded(uint64 subId, address consumer, uint256 amount); + struct RequestStatus { bool fulfilled; uint256[] randomWords; @@ -32,7 +34,7 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { mapping(uint256 => RequestStatus) /* requestId */ /* requestStatus */ public s_requests; - constructor(address _vrfCoordinator) VRFConsumerBaseV2(_vrfCoordinator) ConfirmedOwner(msg.sender) { + constructor(address _vrfCoordinator) VRFConsumerBaseV2(_vrfCoordinator) { COORDINATOR = VRFCoordinatorV2Interface(_vrfCoordinator); } @@ -64,28 +66,30 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { uint32 _callbackGasLimit, uint32 _numWords, uint16 _requestCount - ) external onlyOwner { - for (uint16 i = 0; i < _requestCount; i++) { - uint256 requestId = COORDINATOR.requestRandomWords( - _keyHash, - _subId, - _requestConfirmations, - _callbackGasLimit, - _numWords - ); - s_lastRequestId = requestId; - uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); - s_requests[requestId] = RequestStatus({ - randomWords: new uint256[](0), - fulfilled: false, - requestTimestamp: block.timestamp, - fulfilmentTimestamp: 0, - requestBlockNumber: requestBlockNumber, - fulfilmentBlockNumber: 0 - }); - s_requestCount++; - requestHeights[requestId] = requestBlockNumber; - } + ) external { + _makeLoadTestRequests(_subId, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount); + } + + function requestRandomWordsWithForceFulfill( + uint16 _requestConfirmations, + bytes32 _keyHash, + uint32 _callbackGasLimit, + uint32 _numWords, + uint16 _requestCount, + uint256 _subTopUpAmount, + address _link + ) external { + // create a subscription, address(this) will be the owner + uint64 _subId = COORDINATOR.createSubscription(); + // add address(this) as a consumer on the subscription + COORDINATOR.addConsumer(_subId, address(this)); + topUpSubscription(_subId, _subTopUpAmount, _link); + emit SubscriptionCreatedFundedAndConsumerAdded(_subId, address(this), _subTopUpAmount); + + _makeLoadTestRequests(_subId, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount); + + COORDINATOR.removeConsumer(_subId, address(this)); + COORDINATOR.cancelSubscription(_subId, msg.sender); } function reset() external { @@ -120,4 +124,40 @@ contract VRFV2LoadTestWithMetrics is VRFConsumerBaseV2, ConfirmedOwner { request.fulfilmentBlockNumber ); } + + function _makeLoadTestRequests( + uint64 _subId, + uint16 _requestConfirmations, + bytes32 _keyHash, + uint32 _callbackGasLimit, + uint32 _numWords, + uint16 _requestCount + ) internal { + for (uint16 i = 0; i < _requestCount; i++) { + uint256 requestId = COORDINATOR.requestRandomWords( + _keyHash, + _subId, + _requestConfirmations, + _callbackGasLimit, + _numWords + ); + s_lastRequestId = requestId; + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); + s_requests[requestId] = RequestStatus({ + randomWords: new uint256[](0), + fulfilled: false, + requestTimestamp: block.timestamp, + fulfilmentTimestamp: 0, + requestBlockNumber: requestBlockNumber, + fulfilmentBlockNumber: 0 + }); + s_requestCount++; + requestHeights[requestId] = requestBlockNumber; + } + } + + function topUpSubscription(uint64 _subId, uint256 _amount, address _link) public { + LINKTOKEN = LinkTokenInterface(_link); + LINKTOKEN.transferAndCall(address(COORDINATOR), _amount, abi.encode(_subId)); + } } diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol index dd1af80a92d..5961f4e5d49 100644 --- a/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2OwnerTestConsumer.sol @@ -5,9 +5,11 @@ import {VRFCoordinatorV2Interface} from "../interfaces/VRFCoordinatorV2Interface import {VRFConsumerBaseV2} from "../VRFConsumerBaseV2.sol"; import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {LinkTokenInterface} from "../../shared/interfaces/LinkTokenInterface.sol"; contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { VRFCoordinatorV2Interface public COORDINATOR; + LinkTokenInterface public LINKTOKEN; uint64 public subId; uint256 public s_responseCount; uint256 public s_requestCount; @@ -17,6 +19,8 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { uint256 public s_lastRequestId; mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made + event SubscriptionCreatedFundedAndConsumerAdded(uint64 subId, address consumer, uint256 amount); + struct RequestStatus { bool fulfilled; uint256[] randomWords; @@ -28,12 +32,9 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { mapping(uint256 => RequestStatus) /* requestId */ /* requestStatus */ public s_requests; - constructor(address _vrfCoordinator) VRFConsumerBaseV2(_vrfCoordinator) ConfirmedOwner(msg.sender) { + constructor(address _vrfCoordinator, address _link) VRFConsumerBaseV2(_vrfCoordinator) ConfirmedOwner(msg.sender) { COORDINATOR = VRFCoordinatorV2Interface(_vrfCoordinator); - // create a subscription, address(this) will be the owner - subId = COORDINATOR.createSubscription(); - // add address(this) as a consumer on the subscription - COORDINATOR.addConsumer(subId, address(this)); + LINKTOKEN = LinkTokenInterface(_link); } function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { @@ -62,8 +63,16 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { bytes32 _keyHash, uint32 _callbackGasLimit, uint32 _numWords, - uint16 _requestCount + uint16 _requestCount, + uint256 _subTopUpAmount ) external onlyOwner { + // create a subscription, address(this) will be the owner + subId = COORDINATOR.createSubscription(); + // add address(this) as a consumer on the subscription + COORDINATOR.addConsumer(subId, address(this)); + topUpSubscription(_subTopUpAmount); + emit SubscriptionCreatedFundedAndConsumerAdded(subId, address(this), _subTopUpAmount); + for (uint16 i = 0; i < _requestCount; i++) { uint256 requestId = COORDINATOR.requestRandomWords( _keyHash, @@ -122,4 +131,8 @@ contract VRFV2OwnerTestConsumer is VRFConsumerBaseV2, ConfirmedOwner { request.fulfilmentBlockNumber ); } + + function topUpSubscription(uint256 amount) public onlyOwner { + LINKTOKEN.transferAndCall(address(COORDINATOR), amount, abi.encode(subId)); + } } diff --git a/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol new file mode 100644 index 00000000000..5a82d4b0b9d --- /dev/null +++ b/contracts/src/v0.8/vrf/testhelpers/VRFV2WrapperLoadTestConsumer.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.6; + +import {VRFV2WrapperConsumerBase} from "../VRFV2WrapperConsumerBase.sol"; +import {ConfirmedOwner} from "../../shared/access/ConfirmedOwner.sol"; +import {ChainSpecificUtil} from "../../ChainSpecificUtil.sol"; +import {VRFV2WrapperInterface} from "../interfaces/VRFV2WrapperInterface.sol"; + +contract VRFV2WrapperLoadTestConsumer is VRFV2WrapperConsumerBase, ConfirmedOwner { + VRFV2WrapperInterface public immutable i_vrfV2Wrapper; + uint256 public s_responseCount; + uint256 public s_requestCount; + uint256 public s_averageFulfillmentInMillions = 0; // in millions for better precision + uint256 public s_slowestFulfillment = 0; + uint256 public s_fastestFulfillment = 999; + uint256 public s_lastRequestId; + // solhint-disable-next-line chainlink-solidity/prefix-storage-variables-with-s-underscore + mapping(uint256 => uint256) internal requestHeights; // requestIds to block number when rand request was made + mapping(uint256 => RequestStatus) /* requestId */ /* requestStatus */ public s_requests; + + event WrappedRequestFulfilled(uint256 requestId, uint256[] randomWords, uint256 payment); + event WrapperRequestMade(uint256 indexed requestId, uint256 paid); + + struct RequestStatus { + uint256 paid; + bool fulfilled; + uint256[] randomWords; + uint256 requestTimestamp; + uint256 fulfilmentTimestamp; + uint256 requestBlockNumber; + uint256 fulfilmentBlockNumber; + } + + constructor( + address _link, + address _vrfV2Wrapper + ) ConfirmedOwner(msg.sender) VRFV2WrapperConsumerBase(_link, _vrfV2Wrapper) { + i_vrfV2Wrapper = VRFV2WrapperInterface(_vrfV2Wrapper); + } + + function makeRequests( + uint32 _callbackGasLimit, + uint16 _requestConfirmations, + uint32 _numWords, + uint16 _requestCount + ) external onlyOwner { + for (uint16 i = 0; i < _requestCount; i++) { + uint256 requestId = requestRandomness(_callbackGasLimit, _requestConfirmations, _numWords); + s_lastRequestId = requestId; + uint256 requestBlockNumber = ChainSpecificUtil._getBlockNumber(); + uint256 paid = VRF_V2_WRAPPER.calculateRequestPrice(_callbackGasLimit); + s_requests[requestId] = RequestStatus({ + paid: paid, + fulfilled: false, + randomWords: new uint256[](0), + requestTimestamp: block.timestamp, + fulfilmentTimestamp: 0, + requestBlockNumber: requestBlockNumber, + fulfilmentBlockNumber: 0 + }); + s_requestCount++; + requestHeights[requestId] = requestBlockNumber; + emit WrapperRequestMade(requestId, paid); + } + } + + function fulfillRandomWords(uint256 _requestId, uint256[] memory _randomWords) internal override { + // solhint-disable-next-line custom-errors + require(s_requests[_requestId].paid > 0, "request not found"); + uint256 fulfilmentBlockNumber = ChainSpecificUtil._getBlockNumber(); + uint256 requestDelay = fulfilmentBlockNumber - requestHeights[_requestId]; + uint256 requestDelayInMillions = requestDelay * 1_000_000; + + if (requestDelay > s_slowestFulfillment) { + s_slowestFulfillment = requestDelay; + } + if (requestDelay < s_fastestFulfillment) { + s_fastestFulfillment = requestDelay; + } + s_averageFulfillmentInMillions = s_responseCount > 0 + ? (s_averageFulfillmentInMillions * s_responseCount + requestDelayInMillions) / (s_responseCount + 1) + : requestDelayInMillions; + + s_responseCount++; + s_requests[_requestId].fulfilled = true; + s_requests[_requestId].randomWords = _randomWords; + s_requests[_requestId].fulfilmentTimestamp = block.timestamp; + s_requests[_requestId].fulfilmentBlockNumber = fulfilmentBlockNumber; + + emit WrappedRequestFulfilled(_requestId, _randomWords, s_requests[_requestId].paid); + } + + function getRequestStatus( + uint256 _requestId + ) + external + view + returns ( + uint256 paid, + bool fulfilled, + uint256[] memory randomWords, + uint256 requestTimestamp, + uint256 fulfilmentTimestamp, + uint256 requestBlockNumber, + uint256 fulfilmentBlockNumber + ) + { + // solhint-disable-next-line custom-errors + require(s_requests[_requestId].paid > 0, "request not found"); + RequestStatus memory request = s_requests[_requestId]; + return ( + request.paid, + request.fulfilled, + request.randomWords, + request.requestTimestamp, + request.fulfilmentTimestamp, + request.requestBlockNumber, + request.fulfilmentBlockNumber + ); + } + + /// @notice withdrawLink withdraws the amount specified in amount to the owner + /// @param amount the amount to withdraw, in juels + function withdrawLink(uint256 amount) external onlyOwner { + LINK.transfer(owner(), amount); + } + + function reset() external { + s_averageFulfillmentInMillions = 0; + s_slowestFulfillment = 0; + s_fastestFulfillment = 999; + s_requestCount = 0; + s_responseCount = 0; + } + + receive() external payable {} +} diff --git a/contracts/test/v0.8/automation/AutomationRegistrar2_2.test.ts b/contracts/test/v0.8/automation/AutomationRegistrar2_2.test.ts new file mode 100644 index 00000000000..b7585462067 --- /dev/null +++ b/contracts/test/v0.8/automation/AutomationRegistrar2_2.test.ts @@ -0,0 +1,1013 @@ +import { ethers } from 'hardhat' +import { ContractFactory, Contract } from 'ethers' +import { assert, expect } from 'chai' +import { evmRevert } from '../../test-helpers/matchers' +import { getUsers, Personas } from '../../test-helpers/setup' +import { BigNumber, Signer } from 'ethers' +import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' +import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' +import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' +import { UpkeepMock } from '../../../typechain/UpkeepMock' +import { toWei } from '../../test-helpers/helpers' +import { IKeeperRegistryMaster as IKeeperRegistry } from '../../../typechain/IKeeperRegistryMaster' +import { AutomationRegistrar2_2 as Registrar } from '../../../typechain/AutomationRegistrar2_2' +import { deployRegistry21 } from './helpers' + +// copied from KeeperRegistryBase2_2.sol +enum Trigger { + CONDITION, + LOG, +} + +let linkTokenFactory: ContractFactory +let mockV3AggregatorFactory: MockV3AggregatorFactory +let upkeepMockFactory: UpkeepMockFactory + +let personas: Personas + +before(async () => { + personas = (await getUsers()).personas + + linkTokenFactory = await ethers.getContractFactory( + 'src/v0.4/LinkToken.sol:LinkToken', + ) + mockV3AggregatorFactory = (await ethers.getContractFactory( + 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', + )) as unknown as MockV3AggregatorFactory + upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') +}) + +const errorMsgs = { + onlyOwner: 'revert Only callable by owner', + onlyAdmin: 'OnlyAdminOrOwner()', + hashPayload: 'HashMismatch()', + requestNotFound: 'RequestNotFound()', +} + +describe('AutomationRegistrar2_2', () => { + const upkeepName = 'SampleUpkeep' + + const linkEth = BigNumber.from(300000000) + const gasWei = BigNumber.from(100) + const performGas = BigNumber.from(100000) + const paymentPremiumPPB = BigNumber.from(250000000) + const flatFeeMicroLink = BigNumber.from(0) + const maxAllowedAutoApprove = 5 + const trigger = '0xdeadbeef' + const offchainConfig = '0x01234567' + + const emptyBytes = '0x00' + const stalenessSeconds = BigNumber.from(43820) + const gasCeilingMultiplier = BigNumber.from(1) + const checkGasLimit = BigNumber.from(20000000) + const fallbackGasPrice = BigNumber.from(200) + const fallbackLinkPrice = BigNumber.from(200000000) + const maxCheckDataSize = BigNumber.from(10000) + const maxPerformDataSize = BigNumber.from(10000) + const maxRevertDataSize = BigNumber.from(1000) + const maxPerformGas = BigNumber.from(5000000) + const minUpkeepSpend = BigNumber.from('1000000000000000000') + const amount = BigNumber.from('5000000000000000000') + const amount1 = BigNumber.from('6000000000000000000') + const transcoder = ethers.constants.AddressZero + const upkeepManager = ethers.Wallet.createRandom().address + + // Enum values are not auto exported in ABI so have to manually declare + const autoApproveType_DISABLED = 0 + const autoApproveType_ENABLED_SENDER_ALLOWLIST = 1 + const autoApproveType_ENABLED_ALL = 2 + + let owner: Signer + let admin: Signer + let someAddress: Signer + let registrarOwner: Signer + let stranger: Signer + let requestSender: Signer + + let linkToken: Contract + let linkEthFeed: MockV3Aggregator + let gasPriceFeed: MockV3Aggregator + let mock: UpkeepMock + let registry: IKeeperRegistry + let registrar: Registrar + + beforeEach(async () => { + owner = personas.Default + admin = personas.Neil + someAddress = personas.Ned + registrarOwner = personas.Nelly + stranger = personas.Nancy + requestSender = personas.Norbert + + linkToken = await linkTokenFactory.connect(owner).deploy() + gasPriceFeed = await mockV3AggregatorFactory + .connect(owner) + .deploy(0, gasWei) + linkEthFeed = await mockV3AggregatorFactory + .connect(owner) + .deploy(9, linkEth) + + registry = await deployRegistry21( + owner, + 0, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + mock = await upkeepMockFactory.deploy() + + const registrarFactory = await ethers.getContractFactory( + 'AutomationRegistrar2_2', + ) + registrar = await registrarFactory + .connect(registrarOwner) + .deploy(linkToken.address, registry.address, minUpkeepSpend, [ + { + triggerType: Trigger.CONDITION, + autoApproveType: autoApproveType_DISABLED, + autoApproveMaxAllowed: 0, + }, + { + triggerType: Trigger.LOG, + autoApproveType: autoApproveType_DISABLED, + autoApproveMaxAllowed: 0, + }, + ]) + + await linkToken + .connect(owner) + .transfer(await requestSender.getAddress(), toWei('1000')) + + const keepers = [ + await personas.Carol.getAddress(), + await personas.Nancy.getAddress(), + await personas.Ned.getAddress(), + await personas.Neil.getAddress(), + ] + const onchainConfig = { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder, + registrars: [registrar.address], + upkeepPrivilegeManager: upkeepManager, + } + await registry + .connect(owner) + .setConfigTypeSafe(keepers, keepers, 1, onchainConfig, 1, '0x') + }) + + describe('#typeAndVersion', () => { + it('uses the correct type and version', async () => { + const typeAndVersion = await registrar.typeAndVersion() + assert.equal(typeAndVersion, 'AutomationRegistrar 2.1.0') + }) + }) + + describe('#register', () => { + it('reverts if not called by the LINK token', async () => { + await evmRevert( + registrar + .connect(someAddress) + .register( + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ), + 'OnlyLink()', + ) + }) + + it('reverts if the amount passed in data mismatches actual amount sent', async () => { + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_ALL, + maxAllowedAutoApprove, + ) + + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount1, + await requestSender.getAddress(), + ], + ) + + await evmRevert( + linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes), + 'AmountMismatch()', + ) + }) + + it('reverts if the sender passed in data mismatches actual sender', async () => { + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await admin.getAddress(), // Should have been requestSender.getAddress() + ], + ) + await evmRevert( + linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes), + 'SenderMismatch()', + ) + }) + + it('reverts if the admin address is 0x0000...', async () => { + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + '0x0000000000000000000000000000000000000000', + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + + await evmRevert( + linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes), + 'RegistrationRequestFailed()', + ) + }) + + it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { + //set auto approve ON with high threshold limits + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_ALL, + maxAllowedAutoApprove, + ) + + //register with auto approve ON + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + + const [id] = await registry.getActiveUpkeepIDs(0, 1) + + //confirm if a new upkeep has been registered and the details are the same as the one just registered + const newupkeep = await registry.getUpkeep(id) + assert.equal(newupkeep.target, mock.address) + assert.equal(newupkeep.admin, await admin.getAddress()) + assert.equal(newupkeep.checkData, emptyBytes) + assert.equal(newupkeep.balance.toString(), amount.toString()) + assert.equal(newupkeep.performGas, performGas.toNumber()) + assert.equal(newupkeep.offchainConfig, offchainConfig) + + await expect(tx).to.emit(registrar, 'RegistrationRequested') + await expect(tx).to.emit(registrar, 'RegistrationApproved') + }) + + it('Auto Approve OFF - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { + //get upkeep count before attempting registration + const beforeCount = (await registry.getState()).state.numUpkeeps + + //set auto approve OFF, threshold limits dont matter in this case + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_DISABLED, + maxAllowedAutoApprove, + ) + + //register with auto approve OFF + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + const receipt = await tx.wait() + + //get upkeep count after attempting registration + const afterCount = (await registry.getState()).state.numUpkeeps + //confirm that a new upkeep has NOT been registered and upkeep count is still the same + assert.deepEqual(beforeCount, afterCount) + + //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not + await expect(tx).to.emit(registrar, 'RegistrationRequested') + await expect(tx).not.to.emit(registrar, 'RegistrationApproved') + + const hash = receipt.logs[2].topics[1] + const pendingRequest = await registrar.getPendingRequest(hash) + assert.equal(await admin.getAddress(), pendingRequest[0]) + assert.ok(amount.eq(pendingRequest[1])) + }) + + it('Auto Approve ON - Throttle max approvals - does not register an upkeep on KeeperRegistry beyond the max limit, emits only RegistrationRequested event after limit is hit', async () => { + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 0) + + //set auto approve on, with max 1 allowed + await registrar + .connect(registrarOwner) + .setTriggerConfig(Trigger.CONDITION, autoApproveType_ENABLED_ALL, 1) + + //set auto approve on, with max 1 allowed + await registrar + .connect(registrarOwner) + .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 1) + + // register within threshold, new upkeep should be registered + let abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ]) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 + + // try registering another one, new upkeep should not be registered + abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ + upkeepName, + emptyBytes, + mock.address, + performGas.toNumber() + 1, // make unique hash + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ]) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // Still 1 + + // register a second type of upkeep, different limit + abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + Trigger.LOG, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ]) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 2) // 1 -> 2 + + // Now set new max limit to 2. One more upkeep should get auto approved + await registrar + .connect(registrarOwner) + .setTriggerConfig(Trigger.CONDITION, autoApproveType_ENABLED_ALL, 2) + + abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ + upkeepName, + emptyBytes, + mock.address, + performGas.toNumber() + 2, // make unique hash + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ]) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 3) // 2 -> 3 + + // One more upkeep should not get registered + abiEncodedBytes = registrar.interface.encodeFunctionData('register', [ + upkeepName, + emptyBytes, + mock.address, + performGas.toNumber() + 3, // make unique hash + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ]) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 3) // Still 3 + }) + + it('Auto Approve Sender Allowlist - sender in allowlist - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { + const senderAddress = await requestSender.getAddress() + + //set auto approve to ENABLED_SENDER_ALLOWLIST type with high threshold limits + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_SENDER_ALLOWLIST, + maxAllowedAutoApprove, + ) + + // Add sender to allowlist + await registrar + .connect(registrarOwner) + .setAutoApproveAllowedSender(senderAddress, true) + + //register with auto approve ON + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + + const [id] = await registry.getActiveUpkeepIDs(0, 1) + + //confirm if a new upkeep has been registered and the details are the same as the one just registered + const newupkeep = await registry.getUpkeep(id) + assert.equal(newupkeep.target, mock.address) + assert.equal(newupkeep.admin, await admin.getAddress()) + assert.equal(newupkeep.checkData, emptyBytes) + assert.equal(newupkeep.balance.toString(), amount.toString()) + assert.equal(newupkeep.performGas, performGas.toNumber()) + + await expect(tx).to.emit(registrar, 'RegistrationRequested') + await expect(tx).to.emit(registrar, 'RegistrationApproved') + }) + + it('Auto Approve Sender Allowlist - sender NOT in allowlist - does not registers an upkeep on KeeperRegistry, emits only RegistrationRequested event', async () => { + const beforeCount = (await registry.getState()).state.numUpkeeps + const senderAddress = await requestSender.getAddress() + + //set auto approve to ENABLED_SENDER_ALLOWLIST type with high threshold limits + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_SENDER_ALLOWLIST, + maxAllowedAutoApprove, + ) + + // Explicitly remove sender from allowlist + await registrar + .connect(registrarOwner) + .setAutoApproveAllowedSender(senderAddress, false) + + //register. auto approve shouldn't happen + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + const receipt = await tx.wait() + + //get upkeep count after attempting registration + const afterCount = (await registry.getState()).state.numUpkeeps + //confirm that a new upkeep has NOT been registered and upkeep count is still the same + assert.deepEqual(beforeCount, afterCount) + + //confirm that only RegistrationRequested event is emitted and RegistrationApproved event is not + await expect(tx).to.emit(registrar, 'RegistrationRequested') + await expect(tx).not.to.emit(registrar, 'RegistrationApproved') + + const hash = receipt.logs[2].topics[1] + const pendingRequest = await registrar.getPendingRequest(hash) + assert.equal(await admin.getAddress(), pendingRequest[0]) + assert.ok(amount.eq(pendingRequest[1])) + }) + }) + + describe('#registerUpkeep', () => { + it('reverts with empty message if amount sent is not available in LINK allowance', async () => { + await evmRevert( + registrar.connect(someAddress).registerUpkeep({ + name: upkeepName, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + triggerType: 0, + checkData: emptyBytes, + triggerConfig: trigger, + offchainConfig: emptyBytes, + amount, + encryptedEmail: emptyBytes, + }), + '', + ) + }) + + it('reverts if the amount passed in data is less than configured minimum', async () => { + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_ALL, + maxAllowedAutoApprove, + ) + + // amt is one order of magnitude less than minUpkeepSpend + const amt = BigNumber.from('100000000000000000') + + await evmRevert( + registrar.connect(someAddress).registerUpkeep({ + name: upkeepName, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + triggerType: 0, + checkData: emptyBytes, + triggerConfig: trigger, + offchainConfig: emptyBytes, + amount: amt, + encryptedEmail: emptyBytes, + }), + 'InsufficientPayment()', + ) + }) + + it('Auto Approve ON - registers an upkeep on KeeperRegistry instantly and emits both RegistrationRequested and RegistrationApproved events', async () => { + //set auto approve ON with high threshold limits + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_ENABLED_ALL, + maxAllowedAutoApprove, + ) + + await linkToken.connect(requestSender).approve(registrar.address, amount) + + const tx = await registrar.connect(requestSender).registerUpkeep({ + name: upkeepName, + upkeepContract: mock.address, + gasLimit: performGas, + adminAddress: await admin.getAddress(), + triggerType: 0, + checkData: emptyBytes, + triggerConfig: trigger, + offchainConfig, + amount, + encryptedEmail: emptyBytes, + }) + assert.equal((await registry.getState()).state.numUpkeeps.toNumber(), 1) // 0 -> 1 + + //confirm if a new upkeep has been registered and the details are the same as the one just registered + const [id] = await registry.getActiveUpkeepIDs(0, 1) + const newupkeep = await registry.getUpkeep(id) + assert.equal(newupkeep.target, mock.address) + assert.equal(newupkeep.admin, await admin.getAddress()) + assert.equal(newupkeep.checkData, emptyBytes) + assert.equal(newupkeep.balance.toString(), amount.toString()) + assert.equal(newupkeep.performGas, performGas.toNumber()) + assert.equal(newupkeep.offchainConfig, offchainConfig) + + await expect(tx).to.emit(registrar, 'RegistrationRequested') + await expect(tx).to.emit(registrar, 'RegistrationApproved') + }) + }) + + describe('#setAutoApproveAllowedSender', () => { + it('reverts if not called by the owner', async () => { + const tx = registrar + .connect(stranger) + .setAutoApproveAllowedSender(await admin.getAddress(), false) + await evmRevert(tx, 'Only callable by owner') + }) + + it('sets the allowed status correctly and emits log', async () => { + const senderAddress = await stranger.getAddress() + let tx = await registrar + .connect(registrarOwner) + .setAutoApproveAllowedSender(senderAddress, true) + await expect(tx) + .to.emit(registrar, 'AutoApproveAllowedSenderSet') + .withArgs(senderAddress, true) + + let senderAllowedStatus = await registrar + .connect(owner) + .getAutoApproveAllowedSender(senderAddress) + assert.isTrue(senderAllowedStatus) + + tx = await registrar + .connect(registrarOwner) + .setAutoApproveAllowedSender(senderAddress, false) + await expect(tx) + .to.emit(registrar, 'AutoApproveAllowedSenderSet') + .withArgs(senderAddress, false) + + senderAllowedStatus = await registrar + .connect(owner) + .getAutoApproveAllowedSender(senderAddress) + assert.isFalse(senderAllowedStatus) + }) + }) + + describe('#setTriggerConfig', () => { + it('reverts if not called by the owner', async () => { + const tx = registrar + .connect(stranger) + .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) + await evmRevert(tx, 'Only callable by owner') + }) + + it('changes the config', async () => { + const tx = await registrar + .connect(registrarOwner) + .setTriggerConfig(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) + await registrar.getTriggerRegistrationDetails(Trigger.LOG) + await expect(tx) + .to.emit(registrar, 'TriggerConfigSet') + .withArgs(Trigger.LOG, autoApproveType_ENABLED_ALL, 100) + }) + }) + + describe('#approve', () => { + let hash: string + + beforeEach(async () => { + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_DISABLED, + maxAllowedAutoApprove, + ) + + //register with auto approve OFF + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + const receipt = await tx.wait() + hash = receipt.logs[2].topics[1] + }) + + it('reverts if not called by the owner', async () => { + const tx = registrar + .connect(stranger) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, 'Only callable by owner') + }) + + it('reverts if the hash does not exist', async () => { + const tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + emptyBytes, + '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', + ) + await evmRevert(tx, errorMsgs.requestNotFound) + }) + + it('reverts if any member of the payload changes', async () => { + let tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + ethers.Wallet.createRandom().address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, errorMsgs.hashPayload) + tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + 10000, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, errorMsgs.hashPayload) + tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + ethers.Wallet.createRandom().address, + 0, + emptyBytes, + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, errorMsgs.hashPayload) + tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + '0x1234', + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, errorMsgs.hashPayload) + }) + + it('approves an existing registration request', async () => { + const tx = await registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + hash, + ) + await expect(tx).to.emit(registrar, 'RegistrationApproved') + }) + + it('deletes the request afterwards / reverts if the request DNE', async () => { + await registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + hash, + ) + const tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + hash, + ) + await evmRevert(tx, errorMsgs.requestNotFound) + }) + }) + + describe('#cancel', () => { + let hash: string + + beforeEach(async () => { + await registrar + .connect(registrarOwner) + .setTriggerConfig( + Trigger.CONDITION, + autoApproveType_DISABLED, + maxAllowedAutoApprove, + ) + + //register with auto approve OFF + const abiEncodedBytes = registrar.interface.encodeFunctionData( + 'register', + [ + upkeepName, + emptyBytes, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + offchainConfig, + amount, + await requestSender.getAddress(), + ], + ) + const tx = await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + const receipt = await tx.wait() + hash = receipt.logs[2].topics[1] + // submit duplicate request (increase balance) + await linkToken + .connect(requestSender) + .transferAndCall(registrar.address, amount, abiEncodedBytes) + }) + + it('reverts if not called by the admin / owner', async () => { + const tx = registrar.connect(stranger).cancel(hash) + await evmRevert(tx, errorMsgs.onlyAdmin) + }) + + it('reverts if the hash does not exist', async () => { + const tx = registrar + .connect(registrarOwner) + .cancel( + '0x000000000000000000000000322813fd9a801c5507c9de605d63cea4f2ce6c44', + ) + await evmRevert(tx, errorMsgs.requestNotFound) + }) + + it('refunds the total request balance to the admin address if owner cancels', async () => { + const before = await linkToken.balanceOf(await admin.getAddress()) + const tx = await registrar.connect(registrarOwner).cancel(hash) + const after = await linkToken.balanceOf(await admin.getAddress()) + assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) + await expect(tx).to.emit(registrar, 'RegistrationRejected') + }) + + it('refunds the total request balance to the admin address if admin cancels', async () => { + const before = await linkToken.balanceOf(await admin.getAddress()) + const tx = await registrar.connect(admin).cancel(hash) + const after = await linkToken.balanceOf(await admin.getAddress()) + assert.isTrue(after.sub(before).eq(amount.mul(BigNumber.from(2)))) + await expect(tx).to.emit(registrar, 'RegistrationRejected') + }) + + it('deletes the request hash', async () => { + await registrar.connect(registrarOwner).cancel(hash) + let tx = registrar.connect(registrarOwner).cancel(hash) + await evmRevert(tx, errorMsgs.requestNotFound) + tx = registrar + .connect(registrarOwner) + .approve( + upkeepName, + mock.address, + performGas, + await admin.getAddress(), + 0, + emptyBytes, + trigger, + emptyBytes, + hash, + ) + await evmRevert(tx, errorMsgs.requestNotFound) + }) + }) +}) diff --git a/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts b/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts new file mode 100644 index 00000000000..740e4ac1c27 --- /dev/null +++ b/contracts/test/v0.8/automation/AutomationRegistry2_2.test.ts @@ -0,0 +1,5764 @@ +import { ethers } from 'hardhat' +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' +import { assert, expect } from 'chai' +import { + BigNumber, + BigNumberish, + BytesLike, + Contract, + ContractFactory, + ContractReceipt, + ContractTransaction, + Signer, + Wallet, +} from 'ethers' +import { evmRevert } from '../../test-helpers/matchers' +import { getUsers, Personas } from '../../test-helpers/setup' +import { randomAddress, toWei } from '../../test-helpers/helpers' +import { StreamsLookupUpkeep__factory as StreamsLookupUpkeepFactory } from '../../../typechain/factories/StreamsLookupUpkeep__factory' +import { MockV3Aggregator__factory as MockV3AggregatorFactory } from '../../../typechain/factories/MockV3Aggregator__factory' +import { UpkeepMock__factory as UpkeepMockFactory } from '../../../typechain/factories/UpkeepMock__factory' +import { UpkeepAutoFunder__factory as UpkeepAutoFunderFactory } from '../../../typechain/factories/UpkeepAutoFunder__factory' +import { MockArbGasInfo__factory as MockArbGasInfoFactory } from '../../../typechain/factories/MockArbGasInfo__factory' +import { MockOVMGasPriceOracle__factory as MockOVMGasPriceOracleFactory } from '../../../typechain/factories/MockOVMGasPriceOracle__factory' +import { ILogAutomation__factory as ILogAutomationactory } from '../../../typechain/factories/ILogAutomation__factory' +import { IAutomationForwarder__factory as IAutomationForwarderFactory } from '../../../typechain/factories/IAutomationForwarder__factory' +import { MockArbSys__factory as MockArbSysFactory } from '../../../typechain/factories/MockArbSys__factory' +import { AutomationUtils2_2 as AutomationUtils } from '../../../typechain/AutomationUtils2_2' +import { StreamsLookupUpkeep } from '../../../typechain/StreamsLookupUpkeep' +import { MockV3Aggregator } from '../../../typechain/MockV3Aggregator' +import { UpkeepMock } from '../../../typechain/UpkeepMock' +import { MockArbGasInfo } from '../../../typechain/MockArbGasInfo' +import { MockOVMGasPriceOracle } from '../../../typechain/MockOVMGasPriceOracle' +import { UpkeepTranscoder } from '../../../typechain/UpkeepTranscoder' +import { UpkeepAutoFunder } from '../../../typechain' +import { + CancelledUpkeepReportEvent, + IAutomationRegistryMaster as IAutomationRegistry, + InsufficientFundsUpkeepReportEvent, + ReorgedUpkeepReportEvent, + StaleUpkeepReportEvent, + UpkeepPerformedEvent, +} from '../../../typechain/IAutomationRegistryMaster' +import { + deployMockContract, + MockContract, +} from '@ethereum-waffle/mock-contract' +import { deployRegistry22 } from './helpers' + +const describeMaybe = process.env.SKIP_SLOW ? describe.skip : describe +const itMaybe = process.env.SKIP_SLOW ? it.skip : it + +// copied from AutomationRegistryInterface2_2.sol +enum UpkeepFailureReason { + NONE, + UPKEEP_CANCELLED, + UPKEEP_PAUSED, + TARGET_CHECK_REVERTED, + UPKEEP_NOT_NEEDED, + PERFORM_DATA_EXCEEDS_LIMIT, + INSUFFICIENT_BALANCE, + CHECK_CALLBACK_REVERTED, + REVERT_DATA_EXCEEDS_LIMIT, + REGISTRY_PAUSED, +} + +// copied from AutomationRegistryInterface2_2.sol +enum Mode { + DEFAULT, + ARBITRUM, + OPTIMISM, +} + +// copied from AutomationRegistryBase2_2.sol +enum Trigger { + CONDITION, + LOG, +} + +// un-exported types that must be extracted from the utils contract +type Report = Parameters[0] +type OnChainConfig = Parameters[0] +type LogTrigger = Parameters[0] +type ConditionalTrigger = Parameters[0] +type Log = Parameters[0] + +// ----------------------------------------------------------------------------------------------- + +// These values should match the constants declared in registry +let registryConditionalOverhead: BigNumber +let registryLogOverhead: BigNumber +let registryPerSignerGasOverhead: BigNumber +let registryPerPerformByteGasOverhead: BigNumber +let cancellationDelay: number + +// This is the margin for gas that we test for. Gas charged should always be greater +// than total gas used in tx but should not increase beyond this margin +const gasCalculationMargin = BigNumber.from(8000) + +const linkEth = BigNumber.from(5000000000000000) // 1 Link = 0.005 Eth +const gasWei = BigNumber.from(1000000000) // 1 gwei +// ----------------------------------------------------------------------------------------------- +// test-wide configs for upkeeps +const linkDivisibility = BigNumber.from('1000000000000000000') +const performGas = BigNumber.from('1000000') +const paymentPremiumBase = BigNumber.from('1000000000') +const paymentPremiumPPB = BigNumber.from('250000000') +const flatFeeMicroLink = BigNumber.from(0) + +const randomBytes = '0x1234abcd' +const emptyBytes = '0x' +const emptyBytes32 = + '0x0000000000000000000000000000000000000000000000000000000000000000' + +const transmitGasOverhead = 1_000_000 +const checkGasOverhead = 400_000 + +const stalenessSeconds = BigNumber.from(43820) +const gasCeilingMultiplier = BigNumber.from(2) +const checkGasLimit = BigNumber.from(10000000) +const fallbackGasPrice = gasWei.mul(BigNumber.from('2')) +const fallbackLinkPrice = linkEth.div(BigNumber.from('2')) +const maxCheckDataSize = BigNumber.from(1000) +const maxPerformDataSize = BigNumber.from(1000) +const maxRevertDataSize = BigNumber.from(1000) +const maxPerformGas = BigNumber.from(5000000) +const minUpkeepSpend = BigNumber.from(0) +const f = 1 +const offchainVersion = 1 +const offchainBytes = '0x' +const zeroAddress = ethers.constants.AddressZero +const epochAndRound5_1 = + '0x0000000000000000000000000000000000000000000000000000000000000501' + +let logTriggerConfig: string + +// ----------------------------------------------------------------------------------------------- + +// Smart contract factories +let linkTokenFactory: ContractFactory +let mockV3AggregatorFactory: MockV3AggregatorFactory +let upkeepMockFactory: UpkeepMockFactory +let upkeepAutoFunderFactory: UpkeepAutoFunderFactory +let mockArbGasInfoFactory: MockArbGasInfoFactory +let mockOVMGasPriceOracleFactory: MockOVMGasPriceOracleFactory +let streamsLookupUpkeepFactory: StreamsLookupUpkeepFactory +let personas: Personas + +// contracts +let linkToken: Contract +let linkEthFeed: MockV3Aggregator +let gasPriceFeed: MockV3Aggregator +let registry: IAutomationRegistry // default registry, used for most tests +let arbRegistry: IAutomationRegistry // arbitrum registry +let opRegistry: IAutomationRegistry // optimism registry +let mgRegistry: IAutomationRegistry // "migrate registry" used in migration tests +let blankRegistry: IAutomationRegistry // used to test initial configurations +let mock: UpkeepMock +let autoFunderUpkeep: UpkeepAutoFunder +let ltUpkeep: MockContract +let transcoder: UpkeepTranscoder +let mockArbGasInfo: MockArbGasInfo +let mockOVMGasPriceOracle: MockOVMGasPriceOracle +let streamsLookupUpkeep: StreamsLookupUpkeep +let automationUtils: AutomationUtils + +function now() { + return Math.floor(Date.now() / 1000) +} + +async function getUpkeepID(tx: ContractTransaction): Promise { + const receipt = await tx.wait() + for (const event of receipt.events || []) { + if ( + event.args && + event.eventSignature == 'UpkeepRegistered(uint256,uint32,address)' + ) { + return event.args[0] + } + } + throw new Error('could not find upkeep ID in tx event logs') +} + +const getTriggerType = (upkeepId: BigNumber): Trigger => { + const hexBytes = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) + const bytes = ethers.utils.arrayify(hexBytes) + for (let idx = 4; idx < 15; idx++) { + if (bytes[idx] != 0) { + return Trigger.CONDITION + } + } + return bytes[15] as Trigger +} + +const encodeConfig = (onchainConfig: OnChainConfig) => { + return ( + '0x' + + automationUtils.interface + .encodeFunctionData('_onChainConfig', [onchainConfig]) + .slice(10) + ) +} + +const encodeBlockTrigger = (conditionalTrigger: ConditionalTrigger) => { + return ( + '0x' + + automationUtils.interface + .encodeFunctionData('_conditionalTrigger', [conditionalTrigger]) + .slice(10) + ) +} + +const encodeLogTrigger = (logTrigger: LogTrigger) => { + return ( + '0x' + + automationUtils.interface + .encodeFunctionData('_logTrigger', [logTrigger]) + .slice(10) + ) +} + +const encodeLog = (log: Log) => { + return ( + '0x' + automationUtils.interface.encodeFunctionData('_log', [log]).slice(10) + ) +} + +const encodeReport = (report: Report) => { + return ( + '0x' + + automationUtils.interface.encodeFunctionData('_report', [report]).slice(10) + ) +} + +type UpkeepData = { + Id: BigNumberish + performGas: BigNumberish + performData: BytesLike + trigger: BytesLike +} + +const makeReport = (upkeeps: UpkeepData[]) => { + const upkeepIds = upkeeps.map((u) => u.Id) + const performGases = upkeeps.map((u) => u.performGas) + const triggers = upkeeps.map((u) => u.trigger) + const performDatas = upkeeps.map((u) => u.performData) + return encodeReport({ + fastGasWei: gasWei, + linkNative: linkEth, + upkeepIds, + gasLimits: performGases, + triggers, + performDatas, + }) +} + +const makeLatestBlockReport = async (upkeepsIDs: BigNumberish[]) => { + const latestBlock = await ethers.provider.getBlock('latest') + const upkeeps: UpkeepData[] = [] + for (let i = 0; i < upkeepsIDs.length; i++) { + upkeeps.push({ + Id: upkeepsIDs[i], + performGas, + trigger: encodeBlockTrigger({ + blockNum: latestBlock.number, + blockHash: latestBlock.hash, + }), + performData: '0x', + }) + } + return makeReport(upkeeps) +} + +const signReport = ( + reportContext: string[], + report: any, + signers: Wallet[], +) => { + const reportDigest = ethers.utils.keccak256(report) + const packedArgs = ethers.utils.solidityPack( + ['bytes32', 'bytes32[3]'], + [reportDigest, reportContext], + ) + const packedDigest = ethers.utils.keccak256(packedArgs) + + const signatures = [] + for (const signer of signers) { + signatures.push(signer._signingKey().signDigest(packedDigest)) + } + const vs = signatures.map((i) => '0' + (i.v - 27).toString(16)).join('') + return { + vs: '0x' + vs.padEnd(64, '0'), + rs: signatures.map((i) => i.r), + ss: signatures.map((i) => i.s), + } +} + +const parseUpkeepPerformedLogs = (receipt: ContractReceipt) => { + const parsedLogs = [] + for (const rawLog of receipt.logs) { + try { + const log = registry.interface.parseLog(rawLog) + if ( + log.name == + registry.interface.events[ + 'UpkeepPerformed(uint256,bool,uint96,uint256,uint256,bytes)' + ].name + ) { + parsedLogs.push(log as unknown as UpkeepPerformedEvent) + } + } catch { + continue + } + } + return parsedLogs +} + +const parseReorgedUpkeepReportLogs = (receipt: ContractReceipt) => { + const parsedLogs = [] + for (const rawLog of receipt.logs) { + try { + const log = registry.interface.parseLog(rawLog) + if ( + log.name == + registry.interface.events['ReorgedUpkeepReport(uint256,bytes)'].name + ) { + parsedLogs.push(log as unknown as ReorgedUpkeepReportEvent) + } + } catch { + continue + } + } + return parsedLogs +} + +const parseStaleUpkeepReportLogs = (receipt: ContractReceipt) => { + const parsedLogs = [] + for (const rawLog of receipt.logs) { + try { + const log = registry.interface.parseLog(rawLog) + if ( + log.name == + registry.interface.events['StaleUpkeepReport(uint256,bytes)'].name + ) { + parsedLogs.push(log as unknown as StaleUpkeepReportEvent) + } + } catch { + continue + } + } + return parsedLogs +} + +const parseInsufficientFundsUpkeepReportLogs = (receipt: ContractReceipt) => { + const parsedLogs = [] + for (const rawLog of receipt.logs) { + try { + const log = registry.interface.parseLog(rawLog) + if ( + log.name == + registry.interface.events[ + 'InsufficientFundsUpkeepReport(uint256,bytes)' + ].name + ) { + parsedLogs.push(log as unknown as InsufficientFundsUpkeepReportEvent) + } + } catch { + continue + } + } + return parsedLogs +} + +const parseCancelledUpkeepReportLogs = (receipt: ContractReceipt) => { + const parsedLogs = [] + for (const rawLog of receipt.logs) { + try { + const log = registry.interface.parseLog(rawLog) + if ( + log.name == + registry.interface.events['CancelledUpkeepReport(uint256,bytes)'].name + ) { + parsedLogs.push(log as unknown as CancelledUpkeepReportEvent) + } + } catch { + continue + } + } + return parsedLogs +} + +describe('AutomationRegistry2_2', () => { + let owner: Signer + let keeper1: Signer + let keeper2: Signer + let keeper3: Signer + let keeper4: Signer + let keeper5: Signer + let nonkeeper: Signer + let signer1: Wallet + let signer2: Wallet + let signer3: Wallet + let signer4: Wallet + let signer5: Wallet + let admin: Signer + let payee1: Signer + let payee2: Signer + let payee3: Signer + let payee4: Signer + let payee5: Signer + + let upkeepId: BigNumber // conditional upkeep + let afUpkeepId: BigNumber // auto funding upkeep + let logUpkeepId: BigNumber // log trigger upkeepID + let streamsLookupUpkeepId: BigNumber // streams lookup upkeep + const numUpkeeps = 4 // see above + let keeperAddresses: string[] + let payees: string[] + let signers: Wallet[] + let signerAddresses: string[] + let config: any + let baseConfig: Parameters + let upkeepManager: string + + before(async () => { + personas = (await getUsers()).personas + + const utilsFactory = await ethers.getContractFactory('AutomationUtils2_2') + automationUtils = await utilsFactory.deploy() + + linkTokenFactory = await ethers.getContractFactory( + 'src/v0.4/LinkToken.sol:LinkToken', + ) + // need full path because there are two contracts with name MockV3Aggregator + mockV3AggregatorFactory = (await ethers.getContractFactory( + 'src/v0.8/tests/MockV3Aggregator.sol:MockV3Aggregator', + )) as unknown as MockV3AggregatorFactory + upkeepMockFactory = await ethers.getContractFactory('UpkeepMock') + upkeepAutoFunderFactory = + await ethers.getContractFactory('UpkeepAutoFunder') + mockArbGasInfoFactory = await ethers.getContractFactory('MockArbGasInfo') + mockOVMGasPriceOracleFactory = await ethers.getContractFactory( + 'MockOVMGasPriceOracle', + ) + streamsLookupUpkeepFactory = await ethers.getContractFactory( + 'StreamsLookupUpkeep', + ) + + owner = personas.Default + keeper1 = personas.Carol + keeper2 = personas.Eddy + keeper3 = personas.Nancy + keeper4 = personas.Norbert + keeper5 = personas.Nick + nonkeeper = personas.Ned + admin = personas.Neil + payee1 = personas.Nelly + payee2 = personas.Norbert + payee3 = personas.Nick + payee4 = personas.Eddy + payee5 = personas.Carol + upkeepManager = await personas.Norbert.getAddress() + // signers + signer1 = new ethers.Wallet( + '0x7777777000000000000000000000000000000000000000000000000000000001', + ) + signer2 = new ethers.Wallet( + '0x7777777000000000000000000000000000000000000000000000000000000002', + ) + signer3 = new ethers.Wallet( + '0x7777777000000000000000000000000000000000000000000000000000000003', + ) + signer4 = new ethers.Wallet( + '0x7777777000000000000000000000000000000000000000000000000000000004', + ) + signer5 = new ethers.Wallet( + '0x7777777000000000000000000000000000000000000000000000000000000005', + ) + + keeperAddresses = [ + await keeper1.getAddress(), + await keeper2.getAddress(), + await keeper3.getAddress(), + await keeper4.getAddress(), + await keeper5.getAddress(), + ] + payees = [ + await payee1.getAddress(), + await payee2.getAddress(), + await payee3.getAddress(), + await payee4.getAddress(), + await payee5.getAddress(), + ] + signers = [signer1, signer2, signer3, signer4, signer5] + + // We append 26 random addresses to keepers, payees and signers to get a system of 31 oracles + // This allows f value of 1 - 10 + for (let i = 0; i < 26; i++) { + keeperAddresses.push(randomAddress()) + payees.push(randomAddress()) + signers.push(ethers.Wallet.createRandom()) + } + signerAddresses = [] + for (const signer of signers) { + signerAddresses.push(await signer.getAddress()) + } + + logTriggerConfig = + '0x' + + automationUtils.interface + .encodeFunctionData('_logTriggerConfig', [ + { + contractAddress: randomAddress(), + filterSelector: 0, + topic0: ethers.utils.randomBytes(32), + topic1: ethers.utils.randomBytes(32), + topic2: ethers.utils.randomBytes(32), + topic3: ethers.utils.randomBytes(32), + }, + ]) + .slice(10) + }) + + const linkForGas = ( + upkeepGasSpent: BigNumber, + gasOverhead: BigNumber, + gasMultiplier: BigNumber, + premiumPPB: BigNumber, + flatFee: BigNumber, + l1CostWei?: BigNumber, + numUpkeepsBatch?: BigNumber, + ) => { + l1CostWei = l1CostWei === undefined ? BigNumber.from(0) : l1CostWei + numUpkeepsBatch = + numUpkeepsBatch === undefined ? BigNumber.from(1) : numUpkeepsBatch + + const gasSpent = gasOverhead.add(BigNumber.from(upkeepGasSpent)) + const base = gasWei + .mul(gasMultiplier) + .mul(gasSpent) + .mul(linkDivisibility) + .div(linkEth) + const l1Fee = l1CostWei + .mul(gasMultiplier) + .div(numUpkeepsBatch) + .mul(linkDivisibility) + .div(linkEth) + const gasPayment = base.add(l1Fee) + + const premium = gasWei + .mul(gasMultiplier) + .mul(upkeepGasSpent) + .add(l1CostWei.mul(gasMultiplier).div(numUpkeepsBatch)) + .mul(linkDivisibility) + .div(linkEth) + .mul(premiumPPB) + .div(paymentPremiumBase) + .add(BigNumber.from(flatFee).mul('1000000000000')) + + return { + total: gasPayment.add(premium), + gasPaymemnt: gasPayment, + premium, + } + } + + const verifyMaxPayment = async ( + registry: IAutomationRegistry, + l1CostWei?: BigNumber, + ) => { + type TestCase = { + name: string + multiplier: number + gas: number + premium: number + flatFee: number + } + + const tests: TestCase[] = [ + { + name: 'no fees', + multiplier: 1, + gas: 100000, + premium: 0, + flatFee: 0, + }, + { + name: 'basic fees', + multiplier: 1, + gas: 100000, + premium: 250000000, + flatFee: 1000000, + }, + { + name: 'max fees', + multiplier: 3, + gas: 10000000, + premium: 250000000, + flatFee: 1000000, + }, + ] + + const fPlusOne = BigNumber.from(f + 1) + const totalConditionalOverhead = registryConditionalOverhead + .add(registryPerSignerGasOverhead.mul(fPlusOne)) + .add(registryPerPerformByteGasOverhead.mul(maxPerformDataSize)) + const totalLogOverhead = registryLogOverhead + .add(registryPerSignerGasOverhead.mul(fPlusOne)) + .add(registryPerPerformByteGasOverhead.mul(maxPerformDataSize)) + + for (const test of tests) { + await registry.connect(owner).setConfig( + signerAddresses, + keeperAddresses, + f, + encodeConfig({ + paymentPremiumPPB: test.premium, + flatFeeMicroLink: test.flatFee, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier: test.multiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + reorgProtectionEnabled: true, + }), + offchainVersion, + offchainBytes, + ) + + const conditionalPrice = await registry.getMaxPaymentForGas( + Trigger.CONDITION, + test.gas, + ) + expect(conditionalPrice).to.equal( + linkForGas( + BigNumber.from(test.gas), + totalConditionalOverhead, + BigNumber.from(test.multiplier), + BigNumber.from(test.premium), + BigNumber.from(test.flatFee), + l1CostWei, + ).total, + ) + + const logPrice = await registry.getMaxPaymentForGas(Trigger.LOG, test.gas) + expect(logPrice).to.equal( + linkForGas( + BigNumber.from(test.gas), + totalLogOverhead, + BigNumber.from(test.multiplier), + BigNumber.from(test.premium), + BigNumber.from(test.flatFee), + l1CostWei, + ).total, + ) + } + } + + const verifyConsistentAccounting = async ( + maxAllowedSpareChange: BigNumber, + ) => { + const expectedLinkBalance = (await registry.getState()).state + .expectedLinkBalance + const linkTokenBalance = await linkToken.balanceOf(registry.address) + const upkeepIdBalance = (await registry.getUpkeep(upkeepId)).balance + let totalKeeperBalance = BigNumber.from(0) + for (let i = 0; i < keeperAddresses.length; i++) { + totalKeeperBalance = totalKeeperBalance.add( + (await registry.getTransmitterInfo(keeperAddresses[i])).balance, + ) + } + const ownerBalance = (await registry.getState()).state.ownerLinkBalance + assert.isTrue(expectedLinkBalance.eq(linkTokenBalance)) + assert.isTrue( + upkeepIdBalance + .add(totalKeeperBalance) + .add(ownerBalance) + .lte(expectedLinkBalance), + ) + assert.isTrue( + expectedLinkBalance + .sub(upkeepIdBalance) + .sub(totalKeeperBalance) + .sub(ownerBalance) + .lte(maxAllowedSpareChange), + ) + } + + interface GetTransmitTXOptions { + numSigners?: number + startingSignerIndex?: number + gasLimit?: BigNumberish + gasPrice?: BigNumberish + performGas?: BigNumberish + performData?: string + checkBlockNum?: number + checkBlockHash?: string + logBlockHash?: BytesLike + txHash?: BytesLike + logIndex?: number + timestamp?: number + } + + const getTransmitTx = async ( + registry: IAutomationRegistry, + transmitter: Signer, + upkeepIds: BigNumber[], + overrides: GetTransmitTXOptions = {}, + ) => { + const latestBlock = await ethers.provider.getBlock('latest') + const configDigest = (await registry.getState()).state.latestConfigDigest + const config = { + numSigners: f + 1, + startingSignerIndex: 0, + performData: '0x', + performGas, + checkBlockNum: latestBlock.number, + checkBlockHash: latestBlock.hash, + logIndex: 0, + txHash: undefined, // assigned uniquely below + logBlockHash: undefined, // assigned uniquely below + timestamp: now(), + gasLimit: undefined, + gasPrice: undefined, + } + Object.assign(config, overrides) + const upkeeps: UpkeepData[] = [] + for (let i = 0; i < upkeepIds.length; i++) { + let trigger: string + switch (getTriggerType(upkeepIds[i])) { + case Trigger.CONDITION: + trigger = encodeBlockTrigger({ + blockNum: config.checkBlockNum, + blockHash: config.checkBlockHash, + }) + break + case Trigger.LOG: + trigger = encodeLogTrigger({ + logBlockHash: config.logBlockHash || ethers.utils.randomBytes(32), + txHash: config.txHash || ethers.utils.randomBytes(32), + logIndex: config.logIndex, + blockNum: config.checkBlockNum, + blockHash: config.checkBlockHash, + }) + break + } + upkeeps.push({ + Id: upkeepIds[i], + performGas: config.performGas, + trigger, + performData: config.performData, + }) + } + + const report = makeReport(upkeeps) + const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] + const sigs = signReport( + reportContext, + report, + signers.slice( + config.startingSignerIndex, + config.startingSignerIndex + config.numSigners, + ), + ) + + type txOverride = { + gasLimit?: BigNumberish | Promise + gasPrice?: BigNumberish | Promise + } + const txOverrides: txOverride = {} + if (config.gasLimit) { + txOverrides.gasLimit = config.gasLimit + } + if (config.gasPrice) { + txOverrides.gasPrice = config.gasPrice + } + + return registry + .connect(transmitter) + .transmit( + [configDigest, epochAndRound5_1, emptyBytes32], + report, + sigs.rs, + sigs.ss, + sigs.vs, + txOverrides, + ) + } + + const getTransmitTxWithReport = async ( + registry: IAutomationRegistry, + transmitter: Signer, + report: BytesLike, + ) => { + const configDigest = (await registry.getState()).state.latestConfigDigest + const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] + const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) + + return registry + .connect(transmitter) + .transmit( + [configDigest, epochAndRound5_1, emptyBytes32], + report, + sigs.rs, + sigs.ss, + sigs.vs, + ) + } + + const setup = async () => { + linkToken = await linkTokenFactory.connect(owner).deploy() + gasPriceFeed = await mockV3AggregatorFactory + .connect(owner) + .deploy(0, gasWei) + linkEthFeed = await mockV3AggregatorFactory + .connect(owner) + .deploy(9, linkEth) + const upkeepTranscoderFactory = await ethers.getContractFactory( + 'UpkeepTranscoder4_0', + ) + transcoder = await upkeepTranscoderFactory.connect(owner).deploy() + mockArbGasInfo = await mockArbGasInfoFactory.connect(owner).deploy() + mockOVMGasPriceOracle = await mockOVMGasPriceOracleFactory + .connect(owner) + .deploy() + streamsLookupUpkeep = await streamsLookupUpkeepFactory + .connect(owner) + .deploy( + BigNumber.from('10000'), + BigNumber.from('100'), + false /* useArbBlock */, + true /* staging */, + false /* verify mercury response */, + ) + + const arbOracleCode = await ethers.provider.send('eth_getCode', [ + mockArbGasInfo.address, + ]) + await ethers.provider.send('hardhat_setCode', [ + '0x000000000000000000000000000000000000006C', + arbOracleCode, + ]) + + const optOracleCode = await ethers.provider.send('eth_getCode', [ + mockOVMGasPriceOracle.address, + ]) + await ethers.provider.send('hardhat_setCode', [ + '0x420000000000000000000000000000000000000F', + optOracleCode, + ]) + + const mockArbSys = await new MockArbSysFactory(owner).deploy() + const arbSysCode = await ethers.provider.send('eth_getCode', [ + mockArbSys.address, + ]) + await ethers.provider.send('hardhat_setCode', [ + '0x0000000000000000000000000000000000000064', + arbSysCode, + ]) + + config = { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + reorgProtectionEnabled: true, + } + + baseConfig = [ + signerAddresses, + keeperAddresses, + f, + encodeConfig(config), + offchainVersion, + offchainBytes, + ] + + registry = await deployRegistry22( + owner, + Mode.DEFAULT, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + arbRegistry = await deployRegistry22( + owner, + Mode.ARBITRUM, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + opRegistry = await deployRegistry22( + owner, + Mode.OPTIMISM, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + mgRegistry = await deployRegistry22( + owner, + Mode.DEFAULT, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + blankRegistry = await deployRegistry22( + owner, + Mode.DEFAULT, + linkToken.address, + linkEthFeed.address, + gasPriceFeed.address, + ) + + registryConditionalOverhead = await registry.getConditionalGasOverhead() + registryLogOverhead = await registry.getLogGasOverhead() + registryPerSignerGasOverhead = await registry.getPerSignerGasOverhead() + registryPerPerformByteGasOverhead = + await registry.getPerPerformByteGasOverhead() + cancellationDelay = (await registry.getCancellationDelay()).toNumber() + + for (const reg of [registry, arbRegistry, opRegistry, mgRegistry]) { + await reg.connect(owner).setConfig(...baseConfig) + await reg.connect(owner).setPayees(payees) + await linkToken.connect(admin).approve(reg.address, toWei('1000')) + await linkToken.connect(owner).approve(reg.address, toWei('1000')) + } + + mock = await upkeepMockFactory.deploy() + await linkToken + .connect(owner) + .transfer(await admin.getAddress(), toWei('1000')) + let tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + upkeepId = await getUpkeepID(tx) + + autoFunderUpkeep = await upkeepAutoFunderFactory + .connect(owner) + .deploy(linkToken.address, registry.address) + tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + autoFunderUpkeep.address, + performGas, + autoFunderUpkeep.address, + randomBytes, + '0x', + ) + afUpkeepId = await getUpkeepID(tx) + + ltUpkeep = await deployMockContract(owner, ILogAutomationactory.abi) + tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,uint8,bytes,bytes,bytes)']( + ltUpkeep.address, + performGas, + await admin.getAddress(), + Trigger.LOG, + '0x', + logTriggerConfig, + emptyBytes, + ) + logUpkeepId = await getUpkeepID(tx) + + await autoFunderUpkeep.setUpkeepId(afUpkeepId) + // Give enough funds for upkeep as well as to the upkeep contract + await linkToken + .connect(owner) + .transfer(autoFunderUpkeep.address, toWei('1000')) + + tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + streamsLookupUpkeep.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + streamsLookupUpkeepId = await getUpkeepID(tx) + } + + const getMultipleUpkeepsDeployedAndFunded = async ( + numPassingConditionalUpkeeps: number, + numPassingLogUpkeeps: number, + numFailingUpkeeps: number, + ) => { + const passingConditionalUpkeepIds = [] + const passingLogUpkeepIds = [] + const failingUpkeepIds = [] + for (let i = 0; i < numPassingConditionalUpkeeps; i++) { + const mock = await upkeepMockFactory.deploy() + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(BigNumber.from('0')) + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const condUpkeepId = await getUpkeepID(tx) + passingConditionalUpkeepIds.push(condUpkeepId) + + // Add funds to passing upkeeps + await registry.connect(admin).addFunds(condUpkeepId, toWei('100')) + } + for (let i = 0; i < numPassingLogUpkeeps; i++) { + const mock = await upkeepMockFactory.deploy() + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(BigNumber.from('0')) + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,uint8,bytes,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + Trigger.LOG, + '0x', + logTriggerConfig, + emptyBytes, + ) + const logUpkeepId = await getUpkeepID(tx) + passingLogUpkeepIds.push(logUpkeepId) + + // Add funds to passing upkeeps + await registry.connect(admin).addFunds(logUpkeepId, toWei('100')) + } + for (let i = 0; i < numFailingUpkeeps; i++) { + const mock = await upkeepMockFactory.deploy() + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(BigNumber.from('0')) + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const failingUpkeepId = await getUpkeepID(tx) + failingUpkeepIds.push(failingUpkeepId) + } + return { + passingConditionalUpkeepIds, + passingLogUpkeepIds, + failingUpkeepIds, + } + } + + beforeEach(async () => { + await loadFixture(setup) + }) + + describe('#transmit', () => { + const fArray = [1, 5, 10] + + it('reverts when registry is paused', async () => { + await registry.connect(owner).pause() + await evmRevert( + getTransmitTx(registry, keeper1, [upkeepId]), + 'RegistryPaused()', + ) + }) + + it('reverts when called by non active transmitter', async () => { + await evmRevert( + getTransmitTx(registry, payee1, [upkeepId]), + 'OnlyActiveTransmitters()', + ) + }) + + it('reverts when report data lengths mismatches', async () => { + const upkeepIds = [] + const gasLimits: BigNumber[] = [] + const triggers: string[] = [] + const performDatas = [] + + upkeepIds.push(upkeepId) + gasLimits.push(performGas) + triggers.push('0x') + performDatas.push('0x') + // Push an extra perform data + performDatas.push('0x') + + const report = encodeReport({ + fastGasWei: 0, + linkNative: 0, + upkeepIds, + gasLimits, + triggers, + performDatas, + }) + + await evmRevert( + getTransmitTxWithReport(registry, keeper1, report), + 'InvalidReport()', + ) + }) + + it('returns early when invalid upkeepIds are included in report', async () => { + const tx = await getTransmitTx(registry, keeper1, [ + upkeepId.add(BigNumber.from('1')), + ]) + + const receipt = await tx.wait() + const cancelledUpkeepReportLogs = parseCancelledUpkeepReportLogs(receipt) + // exactly 1 CancelledUpkeepReport log should be emitted + assert.equal(cancelledUpkeepReportLogs.length, 1) + }) + + it('returns early when upkeep has insufficient funds', async () => { + const tx = await getTransmitTx(registry, keeper1, [upkeepId]) + const receipt = await tx.wait() + const insufficientFundsUpkeepReportLogs = + parseInsufficientFundsUpkeepReportLogs(receipt) + // exactly 1 InsufficientFundsUpkeepReportLogs log should be emitted + assert.equal(insufficientFundsUpkeepReportLogs.length, 1) + }) + + it('permits retrying log triggers after funds are added', async () => { + const txHash = ethers.utils.randomBytes(32) + let tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { + txHash, + logIndex: 0, + }) + let receipt = await tx.wait() + const insufficientFundsLogs = + parseInsufficientFundsUpkeepReportLogs(receipt) + assert.equal(insufficientFundsLogs.length, 1) + registry.connect(admin).addFunds(logUpkeepId, toWei('100')) + tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { + txHash, + logIndex: 0, + }) + receipt = await tx.wait() + const performedLogs = parseUpkeepPerformedLogs(receipt) + assert.equal(performedLogs.length, 1) + }) + + context('When the upkeep is funded', async () => { + beforeEach(async () => { + // Fund the upkeep + await Promise.all([ + registry.connect(admin).addFunds(upkeepId, toWei('100')), + registry.connect(admin).addFunds(logUpkeepId, toWei('100')), + ]) + }) + + it('handles duplicate upkeepIDs', async () => { + const tests: [string, BigNumber, number, number][] = [ + // [name, upkeep, num stale, num performed] + ['conditional', upkeepId, 1, 1], // checkBlocks must be sequential + ['log-trigger', logUpkeepId, 0, 2], // logs are deduped based on the "trigger ID" + ] + for (const [type, id, nStale, nPerformed] of tests) { + const tx = await getTransmitTx(registry, keeper1, [id, id]) + const receipt = await tx.wait() + const staleUpkeepReport = parseStaleUpkeepReportLogs(receipt) + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + assert.equal( + staleUpkeepReport.length, + nStale, + `wrong log count for ${type} upkeep`, + ) + assert.equal( + upkeepPerformedLogs.length, + nPerformed, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('handles duplicate log triggers', async () => { + const logBlockHash = ethers.utils.randomBytes(32) + const txHash = ethers.utils.randomBytes(32) + const logIndex = 0 + const expectedDedupKey = ethers.utils.solidityKeccak256( + ['uint256', 'bytes32', 'bytes32', 'uint32'], + [logUpkeepId, logBlockHash, txHash, logIndex], + ) + assert.isFalse(await registry.hasDedupKey(expectedDedupKey)) + const tx = await getTransmitTx( + registry, + keeper1, + [logUpkeepId, logUpkeepId], + { logBlockHash, txHash, logIndex }, // will result in the same dedup key + ) + const receipt = await tx.wait() + const staleUpkeepReport = parseStaleUpkeepReportLogs(receipt) + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + assert.equal(staleUpkeepReport.length, 1) + assert.equal(upkeepPerformedLogs.length, 1) + assert.isTrue(await registry.hasDedupKey(expectedDedupKey)) + await expect(tx) + .to.emit(registry, 'DedupKeyAdded') + .withArgs(expectedDedupKey) + }) + + it('returns early when check block number is less than last perform (block)', async () => { + // First perform an upkeep to put last perform block number on upkeep state + const tx = await getTransmitTx(registry, keeper1, [upkeepId]) + await tx.wait() + const lastPerformed = (await registry.getUpkeep(upkeepId)) + .lastPerformedBlockNumber + const lastPerformBlock = await ethers.provider.getBlock(lastPerformed) + assert.equal(lastPerformed.toString(), tx.blockNumber?.toString()) + // Try to transmit a report which has checkBlockNumber = lastPerformed-1, should result in stale report + const transmitTx = await getTransmitTx(registry, keeper1, [upkeepId], { + checkBlockNum: lastPerformBlock.number - 1, + checkBlockHash: lastPerformBlock.parentHash, + }) + const receipt = await transmitTx.wait() + const staleUpkeepReportLogs = parseStaleUpkeepReportLogs(receipt) + // exactly 1 StaleUpkeepReportLogs log should be emitted + assert.equal(staleUpkeepReportLogs.length, 1) + }) + + it('handles case when check block hash does not match', async () => { + const tests: [string, BigNumber][] = [ + ['conditional', upkeepId], + ['log-trigger', logUpkeepId], + ] + for (const [type, id] of tests) { + const latestBlock = await ethers.provider.getBlock('latest') + // Try to transmit a report which has incorrect checkBlockHash + const tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: latestBlock.number - 1, + checkBlockHash: latestBlock.hash, // should be latestBlock.parentHash + }) + + const receipt = await tx.wait() + const reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) + // exactly 1 ReorgedUpkeepReportLogs log should be emitted + assert.equal( + reorgedUpkeepReportLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('handles case when check block number is older than 256 blocks', async () => { + for (let i = 0; i < 256; i++) { + await ethers.provider.send('evm_mine', []) + } + const tests: [string, BigNumber][] = [ + ['conditional', upkeepId], + ['log-trigger', logUpkeepId], + ] + for (const [type, id] of tests) { + const latestBlock = await ethers.provider.getBlock('latest') + const old = await ethers.provider.getBlock(latestBlock.number - 256) + // Try to transmit a report which has incorrect checkBlockHash + const tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: old.number, + checkBlockHash: old.hash, + }) + + const receipt = await tx.wait() + const reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) + // exactly 1 ReorgedUpkeepReportLogs log should be emitted + assert.equal( + reorgedUpkeepReportLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('allows bypassing reorg protection with empty blockhash', async () => { + const tests: [string, BigNumber][] = [ + ['conditional', upkeepId], + ['log-trigger', logUpkeepId], + ] + for (const [type, id] of tests) { + const latestBlock = await ethers.provider.getBlock('latest') + const tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: latestBlock.number, + checkBlockHash: emptyBytes32, + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + assert.equal( + upkeepPerformedLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('allows very old trigger block numbers when bypassing reorg protection with empty blockhash', async () => { + // mine enough blocks so that blockhash(1) is unavailable + for (let i = 0; i <= 256; i++) { + await ethers.provider.send('evm_mine', []) + } + const tests: [string, BigNumber][] = [ + ['conditional', upkeepId], + ['log-trigger', logUpkeepId], + ] + for (const [type, id] of tests) { + const tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: 1, + checkBlockHash: emptyBytes32, + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + assert.equal( + upkeepPerformedLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('returns early when future block number is provided as trigger, irrespective of blockhash being present', async () => { + const tests: [string, BigNumber][] = [ + ['conditional', upkeepId], + ['log-trigger', logUpkeepId], + ] + for (const [type, id] of tests) { + const latestBlock = await ethers.provider.getBlock('latest') + + // Should fail when blockhash is empty + let tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: latestBlock.number + 100, + checkBlockHash: emptyBytes32, + }) + let receipt = await tx.wait() + let reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) + // exactly 1 ReorgedUpkeepReportLogs log should be emitted + assert.equal( + reorgedUpkeepReportLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + + // Should also fail when blockhash is not empty + tx = await getTransmitTx(registry, keeper1, [id], { + checkBlockNum: latestBlock.number + 100, + checkBlockHash: latestBlock.hash, + }) + receipt = await tx.wait() + reorgedUpkeepReportLogs = parseReorgedUpkeepReportLogs(receipt) + // exactly 1 ReorgedUpkeepReportLogs log should be emitted + assert.equal( + reorgedUpkeepReportLogs.length, + 1, + `wrong log count for ${type} upkeep`, + ) + } + }) + + it('returns early when upkeep is cancelled and cancellation delay has gone', async () => { + const latestBlockReport = await makeLatestBlockReport([upkeepId]) + await registry.connect(admin).cancelUpkeep(upkeepId) + + for (let i = 0; i < cancellationDelay; i++) { + await ethers.provider.send('evm_mine', []) + } + + const tx = await getTransmitTxWithReport( + registry, + keeper1, + latestBlockReport, + ) + + const receipt = await tx.wait() + const cancelledUpkeepReportLogs = + parseCancelledUpkeepReportLogs(receipt) + // exactly 1 CancelledUpkeepReport log should be emitted + assert.equal(cancelledUpkeepReportLogs.length, 1) + }) + + it('does not revert if the target cannot execute', async () => { + await mock.setCanPerform(false) + const tx = await getTransmitTx(registry, keeper1, [upkeepId]) + + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const success = upkeepPerformedLog.args.success + assert.equal(success, false) + }) + + it('does not revert if the target runs out of gas', async () => { + await mock.setCanPerform(false) + + const tx = await getTransmitTx(registry, keeper1, [upkeepId], { + performGas: 10, // too little gas + }) + + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const success = upkeepPerformedLog.args.success + assert.equal(success, false) + }) + + it('reverts if not enough gas supplied', async () => { + await evmRevert( + getTransmitTx(registry, keeper1, [upkeepId], { + gasLimit: performGas, + }), + ) + }) + + it('executes the data passed to the registry', async () => { + await mock.setCanPerform(true) + + const tx = await getTransmitTx(registry, keeper1, [upkeepId], { + performData: randomBytes, + }) + const receipt = await tx.wait() + + const upkeepPerformedWithABI = [ + 'event UpkeepPerformedWith(bytes upkeepData)', + ] + const iface = new ethers.utils.Interface(upkeepPerformedWithABI) + const parsedLogs = [] + for (let i = 0; i < receipt.logs.length; i++) { + const log = receipt.logs[i] + try { + parsedLogs.push(iface.parseLog(log)) + } catch (e) { + // ignore log + } + } + assert.equal(parsedLogs.length, 1) + assert.equal(parsedLogs[0].args.upkeepData, randomBytes) + }) + + it('uses actual execution price for payment and premium calculation', async () => { + // Actual multiplier is 2, but we set gasPrice to be 1x gasWei + const gasPrice = gasWei.mul(BigNumber.from('1')) + await mock.setCanPerform(true) + const registryPremiumBefore = (await registry.getState()).state + .totalPremium + const tx = await getTransmitTx(registry, keeper1, [upkeepId], { + gasPrice, + }) + const receipt = await tx.wait() + const registryPremiumAfter = (await registry.getState()).state + .totalPremium + const premium = registryPremiumAfter.sub(registryPremiumBefore) + + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const gasUsed = upkeepPerformedLog.args.gasUsed + const gasOverhead = upkeepPerformedLog.args.gasOverhead + const totalPayment = upkeepPerformedLog.args.totalPayment + + assert.equal( + linkForGas( + gasUsed, + gasOverhead, + BigNumber.from('1'), // Not the config multiplier, but the actual gas used + paymentPremiumPPB, + flatFeeMicroLink, + ).total.toString(), + totalPayment.toString(), + ) + + assert.equal( + linkForGas( + gasUsed, + gasOverhead, + BigNumber.from('1'), // Not the config multiplier, but the actual gas used + paymentPremiumPPB, + flatFeeMicroLink, + ).premium.toString(), + premium.toString(), + ) + }) + + it('only pays at a rate up to the gas ceiling [ @skip-coverage ]', async () => { + // Actual multiplier is 2, but we set gasPrice to be 10x + const gasPrice = gasWei.mul(BigNumber.from('10')) + await mock.setCanPerform(true) + + const tx = await getTransmitTx(registry, keeper1, [upkeepId], { + gasPrice, + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const gasUsed = upkeepPerformedLog.args.gasUsed + const gasOverhead = upkeepPerformedLog.args.gasOverhead + const totalPayment = upkeepPerformedLog.args.totalPayment + + assert.equal( + linkForGas( + gasUsed, + gasOverhead, + gasCeilingMultiplier, // Should be same with exisitng multiplier + paymentPremiumPPB, + flatFeeMicroLink, + ).total.toString(), + totalPayment.toString(), + ) + }) + + it('correctly accounts for l payment', async () => { + await mock.setCanPerform(true) + // Same as MockArbGasInfo.sol + const l1CostWeiArb = BigNumber.from(1000000) + + let tx = await arbRegistry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const testUpkeepId = await getUpkeepID(tx) + await arbRegistry.connect(owner).addFunds(testUpkeepId, toWei('100')) + + // Do the thing + tx = await getTransmitTx( + arbRegistry, + keeper1, + [testUpkeepId], + + { gasPrice: gasWei.mul('5') }, // High gas price so that it gets capped + ) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const gasUsed = upkeepPerformedLog.args.gasUsed + const gasOverhead = upkeepPerformedLog.args.gasOverhead + const totalPayment = upkeepPerformedLog.args.totalPayment + + assert.equal( + linkForGas( + gasUsed, + gasOverhead, + gasCeilingMultiplier, + paymentPremiumPPB, + flatFeeMicroLink, + l1CostWeiArb.div(gasCeilingMultiplier), // Dividing by gasCeilingMultiplier as it gets multiplied later + ).total.toString(), + totalPayment.toString(), + ) + }) + + itMaybe('can self fund', async () => { + const maxPayment = await registry.getMaxPaymentForGas( + Trigger.CONDITION, + performGas, + ) + + // First set auto funding amount to 0 and verify that balance is deducted upon performUpkeep + let initialBalance = toWei('100') + await registry.connect(owner).addFunds(afUpkeepId, initialBalance) + await autoFunderUpkeep.setAutoFundLink(0) + await autoFunderUpkeep.setIsEligible(true) + await getTransmitTx(registry, keeper1, [afUpkeepId]) + + let postUpkeepBalance = (await registry.getUpkeep(afUpkeepId)).balance + assert.isTrue(postUpkeepBalance.lt(initialBalance)) // Balance should be deducted + assert.isTrue(postUpkeepBalance.gte(initialBalance.sub(maxPayment))) // Balance should not be deducted more than maxPayment + + // Now set auto funding amount to 100 wei and verify that the balance increases + initialBalance = postUpkeepBalance + const autoTopupAmount = toWei('100') + await autoFunderUpkeep.setAutoFundLink(autoTopupAmount) + await autoFunderUpkeep.setIsEligible(true) + await getTransmitTx(registry, keeper1, [afUpkeepId]) + + postUpkeepBalance = (await registry.getUpkeep(afUpkeepId)).balance + // Balance should increase by autoTopupAmount and decrease by max maxPayment + assert.isTrue( + postUpkeepBalance.gte( + initialBalance.add(autoTopupAmount).sub(maxPayment), + ), + ) + }) + + it('can self cancel', async () => { + await registry.connect(owner).addFunds(afUpkeepId, toWei('100')) + + await autoFunderUpkeep.setIsEligible(true) + await autoFunderUpkeep.setShouldCancel(true) + + let registration = await registry.getUpkeep(afUpkeepId) + const oldExpiration = registration.maxValidBlocknumber + + // Do the thing + await getTransmitTx(registry, keeper1, [afUpkeepId]) + + // Verify upkeep gets cancelled + registration = await registry.getUpkeep(afUpkeepId) + const newExpiration = registration.maxValidBlocknumber + assert.isTrue(newExpiration.lt(oldExpiration)) + }) + + it('reverts when configDigest mismatches', async () => { + const report = await makeLatestBlockReport([upkeepId]) + const reportContext = [emptyBytes32, epochAndRound5_1, emptyBytes32] // wrong config digest + const sigs = signReport(reportContext, report, signers.slice(0, f + 1)) + await evmRevert( + registry + .connect(keeper1) + .transmit( + [reportContext[0], reportContext[1], reportContext[2]], + report, + sigs.rs, + sigs.ss, + sigs.vs, + ), + 'ConfigDigestMismatch()', + ) + }) + + it('reverts with incorrect number of signatures', async () => { + const configDigest = (await registry.getState()).state + .latestConfigDigest + const report = await makeLatestBlockReport([upkeepId]) + const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest + const sigs = signReport(reportContext, report, signers.slice(0, f + 2)) + await evmRevert( + registry + .connect(keeper1) + .transmit( + [reportContext[0], reportContext[1], reportContext[2]], + report, + sigs.rs, + sigs.ss, + sigs.vs, + ), + 'IncorrectNumberOfSignatures()', + ) + }) + + it('reverts with invalid signature for inactive signers', async () => { + const configDigest = (await registry.getState()).state + .latestConfigDigest + const report = await makeLatestBlockReport([upkeepId]) + const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest + const sigs = signReport(reportContext, report, [ + new ethers.Wallet(ethers.Wallet.createRandom()), + new ethers.Wallet(ethers.Wallet.createRandom()), + ]) + await evmRevert( + registry + .connect(keeper1) + .transmit( + [reportContext[0], reportContext[1], reportContext[2]], + report, + sigs.rs, + sigs.ss, + sigs.vs, + ), + 'OnlyActiveSigners()', + ) + }) + + it('reverts with invalid signature for duplicated signers', async () => { + const configDigest = (await registry.getState()).state + .latestConfigDigest + const report = await makeLatestBlockReport([upkeepId]) + const reportContext = [configDigest, epochAndRound5_1, emptyBytes32] // wrong config digest + const sigs = signReport(reportContext, report, [signer1, signer1]) + await evmRevert( + registry + .connect(keeper1) + .transmit( + [reportContext[0], reportContext[1], reportContext[2]], + report, + sigs.rs, + sigs.ss, + sigs.vs, + ), + 'DuplicateSigners()', + ) + }) + + itMaybe( + 'has a large enough gas overhead to cover upkeep that use all its gas [ @skip-coverage ]', + async () => { + await registry.connect(owner).setConfigTypeSafe( + signerAddresses, + keeperAddresses, + 10, // maximise f to maximise overhead + config, + offchainVersion, + offchainBytes, + ) + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + maxPerformGas, // max allowed gas + await admin.getAddress(), + randomBytes, + '0x', + ) + const testUpkeepId = await getUpkeepID(tx) + await registry.connect(admin).addFunds(testUpkeepId, toWei('100')) + + let performData = '0x' + for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { + performData += '11' + } // max allowed performData + + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(maxPerformGas) + + await getTransmitTx(registry, keeper1, [testUpkeepId], { + gasLimit: maxPerformGas.add(transmitGasOverhead), + numSigners: 11, + performData, + }) // Should not revert + }, + ) + + itMaybe( + 'performs upkeep, deducts payment, updates lastPerformed and emits events', + async () => { + await mock.setCanPerform(true) + + for (const i in fArray) { + const newF = fArray[i] + await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + newF, + config, + offchainVersion, + offchainBytes, + ) + const checkBlock = await ethers.provider.getBlock('latest') + + const keeperBefore = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const registrationBefore = await registry.getUpkeep(upkeepId) + const registryPremiumBefore = (await registry.getState()).state + .totalPremium + const keeperLinkBefore = await linkToken.balanceOf( + await keeper1.getAddress(), + ) + const registryLinkBefore = await linkToken.balanceOf( + registry.address, + ) + + // Do the thing + const tx = await getTransmitTx(registry, keeper1, [upkeepId], { + checkBlockNum: checkBlock.number, + checkBlockHash: checkBlock.hash, + numSigners: newF + 1, + }) + + const receipt = await tx.wait() + + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const id = upkeepPerformedLog.args.id + const success = upkeepPerformedLog.args.success + const trigger = upkeepPerformedLog.args.trigger + const gasUsed = upkeepPerformedLog.args.gasUsed + const gasOverhead = upkeepPerformedLog.args.gasOverhead + const totalPayment = upkeepPerformedLog.args.totalPayment + assert.equal(id.toString(), upkeepId.toString()) + assert.equal(success, true) + assert.equal( + trigger, + encodeBlockTrigger({ + blockNum: checkBlock.number, + blockHash: checkBlock.hash, + }), + ) + assert.isTrue(gasUsed.gt(BigNumber.from('0'))) + assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) + assert.isTrue(totalPayment.gt(BigNumber.from('0'))) + + const keeperAfter = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const registrationAfter = await registry.getUpkeep(upkeepId) + const keeperLinkAfter = await linkToken.balanceOf( + await keeper1.getAddress(), + ) + const registryLinkAfter = await linkToken.balanceOf( + registry.address, + ) + const registryPremiumAfter = (await registry.getState()).state + .totalPremium + const premium = registryPremiumAfter.sub(registryPremiumBefore) + // Keeper payment is gasPayment + premium / num keepers + const keeperPayment = totalPayment + .sub(premium) + .add(premium.div(BigNumber.from(keeperAddresses.length))) + + assert.equal( + keeperAfter.balance.sub(keeperPayment).toString(), + keeperBefore.balance.toString(), + ) + assert.equal( + registrationBefore.balance.sub(totalPayment).toString(), + registrationAfter.balance.toString(), + ) + assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) + assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) + + // Amount spent should be updated correctly + assert.equal( + registrationAfter.amountSpent.sub(totalPayment).toString(), + registrationBefore.amountSpent.toString(), + ) + assert.isTrue( + registrationAfter.amountSpent + .sub(registrationBefore.amountSpent) + .eq(registrationBefore.balance.sub(registrationAfter.balance)), + ) + // Last perform block number should be updated + assert.equal( + registrationAfter.lastPerformedBlockNumber.toString(), + tx.blockNumber?.toString(), + ) + + // Latest epoch should be 5 + assert.equal((await registry.getState()).state.latestEpoch, 5) + } + }, + ) + + describeMaybe( + 'Gas benchmarking conditional upkeeps [ @skip-coverage ]', + function () { + const fs = [1, 10] + fs.forEach(function (newF) { + it( + 'When f=' + + newF + + ' calculates gas overhead appropriately within a margin for different scenarios', + async () => { + // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement + let tx = await getTransmitTx(registry, keeper1, [upkeepId]) + await tx.wait() + + // Different test scenarios + let longBytes = '0x' + for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { + longBytes += '11' + } + const upkeepSuccessArray = [true, false] + const performGasArray = [5000, performGas] + const performDataArray = ['0x', longBytes] + + for (const i in upkeepSuccessArray) { + for (const j in performGasArray) { + for (const k in performDataArray) { + const upkeepSuccess = upkeepSuccessArray[i] + const performGas = performGasArray[j] + const performData = performDataArray[k] + + await mock.setCanPerform(upkeepSuccess) + await mock.setPerformGasToBurn(performGas) + await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + newF, + config, + offchainVersion, + offchainBytes, + ) + tx = await getTransmitTx(registry, keeper1, [upkeepId], { + numSigners: newF + 1, + performData, + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = + parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const upkeepGasUsed = upkeepPerformedLog.args.gasUsed + const chargedGasOverhead = + upkeepPerformedLog.args.gasOverhead + const actualGasOverhead = + receipt.gasUsed.sub(upkeepGasUsed) + + assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) + assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) + + console.log( + 'Gas Benchmarking conditional upkeeps:', + 'upkeepSuccess=', + upkeepSuccess, + 'performGas=', + performGas.toString(), + 'performData length=', + performData.length / 2 - 1, + 'sig verification ( f =', + newF, + '): calculated overhead: ', + chargedGasOverhead.toString(), + ' actual overhead: ', + actualGasOverhead.toString(), + ' margin over gasUsed: ', + chargedGasOverhead.sub(actualGasOverhead).toString(), + ) + + // Overhead should not get capped + const gasOverheadCap = registryConditionalOverhead + .add( + registryPerSignerGasOverhead.mul( + BigNumber.from(newF + 1), + ), + ) + .add( + BigNumber.from( + registryPerPerformByteGasOverhead.toNumber() * + performData.length, + ), + ) + const gasCapMinusOverhead = + gasOverheadCap.sub(chargedGasOverhead) + assert.isTrue( + gasCapMinusOverhead.gt(BigNumber.from(0)), + 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD by atleast ' + + gasCapMinusOverhead.toString(), + ) + // total gas charged should be greater than tx gas but within gasCalculationMargin + assert.isTrue( + chargedGasOverhead.gt(actualGasOverhead), + 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + + actualGasOverhead.sub(chargedGasOverhead).toString(), + ) + + assert.isTrue( + chargedGasOverhead + .sub(actualGasOverhead) + .lt(gasCalculationMargin), + ), + 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + + chargedGasOverhead + .sub(chargedGasOverhead) + .sub(gasCalculationMargin) + .toString() + } + } + } + }, + ) + }) + }, + ) + + describeMaybe( + 'Gas benchmarking log upkeeps [ @skip-coverage ]', + function () { + const fs = [1, 10] + fs.forEach(function (newF) { + it( + 'When f=' + + newF + + ' calculates gas overhead appropriately within a margin', + async () => { + // Perform the upkeep once to remove non-zero storage slots and have predictable gas measurement + let tx = await getTransmitTx(registry, keeper1, [logUpkeepId]) + await tx.wait() + const performData = '0x' + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(performGas) + await registry.setConfigTypeSafe( + signerAddresses, + keeperAddresses, + newF, + config, + offchainVersion, + offchainBytes, + ) + tx = await getTransmitTx(registry, keeper1, [logUpkeepId], { + numSigners: newF + 1, + performData, + }) + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly 1 Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, 1) + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const upkeepGasUsed = upkeepPerformedLog.args.gasUsed + const chargedGasOverhead = upkeepPerformedLog.args.gasOverhead + const actualGasOverhead = receipt.gasUsed.sub(upkeepGasUsed) + + assert.isTrue(upkeepGasUsed.gt(BigNumber.from('0'))) + assert.isTrue(chargedGasOverhead.gt(BigNumber.from('0'))) + + console.log( + 'Gas Benchmarking log upkeeps:', + 'upkeepSuccess=', + true, + 'performGas=', + performGas.toString(), + 'performData length=', + performData.length / 2 - 1, + 'sig verification ( f =', + newF, + '): calculated overhead: ', + chargedGasOverhead.toString(), + ' actual overhead: ', + actualGasOverhead.toString(), + ' margin over gasUsed: ', + chargedGasOverhead.sub(actualGasOverhead).toString(), + ) + + // Overhead should not get capped + const gasOverheadCap = registryLogOverhead + .add( + registryPerSignerGasOverhead.mul(BigNumber.from(newF + 1)), + ) + .add( + BigNumber.from( + registryPerPerformByteGasOverhead.toNumber() * + performData.length, + ), + ) + const gasCapMinusOverhead = + gasOverheadCap.sub(chargedGasOverhead) + assert.isTrue( + gasCapMinusOverhead.gt(BigNumber.from(0)), + 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD by atleast ' + + gasCapMinusOverhead.toString(), + ) + // total gas charged should be greater than tx gas but within gasCalculationMargin + assert.isTrue( + chargedGasOverhead.gt(actualGasOverhead), + 'Gas overhead calculated is too low, increase account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + + actualGasOverhead.sub(chargedGasOverhead).toString(), + ) + + assert.isTrue( + chargedGasOverhead + .sub(actualGasOverhead) + .lt(gasCalculationMargin), + ), + 'Gas overhead calculated is too high, decrease account gas variables (ACCOUNTING_FIXED_GAS_OVERHEAD/ACCOUNTING_PER_SIGNER_GAS_OVERHEAD) by atleast ' + + chargedGasOverhead + .sub(chargedGasOverhead) + .sub(gasCalculationMargin) + .toString() + }, + ) + }) + }, + ) + }) + }) + + describeMaybe( + '#transmit with upkeep batches [ @skip-coverage ]', + function () { + const numPassingConditionalUpkeepsArray = [0, 1, 5] + const numPassingLogUpkeepsArray = [0, 1, 5] + const numFailingUpkeepsArray = [0, 3] + + for (let idx = 0; idx < numPassingConditionalUpkeepsArray.length; idx++) { + for (let jdx = 0; jdx < numPassingLogUpkeepsArray.length; jdx++) { + for (let kdx = 0; kdx < numFailingUpkeepsArray.length; kdx++) { + const numPassingConditionalUpkeeps = + numPassingConditionalUpkeepsArray[idx] + const numPassingLogUpkeeps = numPassingLogUpkeepsArray[jdx] + const numFailingUpkeeps = numFailingUpkeepsArray[kdx] + if ( + numPassingConditionalUpkeeps == 0 && + numPassingLogUpkeeps == 0 + ) { + continue + } + it( + '[Conditional:' + + numPassingConditionalUpkeeps + + ',Log:' + + numPassingLogUpkeeps + + ',Failures:' + + numFailingUpkeeps + + '] performs successful upkeeps and does not charge failing upkeeps', + async () => { + const allUpkeeps = await getMultipleUpkeepsDeployedAndFunded( + numPassingConditionalUpkeeps, + numPassingLogUpkeeps, + numFailingUpkeeps, + ) + const passingConditionalUpkeepIds = + allUpkeeps.passingConditionalUpkeepIds + const passingLogUpkeepIds = allUpkeeps.passingLogUpkeepIds + const failingUpkeepIds = allUpkeeps.failingUpkeepIds + + const keeperBefore = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const keeperLinkBefore = await linkToken.balanceOf( + await keeper1.getAddress(), + ) + const registryLinkBefore = await linkToken.balanceOf( + registry.address, + ) + const registryPremiumBefore = (await registry.getState()).state + .totalPremium + const registrationConditionalPassingBefore = await Promise.all( + passingConditionalUpkeepIds.map(async (id) => { + const reg = await registry.getUpkeep(BigNumber.from(id)) + assert.equal(reg.lastPerformedBlockNumber.toString(), '0') + return reg + }), + ) + const registrationLogPassingBefore = await Promise.all( + passingLogUpkeepIds.map(async (id) => { + const reg = await registry.getUpkeep(BigNumber.from(id)) + assert.equal(reg.lastPerformedBlockNumber.toString(), '0') + return reg + }), + ) + const registrationFailingBefore = await Promise.all( + failingUpkeepIds.map(async (id) => { + const reg = await registry.getUpkeep(BigNumber.from(id)) + assert.equal(reg.lastPerformedBlockNumber.toString(), '0') + return reg + }), + ) + + const tx = await getTransmitTx( + registry, + keeper1, + passingConditionalUpkeepIds.concat( + passingLogUpkeepIds.concat(failingUpkeepIds), + ), + ) + + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly numPassingUpkeeps Upkeep Performed should be emitted + assert.equal( + upkeepPerformedLogs.length, + numPassingConditionalUpkeeps + numPassingLogUpkeeps, + ) + const insufficientFundsLogs = + parseInsufficientFundsUpkeepReportLogs(receipt) + // exactly numFailingUpkeeps Upkeep Performed should be emitted + assert.equal(insufficientFundsLogs.length, numFailingUpkeeps) + + const keeperAfter = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const keeperLinkAfter = await linkToken.balanceOf( + await keeper1.getAddress(), + ) + const registryLinkAfter = await linkToken.balanceOf( + registry.address, + ) + const registrationConditionalPassingAfter = await Promise.all( + passingConditionalUpkeepIds.map(async (id) => { + return await registry.getUpkeep(BigNumber.from(id)) + }), + ) + const registrationLogPassingAfter = await Promise.all( + passingLogUpkeepIds.map(async (id) => { + return await registry.getUpkeep(BigNumber.from(id)) + }), + ) + const registrationFailingAfter = await Promise.all( + failingUpkeepIds.map(async (id) => { + return await registry.getUpkeep(BigNumber.from(id)) + }), + ) + const registryPremiumAfter = (await registry.getState()).state + .totalPremium + const premium = registryPremiumAfter.sub(registryPremiumBefore) + + let netPayment = BigNumber.from('0') + for (let i = 0; i < numPassingConditionalUpkeeps; i++) { + const id = upkeepPerformedLogs[i].args.id + const gasUsed = upkeepPerformedLogs[i].args.gasUsed + const gasOverhead = upkeepPerformedLogs[i].args.gasOverhead + const totalPayment = upkeepPerformedLogs[i].args.totalPayment + + expect(id).to.equal(passingConditionalUpkeepIds[i]) + assert.isTrue(gasUsed.gt(BigNumber.from('0'))) + assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) + assert.isTrue(totalPayment.gt(BigNumber.from('0'))) + + // Balance should be deducted + assert.equal( + registrationConditionalPassingBefore[i].balance + .sub(totalPayment) + .toString(), + registrationConditionalPassingAfter[i].balance.toString(), + ) + + // Amount spent should be updated correctly + assert.equal( + registrationConditionalPassingAfter[i].amountSpent + .sub(totalPayment) + .toString(), + registrationConditionalPassingBefore[ + i + ].amountSpent.toString(), + ) + + // Last perform block number should be updated + assert.equal( + registrationConditionalPassingAfter[ + i + ].lastPerformedBlockNumber.toString(), + tx.blockNumber?.toString(), + ) + + netPayment = netPayment.add(totalPayment) + } + + for (let i = 0; i < numPassingLogUpkeeps; i++) { + const id = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .id + const gasUsed = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .gasUsed + const gasOverhead = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .gasOverhead + const totalPayment = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .totalPayment + + expect(id).to.equal(passingLogUpkeepIds[i]) + assert.isTrue(gasUsed.gt(BigNumber.from('0'))) + assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) + assert.isTrue(totalPayment.gt(BigNumber.from('0'))) + + // Balance should be deducted + assert.equal( + registrationLogPassingBefore[i].balance + .sub(totalPayment) + .toString(), + registrationLogPassingAfter[i].balance.toString(), + ) + + // Amount spent should be updated correctly + assert.equal( + registrationLogPassingAfter[i].amountSpent + .sub(totalPayment) + .toString(), + registrationLogPassingBefore[i].amountSpent.toString(), + ) + + // Last perform block number should not be updated for log triggers + assert.equal( + registrationLogPassingAfter[ + i + ].lastPerformedBlockNumber.toString(), + '0', + ) + + netPayment = netPayment.add(totalPayment) + } + + for (let i = 0; i < numFailingUpkeeps; i++) { + // InsufficientFunds log should be emitted + const id = insufficientFundsLogs[i].args.id + expect(id).to.equal(failingUpkeepIds[i]) + + // Balance and amount spent should be same + assert.equal( + registrationFailingBefore[i].balance.toString(), + registrationFailingAfter[i].balance.toString(), + ) + assert.equal( + registrationFailingBefore[i].amountSpent.toString(), + registrationFailingAfter[i].amountSpent.toString(), + ) + + // Last perform block number should not be updated + assert.equal( + registrationFailingAfter[ + i + ].lastPerformedBlockNumber.toString(), + '0', + ) + } + + // Keeper payment is gasPayment + premium / num keepers + const keeperPayment = netPayment + .sub(premium) + .add(premium.div(BigNumber.from(keeperAddresses.length))) + + // Keeper should be paid net payment for all passed upkeeps + assert.equal( + keeperAfter.balance.sub(keeperPayment).toString(), + keeperBefore.balance.toString(), + ) + + assert.isTrue(keeperLinkAfter.eq(keeperLinkBefore)) + assert.isTrue(registryLinkBefore.eq(registryLinkAfter)) + }, + ) + + it( + '[Conditional:' + + numPassingConditionalUpkeeps + + ',Log' + + numPassingLogUpkeeps + + ',Failures:' + + numFailingUpkeeps + + '] splits gas overhead appropriately among performed upkeeps [ @skip-coverage ]', + async () => { + const allUpkeeps = await getMultipleUpkeepsDeployedAndFunded( + numPassingConditionalUpkeeps, + numPassingLogUpkeeps, + numFailingUpkeeps, + ) + const passingConditionalUpkeepIds = + allUpkeeps.passingConditionalUpkeepIds + const passingLogUpkeepIds = allUpkeeps.passingLogUpkeepIds + const failingUpkeepIds = allUpkeeps.failingUpkeepIds + + // Perform the upkeeps once to remove non-zero storage slots and have predictable gas measurement + let tx = await getTransmitTx( + registry, + keeper1, + passingConditionalUpkeepIds.concat( + passingLogUpkeepIds.concat(failingUpkeepIds), + ), + ) + + await tx.wait() + + // Do the actual thing + + tx = await getTransmitTx( + registry, + keeper1, + passingConditionalUpkeepIds.concat( + passingLogUpkeepIds.concat(failingUpkeepIds), + ), + ) + + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly numPassingUpkeeps Upkeep Performed should be emitted + assert.equal( + upkeepPerformedLogs.length, + numPassingConditionalUpkeeps + numPassingLogUpkeeps, + ) + + const gasConditionalOverheadCap = + registryConditionalOverhead.add( + registryPerSignerGasOverhead.mul(BigNumber.from(f + 1)), + ) + const gasLogOverheadCap = registryLogOverhead.add( + registryPerSignerGasOverhead.mul(BigNumber.from(f + 1)), + ) + + const overheadCanGetCapped = + numFailingUpkeeps > 0 && + numPassingConditionalUpkeeps <= 1 && + numPassingLogUpkeeps <= 1 + // Can happen if there are failing upkeeps and only 1 successful upkeep of each type + let netGasUsedPlusOverhead = BigNumber.from('0') + + for (let i = 0; i < numPassingConditionalUpkeeps; i++) { + const gasUsed = upkeepPerformedLogs[i].args.gasUsed + const gasOverhead = upkeepPerformedLogs[i].args.gasOverhead + + assert.isTrue(gasUsed.gt(BigNumber.from('0'))) + assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) + + // Overhead should not exceed capped + assert.isTrue(gasOverhead.lte(gasConditionalOverheadCap)) + + // Overhead should be same for every upkeep since they have equal performData, hence same caps + assert.isTrue( + gasOverhead.eq(upkeepPerformedLogs[0].args.gasOverhead), + ) + + netGasUsedPlusOverhead = netGasUsedPlusOverhead + .add(gasUsed) + .add(gasOverhead) + } + for (let i = 0; i < numPassingLogUpkeeps; i++) { + const gasUsed = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .gasUsed + const gasOverhead = + upkeepPerformedLogs[numPassingConditionalUpkeeps + i].args + .gasOverhead + + assert.isTrue(gasUsed.gt(BigNumber.from('0'))) + assert.isTrue(gasOverhead.gt(BigNumber.from('0'))) + + // Overhead should not exceed capped + assert.isTrue(gasOverhead.lte(gasLogOverheadCap)) + + // Overhead should be same for every upkeep since they have equal performData, hence same caps + assert.isTrue( + gasOverhead.eq( + upkeepPerformedLogs[numPassingConditionalUpkeeps].args + .gasOverhead, + ), + ) + + netGasUsedPlusOverhead = netGasUsedPlusOverhead + .add(gasUsed) + .add(gasOverhead) + } + + const overheadsGotCapped = + (numPassingConditionalUpkeeps > 0 && + upkeepPerformedLogs[0].args.gasOverhead.eq( + gasConditionalOverheadCap, + )) || + (numPassingLogUpkeeps > 0 && + upkeepPerformedLogs[ + numPassingConditionalUpkeeps + ].args.gasOverhead.eq(gasLogOverheadCap)) + // Should only get capped in certain scenarios + if (overheadsGotCapped) { + assert.isTrue( + overheadCanGetCapped, + 'Gas overhead got capped. Verify gas overhead variables in test match those in the registry. To not have the overheads capped increase REGISTRY_GAS_OVERHEAD', + ) + } + + console.log( + 'Gas Benchmarking - batching (passedConditionalUpkeeps: ', + numPassingConditionalUpkeeps, + 'passedLogUpkeeps:', + numPassingLogUpkeeps, + 'failedUpkeeps:', + numFailingUpkeeps, + '): ', + 'overheadsGotCapped', + overheadsGotCapped, + numPassingConditionalUpkeeps > 0 + ? 'calculated conditional overhead' + : '', + numPassingConditionalUpkeeps > 0 + ? upkeepPerformedLogs[0].args.gasOverhead.toString() + : '', + numPassingLogUpkeeps > 0 ? 'calculated log overhead' : '', + numPassingLogUpkeeps > 0 + ? upkeepPerformedLogs[ + numPassingConditionalUpkeeps + ].args.gasOverhead.toString() + : '', + ' margin over gasUsed', + netGasUsedPlusOverhead.sub(receipt.gasUsed).toString(), + ) + + // If overheads dont get capped then total gas charged should be greater than tx gas + // We don't check whether the net is within gasMargin as the margin changes with numFailedUpkeeps + // Which is ok, as long as individual gas overhead is capped + if (!overheadsGotCapped) { + assert.isTrue( + netGasUsedPlusOverhead.gt(receipt.gasUsed), + 'Gas overhead is too low, increase ACCOUNTING_PER_UPKEEP_GAS_OVERHEAD', + ) + } + }, + ) + } + } + } + + it('has enough perform gas overhead for large batches [ @skip-coverage ]', async () => { + const numUpkeeps = 20 + const upkeepIds: BigNumber[] = [] + let totalPerformGas = BigNumber.from('0') + for (let i = 0; i < numUpkeeps; i++) { + const mock = await upkeepMockFactory.deploy() + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const testUpkeepId = await getUpkeepID(tx) + upkeepIds.push(testUpkeepId) + + // Add funds to passing upkeeps + await registry.connect(owner).addFunds(testUpkeepId, toWei('10')) + + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(performGas) + + totalPerformGas = totalPerformGas.add(performGas) + } + + // Should revert with no overhead added + await evmRevert( + getTransmitTx(registry, keeper1, upkeepIds, { + gasLimit: totalPerformGas, + }), + ) + // Should not revert with overhead added + await getTransmitTx(registry, keeper1, upkeepIds, { + gasLimit: totalPerformGas.add(transmitGasOverhead), + }) + }) + + it('splits l2 payment among performed upkeeps', async () => { + const numUpkeeps = 7 + const upkeepIds: BigNumber[] = [] + // Same as MockArbGasInfo.sol + const l1CostWeiArb = BigNumber.from(1000000) + + for (let i = 0; i < numUpkeeps; i++) { + const mock = await upkeepMockFactory.deploy() + const tx = await arbRegistry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const testUpkeepId = await getUpkeepID(tx) + upkeepIds.push(testUpkeepId) + + // Add funds to passing upkeeps + await arbRegistry.connect(owner).addFunds(testUpkeepId, toWei('100')) + } + + // Do the thing + const tx = await getTransmitTx( + arbRegistry, + keeper1, + upkeepIds, + + { gasPrice: gasWei.mul('5') }, // High gas price so that it gets capped + ) + + const receipt = await tx.wait() + const upkeepPerformedLogs = parseUpkeepPerformedLogs(receipt) + // exactly numPassingUpkeeps Upkeep Performed should be emitted + assert.equal(upkeepPerformedLogs.length, numUpkeeps) + + // Verify the payment calculation in upkeepPerformed[0] + const upkeepPerformedLog = upkeepPerformedLogs[0] + + const gasUsed = upkeepPerformedLog.args.gasUsed + const gasOverhead = upkeepPerformedLog.args.gasOverhead + const totalPayment = upkeepPerformedLog.args.totalPayment + + assert.equal( + linkForGas( + gasUsed, + gasOverhead, + gasCeilingMultiplier, + paymentPremiumPPB, + flatFeeMicroLink, + l1CostWeiArb.div(gasCeilingMultiplier), // Dividing by gasCeilingMultiplier as it gets multiplied later + BigNumber.from(numUpkeeps), + ).total.toString(), + totalPayment.toString(), + ) + }) + }, + ) + + describe('#recoverFunds', () => { + const sent = toWei('7') + + beforeEach(async () => { + await linkToken.connect(admin).approve(registry.address, toWei('100')) + await linkToken + .connect(owner) + .transfer(await keeper1.getAddress(), toWei('1000')) + + // add funds to upkeep 1 and perform and withdraw some payment + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + emptyBytes, + emptyBytes, + ) + + const id1 = await getUpkeepID(tx) + await registry.connect(admin).addFunds(id1, toWei('5')) + + await getTransmitTx(registry, keeper1, [id1]) + await getTransmitTx(registry, keeper2, [id1]) + await getTransmitTx(registry, keeper3, [id1]) + + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + + // transfer funds directly to the registry + await linkToken.connect(keeper1).transfer(registry.address, sent) + + // add funds to upkeep 2 and perform and withdraw some payment + const tx2 = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + emptyBytes, + emptyBytes, + ) + const id2 = await getUpkeepID(tx2) + await registry.connect(admin).addFunds(id2, toWei('5')) + + await getTransmitTx(registry, keeper1, [id2]) + await getTransmitTx(registry, keeper2, [id2]) + await getTransmitTx(registry, keeper3, [id2]) + + await registry + .connect(payee2) + .withdrawPayment( + await keeper2.getAddress(), + await nonkeeper.getAddress(), + ) + + // transfer funds using onTokenTransfer + const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [id2]) + await linkToken + .connect(owner) + .transferAndCall(registry.address, toWei('1'), data) + + // withdraw some funds + await registry.connect(owner).cancelUpkeep(id1) + await registry + .connect(admin) + .withdrawFunds(id1, await nonkeeper.getAddress()) + }) + + it('reverts if not called by owner', async () => { + await evmRevert( + registry.connect(keeper1).recoverFunds(), + 'Only callable by owner', + ) + }) + + it('allows any funds that have been accidentally transfered to be moved', async () => { + const balanceBefore = await linkToken.balanceOf(registry.address) + const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) + + await registry.connect(owner).recoverFunds() + + const balanceAfter = await linkToken.balanceOf(registry.address) + const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) + + assert.isTrue(balanceBefore.eq(balanceAfter.add(sent))) + assert.isTrue(ownerAfter.eq(ownerBefore.add(sent))) + }) + }) + + describe('#getMinBalanceForUpkeep / #checkUpkeep / #transmit', () => { + it('calculates the minimum balance appropriately', async () => { + await mock.setCanCheck(true) + + const oneWei = BigNumber.from(1) + const minBalance = await registry.getMinBalanceForUpkeep(upkeepId) + const tooLow = minBalance.sub(oneWei) + + await registry.connect(admin).addFunds(upkeepId, tooLow) + let checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.INSUFFICIENT_BALANCE, + ) + + await registry.connect(admin).addFunds(upkeepId, oneWei) + checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + assert.equal(checkUpkeepResult.upkeepNeeded, true) + }) + + it('uses maxPerformData size in checkUpkeep but actual performDataSize in transmit', async () => { + const tx1 = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const upkeepID1 = await getUpkeepID(tx1) + const tx2 = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + const upkeepID2 = await getUpkeepID(tx2) + await mock.setCanCheck(true) + await mock.setCanPerform(true) + + // upkeep 1 is underfunded, 2 is fully funded + const minBalance1 = ( + await registry.getMinBalanceForUpkeep(upkeepID1) + ).sub(1) + const minBalance2 = await registry.getMinBalanceForUpkeep(upkeepID2) + await registry.connect(owner).addFunds(upkeepID1, minBalance1) + await registry.connect(owner).addFunds(upkeepID2, minBalance2) + + // upkeep 1 check should return false, 2 should return true + let checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepID1) + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.INSUFFICIENT_BALANCE, + ) + + checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepID2) + assert.equal(checkUpkeepResult.upkeepNeeded, true) + + // upkeep 1 perform should return with insufficient balance using max performData size + let maxPerformData = '0x' + for (let i = 0; i < maxPerformDataSize.toNumber(); i++) { + maxPerformData += '11' + } + + const tx = await getTransmitTx(registry, keeper1, [upkeepID1], { + gasPrice: gasWei.mul(gasCeilingMultiplier), + performData: maxPerformData, + }) + + const receipt = await tx.wait() + const insufficientFundsUpkeepReportLogs = + parseInsufficientFundsUpkeepReportLogs(receipt) + // exactly 1 InsufficientFundsUpkeepReportLogs log should be emitted + assert.equal(insufficientFundsUpkeepReportLogs.length, 1) + + // upkeep 1 perform should succeed with empty performData + await getTransmitTx(registry, keeper1, [upkeepID1], { + gasPrice: gasWei.mul(gasCeilingMultiplier), + }), + // upkeep 2 perform should succeed with max performData size + await getTransmitTx(registry, keeper1, [upkeepID2], { + gasPrice: gasWei.mul(gasCeilingMultiplier), + performData: maxPerformData, + }) + }) + }) + + describe('#withdrawFunds', () => { + let upkeepId2: BigNumber + + beforeEach(async () => { + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + randomBytes, + '0x', + ) + upkeepId2 = await getUpkeepID(tx) + + await registry.connect(admin).addFunds(upkeepId, toWei('100')) + await registry.connect(admin).addFunds(upkeepId2, toWei('100')) + + // Do a perform so that upkeep is charged some amount + await getTransmitTx(registry, keeper1, [upkeepId]) + await getTransmitTx(registry, keeper1, [upkeepId2]) + }) + + it('reverts if called on a non existing ID', async () => { + await evmRevert( + registry + .connect(admin) + .withdrawFunds(upkeepId.add(1), await payee1.getAddress()), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if called by anyone but the admin', async () => { + await evmRevert( + registry + .connect(owner) + .withdrawFunds(upkeepId, await payee1.getAddress()), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if called on an uncanceled upkeep', async () => { + await evmRevert( + registry + .connect(admin) + .withdrawFunds(upkeepId, await payee1.getAddress()), + 'UpkeepNotCanceled()', + ) + }) + + it('reverts if called with the 0 address', async () => { + await evmRevert( + registry.connect(admin).withdrawFunds(upkeepId, zeroAddress), + 'InvalidRecipient()', + ) + }) + + describe('after the registration is paused, then cancelled', () => { + it('allows the admin to withdraw', async () => { + const balance = await registry.getBalance(upkeepId) + const payee = await payee1.getAddress() + await registry.connect(admin).pauseUpkeep(upkeepId) + await registry.connect(owner).cancelUpkeep(upkeepId) + await expect(() => + registry.connect(admin).withdrawFunds(upkeepId, payee), + ).to.changeTokenBalance(linkToken, payee1, balance) + }) + }) + + describe('after the registration is cancelled', () => { + beforeEach(async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + await registry.connect(owner).cancelUpkeep(upkeepId2) + }) + + it('can be called successively on two upkeeps', async () => { + await registry + .connect(admin) + .withdrawFunds(upkeepId, await payee1.getAddress()) + await registry + .connect(admin) + .withdrawFunds(upkeepId2, await payee1.getAddress()) + }) + + it('moves the funds out and updates the balance and emits an event', async () => { + const payee1Before = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const registryBefore = await linkToken.balanceOf(registry.address) + + let registration = await registry.getUpkeep(upkeepId) + const previousBalance = registration.balance + + const tx = await registry + .connect(admin) + .withdrawFunds(upkeepId, await payee1.getAddress()) + await expect(tx) + .to.emit(registry, 'FundsWithdrawn') + .withArgs(upkeepId, previousBalance, await payee1.getAddress()) + + const payee1After = await linkToken.balanceOf(await payee1.getAddress()) + const registryAfter = await linkToken.balanceOf(registry.address) + + assert.isTrue(payee1Before.add(previousBalance).eq(payee1After)) + assert.isTrue(registryBefore.sub(previousBalance).eq(registryAfter)) + + registration = await registry.getUpkeep(upkeepId) + assert.equal(0, registration.balance.toNumber()) + }) + }) + }) + + describe('#simulatePerformUpkeep', () => { + it('reverts if called by non zero address', async () => { + await evmRevert( + registry + .connect(await owner.getAddress()) + .callStatic.simulatePerformUpkeep(upkeepId, '0x'), + 'OnlySimulatedBackend()', + ) + }) + + it('reverts when registry is paused', async () => { + await registry.connect(owner).pause() + await evmRevert( + registry + .connect(zeroAddress) + .callStatic.simulatePerformUpkeep(upkeepId, '0x'), + 'RegistryPaused()', + ) + }) + + it('returns false and gasUsed when perform fails', async () => { + await mock.setCanPerform(false) + + const simulatePerformResult = await registry + .connect(zeroAddress) + .callStatic.simulatePerformUpkeep(upkeepId, '0x') + + assert.equal(simulatePerformResult.success, false) + assert.isTrue(simulatePerformResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + + it('returns true, gasUsed, and performGas when perform succeeds', async () => { + await mock.setCanPerform(true) + + const simulatePerformResult = await registry + .connect(zeroAddress) + .callStatic.simulatePerformUpkeep(upkeepId, '0x') + + assert.equal(simulatePerformResult.success, true) + assert.isTrue(simulatePerformResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + + it('returns correct amount of gasUsed when perform succeeds', async () => { + await mock.setCanPerform(true) + await mock.setPerformGasToBurn(performGas) + + const simulatePerformResult = await registry + .connect(zeroAddress) + .callStatic.simulatePerformUpkeep(upkeepId, '0x') + + assert.equal(simulatePerformResult.success, true) + // Full execute gas should be used, with some performGasBuffer(1000) + assert.isTrue( + simulatePerformResult.gasUsed.gt( + performGas.sub(BigNumber.from('1000')), + ), + ) + }) + }) + + describe('#checkUpkeep', () => { + it('reverts if called by non zero address', async () => { + await evmRevert( + registry + .connect(await owner.getAddress()) + .callStatic['checkUpkeep(uint256)'](upkeepId), + 'OnlySimulatedBackend()', + ) + }) + + it('returns false and error code if the upkeep is cancelled by admin', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.UPKEEP_CANCELLED, + ) + expect(checkUpkeepResult.gasUsed).to.equal(0) + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if the upkeep is cancelled by owner', async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.UPKEEP_CANCELLED, + ) + expect(checkUpkeepResult.gasUsed).to.equal(0) + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if the registry is paused', async () => { + await registry.connect(owner).pause() + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.REGISTRY_PAUSED, + ) + expect(checkUpkeepResult.gasUsed).to.equal(0) + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if the upkeep is paused', async () => { + await registry.connect(admin).pauseUpkeep(upkeepId) + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.UPKEEP_PAUSED, + ) + expect(checkUpkeepResult.gasUsed).to.equal(0) + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if user is out of funds', async () => { + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.INSUFFICIENT_BALANCE, + ) + expect(checkUpkeepResult.gasUsed).to.equal(0) + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + context('when the registration is funded', () => { + beforeEach(async () => { + await linkToken.connect(admin).approve(registry.address, toWei('200')) + await registry.connect(admin).addFunds(upkeepId, toWei('100')) + await registry.connect(admin).addFunds(logUpkeepId, toWei('100')) + }) + + it('returns false, error code, and revert data if the target check reverts', async () => { + await mock.setShouldRevertCheck(true) + await mock.setCheckRevertReason( + 'custom revert error, clever way to insert offchain data', + ) + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + assert.equal(checkUpkeepResult.upkeepNeeded, false) + + const revertReasonBytes = `0x${checkUpkeepResult.performData.slice(10)}` // remove sighash + assert.equal( + ethers.utils.defaultAbiCoder.decode(['string'], revertReasonBytes)[0], + 'custom revert error, clever way to insert offchain data', + ) + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.TARGET_CHECK_REVERTED, + ) + assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + // Feed data should be returned here + assert.isTrue(checkUpkeepResult.fastGasWei.gt(BigNumber.from('0'))) + assert.isTrue(checkUpkeepResult.linkNative.gt(BigNumber.from('0'))) + }) + + it('returns false, error code, and no revert data if the target check revert data exceeds maxRevertDataSize', async () => { + await mock.setShouldRevertCheck(true) + let longRevertReason = '' + for (let i = 0; i <= maxRevertDataSize.toNumber(); i++) { + longRevertReason += 'x' + } + await mock.setCheckRevertReason(longRevertReason) + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + assert.equal(checkUpkeepResult.upkeepNeeded, false) + + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.REVERT_DATA_EXCEEDS_LIMIT, + ) + assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if the upkeep is not needed', async () => { + await mock.setCanCheck(false) + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.UPKEEP_NOT_NEEDED, + ) + assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns false and error code if the performData exceeds limit', async () => { + let longBytes = '0x' + for (let i = 0; i < 5000; i++) { + longBytes += '1' + } + await mock.setCanCheck(true) + await mock.setPerformData(longBytes) + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId) + + assert.equal(checkUpkeepResult.upkeepNeeded, false) + assert.equal(checkUpkeepResult.performData, '0x') + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, + ) + assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + }) + + it('returns true with gas used if the target can execute', async () => { + await mock.setCanCheck(true) + await mock.setPerformData(randomBytes) + + const latestBlock = await ethers.provider.getBlock('latest') + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId, { + blockTag: latestBlock.number, + }) + + assert.equal(checkUpkeepResult.upkeepNeeded, true) + assert.equal(checkUpkeepResult.performData, randomBytes) + assert.equal( + checkUpkeepResult.upkeepFailureReason, + UpkeepFailureReason.NONE, + ) + assert.isTrue(checkUpkeepResult.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + expect(checkUpkeepResult.gasLimit).to.equal(performGas) + assert.isTrue(checkUpkeepResult.fastGasWei.eq(gasWei)) + assert.isTrue(checkUpkeepResult.linkNative.eq(linkEth)) + }) + + it('calls checkLog for log-trigger upkeeps', async () => { + const log: Log = { + index: 0, + timestamp: 0, + txHash: ethers.utils.randomBytes(32), + blockNumber: 100, + blockHash: ethers.utils.randomBytes(32), + source: randomAddress(), + topics: [ethers.utils.randomBytes(32), ethers.utils.randomBytes(32)], + data: ethers.utils.randomBytes(1000), + } + + await ltUpkeep.mock.checkLog.withArgs(log, '0x').returns(true, '0x1234') + + const checkData = encodeLog(log) + + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256,bytes)'](logUpkeepId, checkData) + + expect(checkUpkeepResult.upkeepNeeded).to.be.true + expect(checkUpkeepResult.performData).to.equal('0x1234') + }) + + itMaybe( + 'has a large enough gas overhead to cover upkeeps that use all their gas [ @skip-coverage ]', + async () => { + await mock.setCanCheck(true) + await mock.setCheckGasToBurn(checkGasLimit) + const gas = checkGasLimit.add(checkGasOverhead) + const checkUpkeepResult = await registry + .connect(zeroAddress) + .callStatic['checkUpkeep(uint256)'](upkeepId, { + gasLimit: gas, + }) + + assert.equal(checkUpkeepResult.upkeepNeeded, true) + }, + ) + }) + }) + + describe('#addFunds', () => { + const amount = toWei('1') + + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry.connect(keeper1).addFunds(upkeepId.add(1), amount), + 'UpkeepCancelled()', + ) + }) + + it('adds to the balance of the registration', async () => { + await registry.connect(admin).addFunds(upkeepId, amount) + const registration = await registry.getUpkeep(upkeepId) + assert.isTrue(amount.eq(registration.balance)) + }) + + it('lets anyone add funds to an upkeep not just admin', async () => { + await linkToken.connect(owner).transfer(await payee1.getAddress(), amount) + await linkToken.connect(payee1).approve(registry.address, amount) + + await registry.connect(payee1).addFunds(upkeepId, amount) + const registration = await registry.getUpkeep(upkeepId) + assert.isTrue(amount.eq(registration.balance)) + }) + + it('emits a log', async () => { + const tx = await registry.connect(admin).addFunds(upkeepId, amount) + await expect(tx) + .to.emit(registry, 'FundsAdded') + .withArgs(upkeepId, await admin.getAddress(), amount) + }) + + it('reverts if the upkeep is canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(keeper1).addFunds(upkeepId, amount), + 'UpkeepCancelled()', + ) + }) + }) + + describe('#getActiveUpkeepIDs', () => { + it('reverts if startIndex is out of bounds ', async () => { + await evmRevert( + registry.getActiveUpkeepIDs(numUpkeeps, 0), + 'IndexOutOfRange()', + ) + await evmRevert( + registry.getActiveUpkeepIDs(numUpkeeps + 1, 0), + 'IndexOutOfRange()', + ) + }) + + it('returns upkeep IDs bounded by maxCount', async () => { + let upkeepIds = await registry.getActiveUpkeepIDs(0, 1) + assert(upkeepIds.length == 1) + assert(upkeepIds[0].eq(upkeepId)) + upkeepIds = await registry.getActiveUpkeepIDs(1, 3) + assert(upkeepIds.length == 3) + expect(upkeepIds).to.deep.equal([ + afUpkeepId, + logUpkeepId, + streamsLookupUpkeepId, + ]) + }) + + it('returns as many ids as possible if maxCount > num available', async () => { + const upkeepIds = await registry.getActiveUpkeepIDs(1, numUpkeeps + 100) + assert(upkeepIds.length == numUpkeeps - 1) + }) + + it('returns all upkeep IDs if maxCount is 0', async () => { + let upkeepIds = await registry.getActiveUpkeepIDs(0, 0) + assert(upkeepIds.length == numUpkeeps) + upkeepIds = await registry.getActiveUpkeepIDs(2, 0) + assert(upkeepIds.length == numUpkeeps - 2) + }) + }) + + describe('#getMaxPaymentForGas', () => { + const arbL1PriceinWei = BigNumber.from(1000) // Same as MockArbGasInfo.sol + const l1CostWeiArb = arbL1PriceinWei.mul(16).mul(maxPerformDataSize) + const l1CostWeiOpt = BigNumber.from(2000000) // Same as MockOVMGasPriceOracle.sol + itMaybe('calculates the max fee appropriately', async () => { + await verifyMaxPayment(registry) + }) + + itMaybe('calculates the max fee appropriately for Arbitrum', async () => { + await verifyMaxPayment(arbRegistry, l1CostWeiArb) + }) + + itMaybe('calculates the max fee appropriately for Optimism', async () => { + await verifyMaxPayment(opRegistry, l1CostWeiOpt) + }) + + it('uses the fallback gas price if the feed has issues', async () => { + const expectedFallbackMaxPayment = linkForGas( + performGas, + registryConditionalOverhead + .add(registryPerSignerGasOverhead.mul(f + 1)) + .add(maxPerformDataSize.mul(registryPerPerformByteGasOverhead)), + gasCeilingMultiplier.mul('2'), // fallbackGasPrice is 2x gas price + paymentPremiumPPB, + flatFeeMicroLink, + ).total + + // Stale feed + let roundId = 99 + const answer = 100 + let updatedAt = 946684800 // New Years 2000 🥳 + let startedAt = 946684799 + await gasPriceFeed + .connect(owner) + .updateRoundData(roundId, answer, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + + // Negative feed price + roundId = 100 + updatedAt = now() + startedAt = 946684799 + await gasPriceFeed + .connect(owner) + .updateRoundData(roundId, -100, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + + // Zero feed price + roundId = 101 + updatedAt = now() + startedAt = 946684799 + await gasPriceFeed + .connect(owner) + .updateRoundData(roundId, 0, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + }) + + it('uses the fallback link price if the feed has issues', async () => { + const expectedFallbackMaxPayment = linkForGas( + performGas, + registryConditionalOverhead + .add(registryPerSignerGasOverhead.mul(f + 1)) + .add(maxPerformDataSize.mul(registryPerPerformByteGasOverhead)), + gasCeilingMultiplier.mul('2'), // fallbackLinkPrice is 1/2 link price, so multiply by 2 + paymentPremiumPPB, + flatFeeMicroLink, + ).total + + // Stale feed + let roundId = 99 + const answer = 100 + let updatedAt = 946684800 // New Years 2000 🥳 + let startedAt = 946684799 + await linkEthFeed + .connect(owner) + .updateRoundData(roundId, answer, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + + // Negative feed price + roundId = 100 + updatedAt = now() + startedAt = 946684799 + await linkEthFeed + .connect(owner) + .updateRoundData(roundId, -100, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + + // Zero feed price + roundId = 101 + updatedAt = now() + startedAt = 946684799 + await linkEthFeed + .connect(owner) + .updateRoundData(roundId, 0, updatedAt, startedAt) + + assert.equal( + expectedFallbackMaxPayment.toString(), + ( + await registry.getMaxPaymentForGas(Trigger.CONDITION, performGas) + ).toString(), + ) + }) + }) + + describe('#typeAndVersion', () => { + it('uses the correct type and version', async () => { + const typeAndVersion = await registry.typeAndVersion() + assert.equal(typeAndVersion, 'AutomationRegistry 2.2.0') + }) + }) + + describe('#onTokenTransfer', () => { + const amount = toWei('1') + + it('reverts if not called by the LINK token', async () => { + const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) + + await evmRevert( + registry + .connect(keeper1) + .onTokenTransfer(await keeper1.getAddress(), amount, data), + 'OnlyCallableByLINKToken()', + ) + }) + + it('reverts if not called with more or less than 32 bytes', async () => { + const longData = ethers.utils.defaultAbiCoder.encode( + ['uint256', 'uint256'], + ['33', '34'], + ) + const shortData = '0x12345678' + + await evmRevert( + linkToken + .connect(owner) + .transferAndCall(registry.address, amount, longData), + ) + await evmRevert( + linkToken + .connect(owner) + .transferAndCall(registry.address, amount, shortData), + ) + }) + + it('reverts if the upkeep is canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(keeper1).addFunds(upkeepId, amount), + 'UpkeepCancelled()', + ) + }) + + it('updates the funds of the job id passed', async () => { + const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [upkeepId]) + + const before = (await registry.getUpkeep(upkeepId)).balance + await linkToken + .connect(owner) + .transferAndCall(registry.address, amount, data) + const after = (await registry.getUpkeep(upkeepId)).balance + + assert.isTrue(before.add(amount).eq(after)) + }) + }) + + describeMaybe('#setConfig - onchain', () => { + const payment = BigNumber.from(1) + const flatFee = BigNumber.from(2) + const maxGas = BigNumber.from(6) + const staleness = BigNumber.from(4) + const ceiling = BigNumber.from(5) + const newMinUpkeepSpend = BigNumber.from(9) + const newMaxCheckDataSize = BigNumber.from(10000) + const newMaxPerformDataSize = BigNumber.from(10000) + const newMaxRevertDataSize = BigNumber.from(10000) + const newMaxPerformGas = BigNumber.from(10000000) + const fbGasEth = BigNumber.from(7) + const fbLinkEth = BigNumber.from(8) + const newTranscoder = randomAddress() + const newRegistrars = [randomAddress(), randomAddress()] + const upkeepManager = randomAddress() + + const newConfig: OnChainConfig = { + paymentPremiumPPB: payment, + flatFeeMicroLink: flatFee, + checkGasLimit: maxGas, + stalenessSeconds: staleness, + gasCeilingMultiplier: ceiling, + minUpkeepSpend: newMinUpkeepSpend, + maxCheckDataSize: newMaxCheckDataSize, + maxPerformDataSize: newMaxPerformDataSize, + maxRevertDataSize: newMaxRevertDataSize, + maxPerformGas: newMaxPerformGas, + fallbackGasPrice: fbGasEth, + fallbackLinkPrice: fbLinkEth, + transcoder: newTranscoder, + registrars: newRegistrars, + upkeepPrivilegeManager: upkeepManager, + reorgProtectionEnabled: true, + } + + it('reverts when called by anyone but the proposed owner', async () => { + await evmRevert( + registry + .connect(payee1) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + newConfig, + offchainVersion, + offchainBytes, + ), + 'Only callable by owner', + ) + }) + + it('reverts if signers or transmitters are the zero address', async () => { + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + [randomAddress(), randomAddress(), randomAddress(), zeroAddress], + [ + randomAddress(), + randomAddress(), + randomAddress(), + randomAddress(), + ], + f, + newConfig, + offchainVersion, + offchainBytes, + ), + 'InvalidSigner()', + ) + + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + [ + randomAddress(), + randomAddress(), + randomAddress(), + randomAddress(), + ], + [randomAddress(), randomAddress(), randomAddress(), zeroAddress], + f, + newConfig, + offchainVersion, + offchainBytes, + ), + 'InvalidTransmitter()', + ) + }) + + it('updates the onchainConfig and configDigest', async () => { + const old = await registry.getState() + const oldConfig = old.config + const oldState = old.state + assert.isTrue(paymentPremiumPPB.eq(oldConfig.paymentPremiumPPB)) + assert.isTrue(flatFeeMicroLink.eq(oldConfig.flatFeeMicroLink)) + assert.isTrue(stalenessSeconds.eq(oldConfig.stalenessSeconds)) + assert.isTrue(gasCeilingMultiplier.eq(oldConfig.gasCeilingMultiplier)) + + await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + newConfig, + offchainVersion, + offchainBytes, + ) + + const updated = await registry.getState() + const updatedConfig = updated.config + const updatedState = updated.state + assert.equal(updatedConfig.paymentPremiumPPB, payment.toNumber()) + assert.equal(updatedConfig.flatFeeMicroLink, flatFee.toNumber()) + assert.equal(updatedConfig.stalenessSeconds, staleness.toNumber()) + assert.equal(updatedConfig.gasCeilingMultiplier, ceiling.toNumber()) + assert.equal( + updatedConfig.minUpkeepSpend.toString(), + newMinUpkeepSpend.toString(), + ) + assert.equal( + updatedConfig.maxCheckDataSize, + newMaxCheckDataSize.toNumber(), + ) + assert.equal( + updatedConfig.maxPerformDataSize, + newMaxPerformDataSize.toNumber(), + ) + assert.equal( + updatedConfig.maxRevertDataSize, + newMaxRevertDataSize.toNumber(), + ) + assert.equal(updatedConfig.maxPerformGas, newMaxPerformGas.toNumber()) + assert.equal(updatedConfig.checkGasLimit, maxGas.toNumber()) + assert.equal( + updatedConfig.fallbackGasPrice.toNumber(), + fbGasEth.toNumber(), + ) + assert.equal( + updatedConfig.fallbackLinkPrice.toNumber(), + fbLinkEth.toNumber(), + ) + assert.equal(updatedState.latestEpoch, 0) + + assert(oldState.configCount + 1 == updatedState.configCount) + assert( + oldState.latestConfigBlockNumber != + updatedState.latestConfigBlockNumber, + ) + assert(oldState.latestConfigDigest != updatedState.latestConfigDigest) + + assert.equal(updatedConfig.transcoder, newTranscoder) + assert.deepEqual(updatedConfig.registrars, newRegistrars) + assert.equal(updatedConfig.upkeepPrivilegeManager, upkeepManager) + }) + + it('maintains paused state when config is changed', async () => { + await registry.pause() + const old = await registry.getState() + assert.isTrue(old.state.paused) + + await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + newConfig, + offchainVersion, + offchainBytes, + ) + + const updated = await registry.getState() + assert.isTrue(updated.state.paused) + }) + + it('emits an event', async () => { + const tx = await registry + .connect(owner) + .setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + newConfig, + offchainVersion, + offchainBytes, + ) + await expect(tx).to.emit(registry, 'ConfigSet') + }) + }) + + describe('#setConfig - offchain', () => { + let newKeepers: string[] + + beforeEach(async () => { + newKeepers = [ + await personas.Eddy.getAddress(), + await personas.Nick.getAddress(), + await personas.Neil.getAddress(), + await personas.Carol.getAddress(), + ] + }) + + it('reverts when called by anyone but the owner', async () => { + await evmRevert( + registry + .connect(payee1) + .setConfigTypeSafe( + newKeepers, + newKeepers, + f, + config, + offchainVersion, + offchainBytes, + ), + 'Only callable by owner', + ) + }) + + it('reverts if too many keeperAddresses set', async () => { + for (let i = 0; i < 40; i++) { + newKeepers.push(randomAddress()) + } + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + newKeepers, + newKeepers, + f, + config, + offchainVersion, + offchainBytes, + ), + 'TooManyOracles()', + ) + }) + + it('reverts if f=0', async () => { + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + newKeepers, + newKeepers, + 0, + config, + offchainVersion, + offchainBytes, + ), + 'IncorrectNumberOfFaultyOracles()', + ) + }) + + it('reverts if signers != transmitters length', async () => { + const signers = [randomAddress()] + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + signers, + newKeepers, + f, + config, + offchainVersion, + offchainBytes, + ), + 'IncorrectNumberOfSigners()', + ) + }) + + it('reverts if signers <= 3f', async () => { + newKeepers.pop() + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + newKeepers, + newKeepers, + f, + config, + offchainVersion, + offchainBytes, + ), + 'IncorrectNumberOfSigners()', + ) + }) + + it('reverts on repeated signers', async () => { + const newSigners = [ + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + ] + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + newSigners, + newKeepers, + f, + config, + offchainVersion, + offchainBytes, + ), + 'RepeatedSigner()', + ) + }) + + it('reverts on repeated transmitters', async () => { + const newTransmitters = [ + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + await personas.Eddy.getAddress(), + ] + await evmRevert( + registry + .connect(owner) + .setConfigTypeSafe( + newKeepers, + newTransmitters, + f, + config, + offchainVersion, + offchainBytes, + ), + 'RepeatedTransmitter()', + ) + }) + + itMaybe('stores new config and emits event', async () => { + // Perform an upkeep so that totalPremium is updated + await registry.connect(admin).addFunds(upkeepId, toWei('100')) + let tx = await getTransmitTx(registry, keeper1, [upkeepId]) + await tx.wait() + + const newOffChainVersion = BigNumber.from('2') + const newOffChainConfig = '0x1122' + + const old = await registry.getState() + const oldState = old.state + assert(oldState.totalPremium.gt(BigNumber.from('0'))) + + const newSigners = newKeepers + tx = await registry + .connect(owner) + .setConfigTypeSafe( + newSigners, + newKeepers, + f, + config, + newOffChainVersion, + newOffChainConfig, + ) + + const updated = await registry.getState() + const updatedState = updated.state + assert(oldState.totalPremium.eq(updatedState.totalPremium)) + + // Old signer addresses which are not in new signers should be non active + for (let i = 0; i < signerAddresses.length; i++) { + const signer = signerAddresses[i] + if (!newSigners.includes(signer)) { + assert((await registry.getSignerInfo(signer)).active == false) + assert((await registry.getSignerInfo(signer)).index == 0) + } + } + // New signer addresses should be active + for (let i = 0; i < newSigners.length; i++) { + const signer = newSigners[i] + assert((await registry.getSignerInfo(signer)).active == true) + assert((await registry.getSignerInfo(signer)).index == i) + } + // Old transmitter addresses which are not in new transmitter should be non active, update lastCollected but retain other info + for (let i = 0; i < keeperAddresses.length; i++) { + const transmitter = keeperAddresses[i] + if (!newKeepers.includes(transmitter)) { + assert( + (await registry.getTransmitterInfo(transmitter)).active == false, + ) + assert((await registry.getTransmitterInfo(transmitter)).index == i) + assert( + (await registry.getTransmitterInfo(transmitter)).lastCollected.eq( + oldState.totalPremium.sub( + oldState.totalPremium.mod(keeperAddresses.length), + ), + ), + ) + } + } + // New transmitter addresses should be active + for (let i = 0; i < newKeepers.length; i++) { + const transmitter = newKeepers[i] + assert((await registry.getTransmitterInfo(transmitter)).active == true) + assert((await registry.getTransmitterInfo(transmitter)).index == i) + assert( + (await registry.getTransmitterInfo(transmitter)).lastCollected.eq( + oldState.totalPremium, + ), + ) + } + + // config digest should be updated + assert(oldState.configCount + 1 == updatedState.configCount) + assert( + oldState.latestConfigBlockNumber != + updatedState.latestConfigBlockNumber, + ) + assert(oldState.latestConfigDigest != updatedState.latestConfigDigest) + + //New config should be updated + assert.deepEqual(updated.signers, newKeepers) + assert.deepEqual(updated.transmitters, newKeepers) + + // Event should have been emitted + await expect(tx).to.emit(registry, 'ConfigSet') + }) + }) + + describe('#setPeerRegistryMigrationPermission() / #getPeerRegistryMigrationPermission()', () => { + const peer = randomAddress() + it('allows the owner to set the peer registries', async () => { + let permission = await registry.getPeerRegistryMigrationPermission(peer) + expect(permission).to.equal(0) + await registry.setPeerRegistryMigrationPermission(peer, 1) + permission = await registry.getPeerRegistryMigrationPermission(peer) + expect(permission).to.equal(1) + await registry.setPeerRegistryMigrationPermission(peer, 2) + permission = await registry.getPeerRegistryMigrationPermission(peer) + expect(permission).to.equal(2) + await registry.setPeerRegistryMigrationPermission(peer, 0) + permission = await registry.getPeerRegistryMigrationPermission(peer) + expect(permission).to.equal(0) + }) + it('reverts if passed an unsupported permission', async () => { + await expect( + registry.connect(admin).setPeerRegistryMigrationPermission(peer, 10), + ).to.be.reverted + }) + it('reverts if not called by the owner', async () => { + await expect( + registry.connect(admin).setPeerRegistryMigrationPermission(peer, 1), + ).to.be.revertedWith('Only callable by owner') + }) + }) + + describe('#registerUpkeep', () => { + it('reverts when registry is paused', async () => { + await registry.connect(owner).pause() + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'RegistryPaused()', + ) + }) + + it('reverts if the target is not a contract', async () => { + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + zeroAddress, + performGas, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'NotAContract()', + ) + }) + + it('reverts if called by a non-owner', async () => { + await evmRevert( + registry + .connect(keeper1) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'OnlyCallableByOwnerOrRegistrar()', + ) + }) + + it('reverts if execute gas is too low', async () => { + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + 2299, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'GasLimitOutsideRange()', + ) + }) + + it('reverts if execute gas is too high', async () => { + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + 5000001, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'GasLimitOutsideRange()', + ) + }) + + it('reverts if checkData is too long', async () => { + let longBytes = '0x' + for (let i = 0; i < 10000; i++) { + longBytes += '1' + } + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + longBytes, + '0x', + ), + 'CheckDataExceedsLimit()', + ) + }) + + it('creates a record of the registration', async () => { + const performGases = [100000, 500000] + const checkDatas = [emptyBytes, '0x12'] + + for (let jdx = 0; jdx < performGases.length; jdx++) { + const performGas = performGases[jdx] + for (let kdx = 0; kdx < checkDatas.length; kdx++) { + const checkData = checkDatas[kdx] + const tx = await registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + checkData, + '0x', + ) + + //confirm the upkeep details and verify emitted events + const testUpkeepId = await getUpkeepID(tx) + await expect(tx) + .to.emit(registry, 'UpkeepRegistered') + .withArgs(testUpkeepId, performGas, await admin.getAddress()) + + await expect(tx) + .to.emit(registry, 'UpkeepCheckDataSet') + .withArgs(testUpkeepId, checkData) + await expect(tx) + .to.emit(registry, 'UpkeepTriggerConfigSet') + .withArgs(testUpkeepId, '0x') + + const registration = await registry.getUpkeep(testUpkeepId) + + assert.equal(mock.address, registration.target) + assert.notEqual( + ethers.constants.AddressZero, + await registry.getForwarder(testUpkeepId), + ) + assert.equal( + performGas.toString(), + registration.performGas.toString(), + ) + assert.equal(await admin.getAddress(), registration.admin) + assert.equal(0, registration.balance.toNumber()) + assert.equal(0, registration.amountSpent.toNumber()) + assert.equal(0, registration.lastPerformedBlockNumber) + assert.equal(checkData, registration.checkData) + assert.equal(registration.paused, false) + assert.equal(registration.offchainConfig, '0x') + assert(registration.maxValidBlocknumber.eq('0xffffffff')) + } + } + }) + }) + + describe('#pauseUpkeep', () => { + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry.connect(keeper1).pauseUpkeep(upkeepId.add(1)), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is already canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + await evmRevert( + registry.connect(admin).pauseUpkeep(upkeepId), + 'UpkeepCancelled()', + ) + }) + + it('reverts if the upkeep is already paused', async () => { + await registry.connect(admin).pauseUpkeep(upkeepId) + + await evmRevert( + registry.connect(admin).pauseUpkeep(upkeepId), + 'OnlyUnpausedUpkeep()', + ) + }) + + it('reverts if the caller is not the upkeep admin', async () => { + await evmRevert( + registry.connect(keeper1).pauseUpkeep(upkeepId), + 'OnlyCallableByAdmin()', + ) + }) + + it('pauses the upkeep and emits an event', async () => { + const tx = await registry.connect(admin).pauseUpkeep(upkeepId) + await expect(tx).to.emit(registry, 'UpkeepPaused').withArgs(upkeepId) + + const registration = await registry.getUpkeep(upkeepId) + assert.equal(registration.paused, true) + }) + }) + + describe('#unpauseUpkeep', () => { + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry.connect(keeper1).unpauseUpkeep(upkeepId.add(1)), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is already canceled', async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + + await evmRevert( + registry.connect(admin).unpauseUpkeep(upkeepId), + 'UpkeepCancelled()', + ) + }) + + it('marks the contract as paused', async () => { + assert.isFalse((await registry.getState()).state.paused) + + await registry.connect(owner).pause() + + assert.isTrue((await registry.getState()).state.paused) + }) + + it('reverts if the upkeep is not paused', async () => { + await evmRevert( + registry.connect(admin).unpauseUpkeep(upkeepId), + 'OnlyPausedUpkeep()', + ) + }) + + it('reverts if the caller is not the upkeep admin', async () => { + await registry.connect(admin).pauseUpkeep(upkeepId) + + const registration = await registry.getUpkeep(upkeepId) + + assert.equal(registration.paused, true) + + await evmRevert( + registry.connect(keeper1).unpauseUpkeep(upkeepId), + 'OnlyCallableByAdmin()', + ) + }) + + it('unpauses the upkeep and emits an event', async () => { + const originalCount = (await registry.getActiveUpkeepIDs(0, 0)).length + + await registry.connect(admin).pauseUpkeep(upkeepId) + + const tx = await registry.connect(admin).unpauseUpkeep(upkeepId) + + await expect(tx).to.emit(registry, 'UpkeepUnpaused').withArgs(upkeepId) + + const registration = await registry.getUpkeep(upkeepId) + assert.equal(registration.paused, false) + + const upkeepIds = await registry.getActiveUpkeepIDs(0, 0) + assert.equal(upkeepIds.length, originalCount) + }) + }) + + describe('#setUpkeepCheckData', () => { + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry + .connect(keeper1) + .setUpkeepCheckData(upkeepId.add(1), randomBytes), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the caller is not upkeep admin', async () => { + await evmRevert( + registry.connect(keeper1).setUpkeepCheckData(upkeepId, randomBytes), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is cancelled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + await evmRevert( + registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes), + 'UpkeepCancelled()', + ) + }) + + it('is allowed to update on paused upkeep', async () => { + await registry.connect(admin).pauseUpkeep(upkeepId) + await registry.connect(admin).setUpkeepCheckData(upkeepId, randomBytes) + + const registration = await registry.getUpkeep(upkeepId) + assert.equal(randomBytes, registration.checkData) + }) + + it('reverts if new data exceeds limit', async () => { + let longBytes = '0x' + for (let i = 0; i < 10000; i++) { + longBytes += '1' + } + + await evmRevert( + registry.connect(admin).setUpkeepCheckData(upkeepId, longBytes), + 'CheckDataExceedsLimit()', + ) + }) + + it('updates the upkeep check data and emits an event', async () => { + const tx = await registry + .connect(admin) + .setUpkeepCheckData(upkeepId, randomBytes) + await expect(tx) + .to.emit(registry, 'UpkeepCheckDataSet') + .withArgs(upkeepId, randomBytes) + + const registration = await registry.getUpkeep(upkeepId) + assert.equal(randomBytes, registration.checkData) + }) + }) + + describe('#setUpkeepGasLimit', () => { + const newGasLimit = BigNumber.from('300000') + + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry.connect(admin).setUpkeepGasLimit(upkeepId.add(1), newGasLimit), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit), + 'UpkeepCancelled()', + ) + }) + + it('reverts if called by anyone but the admin', async () => { + await evmRevert( + registry.connect(owner).setUpkeepGasLimit(upkeepId, newGasLimit), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if new gas limit is out of bounds', async () => { + await evmRevert( + registry + .connect(admin) + .setUpkeepGasLimit(upkeepId, BigNumber.from('100')), + 'GasLimitOutsideRange()', + ) + await evmRevert( + registry + .connect(admin) + .setUpkeepGasLimit(upkeepId, BigNumber.from('6000000')), + 'GasLimitOutsideRange()', + ) + }) + + it('updates the gas limit successfully', async () => { + const initialGasLimit = (await registry.getUpkeep(upkeepId)).performGas + assert.equal(initialGasLimit, performGas.toNumber()) + await registry.connect(admin).setUpkeepGasLimit(upkeepId, newGasLimit) + const updatedGasLimit = (await registry.getUpkeep(upkeepId)).performGas + assert.equal(updatedGasLimit, newGasLimit.toNumber()) + }) + + it('emits a log', async () => { + const tx = await registry + .connect(admin) + .setUpkeepGasLimit(upkeepId, newGasLimit) + await expect(tx) + .to.emit(registry, 'UpkeepGasLimitSet') + .withArgs(upkeepId, newGasLimit) + }) + }) + + describe('#setUpkeepOffchainConfig', () => { + const newConfig = '0xc0ffeec0ffee' + + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry + .connect(admin) + .setUpkeepOffchainConfig(upkeepId.add(1), newConfig), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig), + 'UpkeepCancelled()', + ) + }) + + it('reverts if called by anyone but the admin', async () => { + await evmRevert( + registry.connect(owner).setUpkeepOffchainConfig(upkeepId, newConfig), + 'OnlyCallableByAdmin()', + ) + }) + + it('updates the config successfully', async () => { + const initialConfig = (await registry.getUpkeep(upkeepId)).offchainConfig + assert.equal(initialConfig, '0x') + await registry.connect(admin).setUpkeepOffchainConfig(upkeepId, newConfig) + const updatedConfig = (await registry.getUpkeep(upkeepId)).offchainConfig + assert.equal(newConfig, updatedConfig) + }) + + it('emits a log', async () => { + const tx = await registry + .connect(admin) + .setUpkeepOffchainConfig(upkeepId, newConfig) + await expect(tx) + .to.emit(registry, 'UpkeepOffchainConfigSet') + .withArgs(upkeepId, newConfig) + }) + }) + + describe('#setUpkeepTriggerConfig', () => { + const newConfig = '0xdeadbeef' + + it('reverts if the registration does not exist', async () => { + await evmRevert( + registry + .connect(admin) + .setUpkeepTriggerConfig(upkeepId.add(1), newConfig), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts if the upkeep is canceled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(admin).setUpkeepTriggerConfig(upkeepId, newConfig), + 'UpkeepCancelled()', + ) + }) + + it('reverts if called by anyone but the admin', async () => { + await evmRevert( + registry.connect(owner).setUpkeepTriggerConfig(upkeepId, newConfig), + 'OnlyCallableByAdmin()', + ) + }) + + it('emits a log', async () => { + const tx = await registry + .connect(admin) + .setUpkeepTriggerConfig(upkeepId, newConfig) + await expect(tx) + .to.emit(registry, 'UpkeepTriggerConfigSet') + .withArgs(upkeepId, newConfig) + }) + }) + + describe('#transferUpkeepAdmin', () => { + it('reverts when called by anyone but the current upkeep admin', async () => { + await evmRevert( + registry + .connect(payee1) + .transferUpkeepAdmin(upkeepId, await payee2.getAddress()), + 'OnlyCallableByAdmin()', + ) + }) + + it('reverts when transferring to self', async () => { + await evmRevert( + registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await admin.getAddress()), + 'ValueNotChanged()', + ) + }) + + it('reverts when the upkeep is cancelled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + await evmRevert( + registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await keeper1.getAddress()), + 'UpkeepCancelled()', + ) + }) + + it('allows cancelling transfer by reverting to zero address', async () => { + await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + const tx = await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, ethers.constants.AddressZero) + + await expect(tx) + .to.emit(registry, 'UpkeepAdminTransferRequested') + .withArgs( + upkeepId, + await admin.getAddress(), + ethers.constants.AddressZero, + ) + }) + + it('does not change the upkeep admin', async () => { + await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + + const upkeep = await registry.getUpkeep(upkeepId) + assert.equal(await admin.getAddress(), upkeep.admin) + }) + + it('emits an event announcing the new upkeep admin', async () => { + const tx = await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + + await expect(tx) + .to.emit(registry, 'UpkeepAdminTransferRequested') + .withArgs(upkeepId, await admin.getAddress(), await payee1.getAddress()) + }) + + it('does not emit an event when called with the same proposed upkeep admin', async () => { + await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + + const tx = await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + const receipt = await tx.wait() + assert.equal(0, receipt.logs.length) + }) + }) + + describe('#acceptUpkeepAdmin', () => { + beforeEach(async () => { + // Start admin transfer to payee1 + await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + }) + + it('reverts when not called by the proposed upkeep admin', async () => { + await evmRevert( + registry.connect(payee2).acceptUpkeepAdmin(upkeepId), + 'OnlyCallableByProposedAdmin()', + ) + }) + + it('reverts when the upkeep is cancelled', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + await evmRevert( + registry.connect(payee1).acceptUpkeepAdmin(upkeepId), + 'UpkeepCancelled()', + ) + }) + + it('does change the admin', async () => { + await registry.connect(payee1).acceptUpkeepAdmin(upkeepId) + + const upkeep = await registry.getUpkeep(upkeepId) + assert.equal(await payee1.getAddress(), upkeep.admin) + }) + + it('emits an event announcing the new upkeep admin', async () => { + const tx = await registry.connect(payee1).acceptUpkeepAdmin(upkeepId) + await expect(tx) + .to.emit(registry, 'UpkeepAdminTransferred') + .withArgs(upkeepId, await admin.getAddress(), await payee1.getAddress()) + }) + }) + + describe('#withdrawOwnerFunds', () => { + it('can only be called by owner', async () => { + await evmRevert( + registry.connect(keeper1).withdrawOwnerFunds(), + 'Only callable by owner', + ) + }) + + itMaybe('withdraws the collected fees to owner', async () => { + await registry.connect(admin).addFunds(upkeepId, toWei('100')) + // Very high min spend, whole balance as cancellation fees + const minUpkeepSpend = toWei('1000') + await registry.connect(owner).setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + reorgProtectionEnabled: true, + }, + offchainVersion, + offchainBytes, + ) + const upkeepBalance = (await registry.getUpkeep(upkeepId)).balance + const ownerBefore = await linkToken.balanceOf(await owner.getAddress()) + + await registry.connect(owner).cancelUpkeep(upkeepId) + + // Transfered to owner balance on registry + let ownerRegistryBalance = (await registry.getState()).state + .ownerLinkBalance + assert.isTrue(ownerRegistryBalance.eq(upkeepBalance)) + + // Now withdraw + await registry.connect(owner).withdrawOwnerFunds() + + ownerRegistryBalance = (await registry.getState()).state.ownerLinkBalance + const ownerAfter = await linkToken.balanceOf(await owner.getAddress()) + + // Owner registry balance should be changed to 0 + assert.isTrue(ownerRegistryBalance.eq(BigNumber.from('0'))) + + // Owner should be credited with the balance + assert.isTrue(ownerBefore.add(upkeepBalance).eq(ownerAfter)) + }) + }) + + describe('#transferPayeeship', () => { + it('reverts when called by anyone but the current payee', async () => { + await evmRevert( + registry + .connect(payee2) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ), + 'OnlyCallableByPayee()', + ) + }) + + it('reverts when transferring to self', async () => { + await evmRevert( + registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee1.getAddress(), + ), + 'ValueNotChanged()', + ) + }) + + it('does not change the payee', async () => { + await registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ) + + const info = await registry.getTransmitterInfo(await keeper1.getAddress()) + assert.equal(await payee1.getAddress(), info.payee) + }) + + it('emits an event announcing the new payee', async () => { + const tx = await registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ) + await expect(tx) + .to.emit(registry, 'PayeeshipTransferRequested') + .withArgs( + await keeper1.getAddress(), + await payee1.getAddress(), + await payee2.getAddress(), + ) + }) + + it('does not emit an event when called with the same proposal', async () => { + await registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ) + + const tx = await registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ) + const receipt = await tx.wait() + assert.equal(0, receipt.logs.length) + }) + }) + + describe('#acceptPayeeship', () => { + beforeEach(async () => { + await registry + .connect(payee1) + .transferPayeeship( + await keeper1.getAddress(), + await payee2.getAddress(), + ) + }) + + it('reverts when called by anyone but the proposed payee', async () => { + await evmRevert( + registry.connect(payee1).acceptPayeeship(await keeper1.getAddress()), + 'OnlyCallableByProposedPayee()', + ) + }) + + it('emits an event announcing the new payee', async () => { + const tx = await registry + .connect(payee2) + .acceptPayeeship(await keeper1.getAddress()) + await expect(tx) + .to.emit(registry, 'PayeeshipTransferred') + .withArgs( + await keeper1.getAddress(), + await payee1.getAddress(), + await payee2.getAddress(), + ) + }) + + it('does change the payee', async () => { + await registry.connect(payee2).acceptPayeeship(await keeper1.getAddress()) + + const info = await registry.getTransmitterInfo(await keeper1.getAddress()) + assert.equal(await payee2.getAddress(), info.payee) + }) + }) + + describe('#pause', () => { + it('reverts if called by a non-owner', async () => { + await evmRevert( + registry.connect(keeper1).pause(), + 'Only callable by owner', + ) + }) + + it('marks the contract as paused', async () => { + assert.isFalse((await registry.getState()).state.paused) + + await registry.connect(owner).pause() + + assert.isTrue((await registry.getState()).state.paused) + }) + + it('Does not allow transmits when paused', async () => { + await registry.connect(owner).pause() + + await evmRevert( + getTransmitTx(registry, keeper1, [upkeepId]), + 'RegistryPaused()', + ) + }) + + it('Does not allow creation of new upkeeps when paused', async () => { + await registry.connect(owner).pause() + + await evmRevert( + registry + .connect(owner) + ['registerUpkeep(address,uint32,address,bytes,bytes)']( + mock.address, + performGas, + await admin.getAddress(), + emptyBytes, + '0x', + ), + 'RegistryPaused()', + ) + }) + }) + + describe('#unpause', () => { + beforeEach(async () => { + await registry.connect(owner).pause() + }) + + it('reverts if called by a non-owner', async () => { + await evmRevert( + registry.connect(keeper1).unpause(), + 'Only callable by owner', + ) + }) + + it('marks the contract as not paused', async () => { + assert.isTrue((await registry.getState()).state.paused) + + await registry.connect(owner).unpause() + + assert.isFalse((await registry.getState()).state.paused) + }) + }) + + describe('#migrateUpkeeps() / #receiveUpkeeps()', async () => { + context('when permissions are set', () => { + beforeEach(async () => { + await linkToken.connect(owner).approve(registry.address, toWei('100')) + await registry.connect(owner).addFunds(upkeepId, toWei('100')) + await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 1) + await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 2) + }) + + it('migrates an upkeep', async () => { + const offchainBytes = '0x987654abcd' + await registry + .connect(admin) + .setUpkeepOffchainConfig(upkeepId, offchainBytes) + const reg1Upkeep = await registry.getUpkeep(upkeepId) + const forwarderAddress = await registry.getForwarder(upkeepId) + expect(reg1Upkeep.balance).to.equal(toWei('100')) + expect(reg1Upkeep.checkData).to.equal(randomBytes) + expect(forwarderAddress).to.not.equal(ethers.constants.AddressZero) + expect(reg1Upkeep.offchainConfig).to.equal(offchainBytes) + expect((await registry.getState()).state.numUpkeeps).to.equal( + numUpkeeps, + ) + const forwarder = await IAutomationForwarderFactory.connect( + forwarderAddress, + owner, + ) + expect(await forwarder.getRegistry()).to.equal(registry.address) + // Set an upkeep admin transfer in progress too + await registry + .connect(admin) + .transferUpkeepAdmin(upkeepId, await payee1.getAddress()) + + // migrate + await registry + .connect(admin) + .migrateUpkeeps([upkeepId], mgRegistry.address) + expect((await registry.getState()).state.numUpkeeps).to.equal( + numUpkeeps - 1, + ) + expect((await mgRegistry.getState()).state.numUpkeeps).to.equal(1) + expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) + expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') + expect((await mgRegistry.getUpkeep(upkeepId)).balance).to.equal( + toWei('100'), + ) + expect( + (await mgRegistry.getState()).state.expectedLinkBalance, + ).to.equal(toWei('100')) + expect((await mgRegistry.getUpkeep(upkeepId)).checkData).to.equal( + randomBytes, + ) + expect((await mgRegistry.getUpkeep(upkeepId)).offchainConfig).to.equal( + offchainBytes, + ) + expect(await mgRegistry.getForwarder(upkeepId)).to.equal( + forwarderAddress, + ) + // test that registry is updated on forwarder + expect(await forwarder.getRegistry()).to.equal(mgRegistry.address) + // migration will delete the upkeep and nullify admin transfer + await expect( + registry.connect(payee1).acceptUpkeepAdmin(upkeepId), + ).to.be.revertedWith('UpkeepCancelled()') + await expect( + mgRegistry.connect(payee1).acceptUpkeepAdmin(upkeepId), + ).to.be.revertedWith('OnlyCallableByProposedAdmin()') + }) + + it('migrates a paused upkeep', async () => { + expect((await registry.getUpkeep(upkeepId)).balance).to.equal( + toWei('100'), + ) + expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( + randomBytes, + ) + expect((await registry.getState()).state.numUpkeeps).to.equal( + numUpkeeps, + ) + await registry.connect(admin).pauseUpkeep(upkeepId) + // verify the upkeep is paused + expect((await registry.getUpkeep(upkeepId)).paused).to.equal(true) + // migrate + await registry + .connect(admin) + .migrateUpkeeps([upkeepId], mgRegistry.address) + expect((await registry.getState()).state.numUpkeeps).to.equal( + numUpkeeps - 1, + ) + expect((await mgRegistry.getState()).state.numUpkeeps).to.equal(1) + expect((await registry.getUpkeep(upkeepId)).balance).to.equal(0) + expect((await mgRegistry.getUpkeep(upkeepId)).balance).to.equal( + toWei('100'), + ) + expect((await registry.getUpkeep(upkeepId)).checkData).to.equal('0x') + expect((await mgRegistry.getUpkeep(upkeepId)).checkData).to.equal( + randomBytes, + ) + expect( + (await mgRegistry.getState()).state.expectedLinkBalance, + ).to.equal(toWei('100')) + // verify the upkeep is still paused after migration + expect((await mgRegistry.getUpkeep(upkeepId)).paused).to.equal(true) + }) + + it('emits an event on both contracts', async () => { + expect((await registry.getUpkeep(upkeepId)).balance).to.equal( + toWei('100'), + ) + expect((await registry.getUpkeep(upkeepId)).checkData).to.equal( + randomBytes, + ) + expect((await registry.getState()).state.numUpkeeps).to.equal( + numUpkeeps, + ) + const tx = registry + .connect(admin) + .migrateUpkeeps([upkeepId], mgRegistry.address) + await expect(tx) + .to.emit(registry, 'UpkeepMigrated') + .withArgs(upkeepId, toWei('100'), mgRegistry.address) + await expect(tx) + .to.emit(mgRegistry, 'UpkeepReceived') + .withArgs(upkeepId, toWei('100'), registry.address) + }) + + it('is only migratable by the admin', async () => { + await expect( + registry + .connect(owner) + .migrateUpkeeps([upkeepId], mgRegistry.address), + ).to.be.revertedWith('OnlyCallableByAdmin()') + await registry + .connect(admin) + .migrateUpkeeps([upkeepId], mgRegistry.address) + }) + }) + + context('when permissions are not set', () => { + it('reverts', async () => { + // no permissions + await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 0) + await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 0) + await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to + .be.reverted + // only outgoing permissions + await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 1) + await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 0) + await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to + .be.reverted + // only incoming permissions + await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 0) + await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 2) + await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to + .be.reverted + // permissions opposite direction + await registry.setPeerRegistryMigrationPermission(mgRegistry.address, 2) + await mgRegistry.setPeerRegistryMigrationPermission(registry.address, 1) + await expect(registry.migrateUpkeeps([upkeepId], mgRegistry.address)).to + .be.reverted + }) + }) + }) + + describe('#setPayees', () => { + const IGNORE_ADDRESS = '0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF' + + it('reverts when not called by the owner', async () => { + await evmRevert( + registry.connect(keeper1).setPayees(payees), + 'Only callable by owner', + ) + }) + + it('reverts with different numbers of payees than transmitters', async () => { + await evmRevert( + registry.connect(owner).setPayees([...payees, randomAddress()]), + 'ParameterLengthError()', + ) + }) + + it('reverts if the payee is the zero address', async () => { + await blankRegistry.connect(owner).setConfig(...baseConfig) // used to test initial config + + await evmRevert( + blankRegistry // used to test initial config + .connect(owner) + .setPayees([ethers.constants.AddressZero, ...payees.slice(1)]), + 'InvalidPayee()', + ) + }) + + itMaybe( + 'sets the payees when exisitng payees are zero address', + async () => { + //Initial payees should be zero address + await blankRegistry.connect(owner).setConfig(...baseConfig) // used to test initial config + + for (let i = 0; i < keeperAddresses.length; i++) { + const payee = ( + await blankRegistry.getTransmitterInfo(keeperAddresses[i]) + ).payee // used to test initial config + assert.equal(payee, zeroAddress) + } + + await blankRegistry.connect(owner).setPayees(payees) // used to test initial config + + for (let i = 0; i < keeperAddresses.length; i++) { + const payee = ( + await blankRegistry.getTransmitterInfo(keeperAddresses[i]) + ).payee + assert.equal(payee, payees[i]) + } + }, + ) + + it('does not change the payee if IGNORE_ADDRESS is used as payee', async () => { + const signers = Array.from({ length: 5 }, randomAddress) + const keepers = Array.from({ length: 5 }, randomAddress) + const payees = Array.from({ length: 5 }, randomAddress) + const newTransmitter = randomAddress() + const newPayee = randomAddress() + const ignoreAddresses = new Array(payees.length).fill(IGNORE_ADDRESS) + const newPayees = [...ignoreAddresses, newPayee] + // arbitrum registry + // configure registry with 5 keepers // optimism registry + await blankRegistry // used to test initial configurations + .connect(owner) + .setConfigTypeSafe( + signers, + keepers, + f, + config, + offchainVersion, + offchainBytes, + ) + // arbitrum registry + // set initial payees // optimism registry + await blankRegistry.connect(owner).setPayees(payees) // used to test initial configurations + // arbitrum registry + // add another keeper // optimism registry + await blankRegistry // used to test initial configurations + .connect(owner) + .setConfigTypeSafe( + [...signers, randomAddress()], + [...keepers, newTransmitter], + f, + config, + offchainVersion, + offchainBytes, + ) + // arbitrum registry + // update payee list // optimism registry // arbitrum registry + await blankRegistry.connect(owner).setPayees(newPayees) // used to test initial configurations // optimism registry + const ignored = await blankRegistry.getTransmitterInfo(newTransmitter) // used to test initial configurations + assert.equal(newPayee, ignored.payee) + assert.equal(true, ignored.active) + }) + + it('reverts if payee is non zero and owner tries to change payee', async () => { + const newPayees = [randomAddress(), ...payees.slice(1)] + + await evmRevert( + registry.connect(owner).setPayees(newPayees), + 'InvalidPayee()', + ) + }) + + it('emits events for every payee added and removed', async () => { + const tx = await registry.connect(owner).setPayees(payees) + await expect(tx) + .to.emit(registry, 'PayeesUpdated') + .withArgs(keeperAddresses, payees) + }) + }) + + describe('#cancelUpkeep', () => { + it('reverts if the ID is not valid', async () => { + await evmRevert( + registry.connect(owner).cancelUpkeep(upkeepId.add(1)), + 'CannotCancel()', + ) + }) + + it('reverts if called by a non-owner/non-admin', async () => { + await evmRevert( + registry.connect(keeper1).cancelUpkeep(upkeepId), + 'OnlyCallableByOwnerOrAdmin()', + ) + }) + + describe('when called by the owner', async () => { + it('sets the registration to invalid immediately', async () => { + const tx = await registry.connect(owner).cancelUpkeep(upkeepId) + const receipt = await tx.wait() + const registration = await registry.getUpkeep(upkeepId) + assert.equal( + registration.maxValidBlocknumber.toNumber(), + receipt.blockNumber, + ) + }) + + it('emits an event', async () => { + const tx = await registry.connect(owner).cancelUpkeep(upkeepId) + const receipt = await tx.wait() + await expect(tx) + .to.emit(registry, 'UpkeepCanceled') + .withArgs(upkeepId, BigNumber.from(receipt.blockNumber)) + }) + + it('immediately prevents upkeep', async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + + const tx = await getTransmitTx(registry, keeper1, [upkeepId]) + const receipt = await tx.wait() + const cancelledUpkeepReportLogs = + parseCancelledUpkeepReportLogs(receipt) + // exactly 1 CancelledUpkeepReport log should be emitted + assert.equal(cancelledUpkeepReportLogs.length, 1) + }) + + it('does not revert if reverts if called multiple times', async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + await evmRevert( + registry.connect(owner).cancelUpkeep(upkeepId), + 'CannotCancel()', + ) + }) + + describe('when called by the owner when the admin has just canceled', () => { + let oldExpiration: BigNumber + + beforeEach(async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + const registration = await registry.getUpkeep(upkeepId) + oldExpiration = registration.maxValidBlocknumber + }) + + it('allows the owner to cancel it more quickly', async () => { + await registry.connect(owner).cancelUpkeep(upkeepId) + + const registration = await registry.getUpkeep(upkeepId) + const newExpiration = registration.maxValidBlocknumber + assert.isTrue(newExpiration.lt(oldExpiration)) + }) + }) + }) + + describe('when called by the admin', async () => { + it('reverts if called again by the admin', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + await evmRevert( + registry.connect(admin).cancelUpkeep(upkeepId), + 'CannotCancel()', + ) + }) + + it('reverts if called by the owner after the timeout', async () => { + await registry.connect(admin).cancelUpkeep(upkeepId) + + for (let i = 0; i < cancellationDelay; i++) { + await ethers.provider.send('evm_mine', []) + } + + await evmRevert( + registry.connect(owner).cancelUpkeep(upkeepId), + 'CannotCancel()', + ) + }) + + it('sets the registration to invalid in 50 blocks', async () => { + const tx = await registry.connect(admin).cancelUpkeep(upkeepId) + const receipt = await tx.wait() + const registration = await registry.getUpkeep(upkeepId) + assert.equal( + registration.maxValidBlocknumber.toNumber(), + receipt.blockNumber + 50, + ) + }) + + it('emits an event', async () => { + const tx = await registry.connect(admin).cancelUpkeep(upkeepId) + const receipt = await tx.wait() + await expect(tx) + .to.emit(registry, 'UpkeepCanceled') + .withArgs( + upkeepId, + BigNumber.from(receipt.blockNumber + cancellationDelay), + ) + }) + + it('immediately prevents upkeep', async () => { + await linkToken.connect(owner).approve(registry.address, toWei('100')) + await registry.connect(owner).addFunds(upkeepId, toWei('100')) + await registry.connect(admin).cancelUpkeep(upkeepId) + + await getTransmitTx(registry, keeper1, [upkeepId]) + + for (let i = 0; i < cancellationDelay; i++) { + await ethers.provider.send('evm_mine', []) + } + + const tx = await getTransmitTx(registry, keeper1, [upkeepId]) + + const receipt = await tx.wait() + const cancelledUpkeepReportLogs = + parseCancelledUpkeepReportLogs(receipt) + // exactly 1 CancelledUpkeepReport log should be emitted + assert.equal(cancelledUpkeepReportLogs.length, 1) + }) + + describeMaybe('when an upkeep has been performed', async () => { + beforeEach(async () => { + await linkToken.connect(owner).approve(registry.address, toWei('100')) + await registry.connect(owner).addFunds(upkeepId, toWei('100')) + await getTransmitTx(registry, keeper1, [upkeepId]) + }) + + it('deducts a cancellation fee from the upkeep and gives to owner', async () => { + const minUpkeepSpend = toWei('10') + + await registry.connect(owner).setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + reorgProtectionEnabled: true, + }, + offchainVersion, + offchainBytes, + ) + + const payee1Before = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance + const ownerBefore = (await registry.getState()).state.ownerLinkBalance + + const amountSpent = toWei('100').sub(upkeepBefore) + const cancellationFee = minUpkeepSpend.sub(amountSpent) + + await registry.connect(admin).cancelUpkeep(upkeepId) + + const payee1After = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance + const ownerAfter = (await registry.getState()).state.ownerLinkBalance + + // post upkeep balance should be previous balance minus cancellation fee + assert.isTrue(upkeepBefore.sub(cancellationFee).eq(upkeepAfter)) + // payee balance should not change + assert.isTrue(payee1Before.eq(payee1After)) + // owner should receive the cancellation fee + assert.isTrue(ownerAfter.sub(ownerBefore).eq(cancellationFee)) + }) + + it('deducts up to balance as cancellation fee', async () => { + // Very high min spend, should deduct whole balance as cancellation fees + const minUpkeepSpend = toWei('1000') + await registry.connect(owner).setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + reorgProtectionEnabled: true, + }, + offchainVersion, + offchainBytes, + ) + const payee1Before = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance + const ownerBefore = (await registry.getState()).state.ownerLinkBalance + + await registry.connect(admin).cancelUpkeep(upkeepId) + const payee1After = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const ownerAfter = (await registry.getState()).state.ownerLinkBalance + const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance + + // all upkeep balance is deducted for cancellation fee + assert.equal(0, upkeepAfter.toNumber()) + // payee balance should not change + assert.isTrue(payee1After.eq(payee1Before)) + // all upkeep balance is transferred to the owner + assert.isTrue(ownerAfter.sub(ownerBefore).eq(upkeepBefore)) + }) + + it('does not deduct cancellation fee if more than minUpkeepSpend is spent', async () => { + // Very low min spend, already spent in one perform upkeep + const minUpkeepSpend = BigNumber.from(420) + await registry.connect(owner).setConfigTypeSafe( + signerAddresses, + keeperAddresses, + f, + { + paymentPremiumPPB, + flatFeeMicroLink, + checkGasLimit, + stalenessSeconds, + gasCeilingMultiplier, + minUpkeepSpend, + maxCheckDataSize, + maxPerformDataSize, + maxRevertDataSize, + maxPerformGas, + fallbackGasPrice, + fallbackLinkPrice, + transcoder: transcoder.address, + registrars: [], + upkeepPrivilegeManager: upkeepManager, + reorgProtectionEnabled: true, + }, + offchainVersion, + offchainBytes, + ) + const payee1Before = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const upkeepBefore = (await registry.getUpkeep(upkeepId)).balance + const ownerBefore = (await registry.getState()).state.ownerLinkBalance + + await registry.connect(admin).cancelUpkeep(upkeepId) + const payee1After = await linkToken.balanceOf( + await payee1.getAddress(), + ) + const ownerAfter = (await registry.getState()).state.ownerLinkBalance + const upkeepAfter = (await registry.getUpkeep(upkeepId)).balance + + // upkeep does not pay cancellation fee after cancellation because minimum upkeep spent is met + assert.isTrue(upkeepBefore.eq(upkeepAfter)) + // owner balance does not change + assert.isTrue(ownerAfter.eq(ownerBefore)) + // payee balance does not change + assert.isTrue(payee1Before.eq(payee1After)) + }) + }) + }) + }) + + describe('#withdrawPayment', () => { + beforeEach(async () => { + await linkToken.connect(owner).approve(registry.address, toWei('100')) + await registry.connect(owner).addFunds(upkeepId, toWei('100')) + await getTransmitTx(registry, keeper1, [upkeepId]) + }) + + it('reverts if called by anyone but the payee', async () => { + await evmRevert( + registry + .connect(payee2) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ), + 'OnlyCallableByPayee()', + ) + }) + + it('reverts if called with the 0 address', async () => { + await evmRevert( + registry + .connect(payee2) + .withdrawPayment(await keeper1.getAddress(), zeroAddress), + 'InvalidRecipient()', + ) + }) + + it('updates the balances', async () => { + const to = await nonkeeper.getAddress() + const keeperBefore = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const registrationBefore = (await registry.getUpkeep(upkeepId)).balance + const toLinkBefore = await linkToken.balanceOf(to) + const registryLinkBefore = await linkToken.balanceOf(registry.address) + const registryPremiumBefore = (await registry.getState()).state + .totalPremium + const ownerBefore = (await registry.getState()).state.ownerLinkBalance + + // Withdrawing for first time, last collected = 0 + assert.equal(keeperBefore.lastCollected.toString(), '0') + + //// Do the thing + await registry + .connect(payee1) + .withdrawPayment(await keeper1.getAddress(), to) + + const keeperAfter = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const registrationAfter = (await registry.getUpkeep(upkeepId)).balance + const toLinkAfter = await linkToken.balanceOf(to) + const registryLinkAfter = await linkToken.balanceOf(registry.address) + const registryPremiumAfter = (await registry.getState()).state + .totalPremium + const ownerAfter = (await registry.getState()).state.ownerLinkBalance + + // registry total premium should not change + assert.isTrue(registryPremiumBefore.eq(registryPremiumAfter)) + + // Last collected should be updated to premium-change + assert.isTrue( + keeperAfter.lastCollected.eq( + registryPremiumBefore.sub( + registryPremiumBefore.mod(keeperAddresses.length), + ), + ), + ) + + // owner balance should remain unchanged + assert.isTrue(ownerAfter.eq(ownerBefore)) + + assert.isTrue(keeperAfter.balance.eq(BigNumber.from(0))) + assert.isTrue(registrationBefore.eq(registrationAfter)) + assert.isTrue(toLinkBefore.add(keeperBefore.balance).eq(toLinkAfter)) + assert.isTrue( + registryLinkBefore.sub(keeperBefore.balance).eq(registryLinkAfter), + ) + }) + + it('emits a log announcing the withdrawal', async () => { + const balance = ( + await registry.getTransmitterInfo(await keeper1.getAddress()) + ).balance + const tx = await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + await expect(tx) + .to.emit(registry, 'PaymentWithdrawn') + .withArgs( + await keeper1.getAddress(), + balance, + await nonkeeper.getAddress(), + await payee1.getAddress(), + ) + }) + }) + + describe('#checkCallback', () => { + it('returns false with appropriate failure reason when target callback reverts', async () => { + await streamsLookupUpkeep.setShouldRevertCallback(true) + + const values: any[] = ['0x1234', '0xabcd'] + const res = await registry + .connect(zeroAddress) + .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') + + assert.isFalse(res.upkeepNeeded) + assert.equal(res.performData, '0x') + assert.equal( + res.upkeepFailureReason, + UpkeepFailureReason.CHECK_CALLBACK_REVERTED, + ) + assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + + it('returns false with appropriate failure reason when target callback returns big performData', async () => { + let longBytes = '0x' + for (let i = 0; i <= maxPerformDataSize.toNumber(); i++) { + longBytes += '11' + } + const values: any[] = [longBytes, longBytes] + const res = await registry + .connect(zeroAddress) + .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') + + assert.isFalse(res.upkeepNeeded) + assert.equal(res.performData, '0x') + assert.equal( + res.upkeepFailureReason, + UpkeepFailureReason.PERFORM_DATA_EXCEEDS_LIMIT, + ) + assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + + it('returns false with appropriate failure reason when target callback returns false', async () => { + await streamsLookupUpkeep.setCallbackReturnBool(false) + const values: any[] = ['0x1234', '0xabcd'] + const res = await registry + .connect(zeroAddress) + .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') + + assert.isFalse(res.upkeepNeeded) + assert.equal(res.performData, '0x') + assert.equal( + res.upkeepFailureReason, + UpkeepFailureReason.UPKEEP_NOT_NEEDED, + ) + assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + + it('succeeds with upkeep needed', async () => { + const values: any[] = ['0x1234', '0xabcd'] + + const res = await registry + .connect(zeroAddress) + .callStatic.checkCallback(streamsLookupUpkeepId, values, '0x') + const expectedPerformData = ethers.utils.defaultAbiCoder.encode( + ['bytes[]', 'bytes'], + [values, '0x'], + ) + + assert.isTrue(res.upkeepNeeded) + assert.equal(res.performData, expectedPerformData) + assert.equal(res.upkeepFailureReason, UpkeepFailureReason.NONE) + assert.isTrue(res.gasUsed.gt(BigNumber.from('0'))) // Some gas should be used + }) + }) + + describe('#setUpkeepPrivilegeConfig() / #getUpkeepPrivilegeConfig()', () => { + it('reverts when non manager tries to set privilege config', async () => { + await evmRevert( + registry.connect(payee3).setUpkeepPrivilegeConfig(upkeepId, '0x1234'), + 'OnlyCallableByUpkeepPrivilegeManager()', + ) + }) + + it('returns empty bytes for upkeep privilege config before setting', async () => { + const cfg = await registry.getUpkeepPrivilegeConfig(upkeepId) + assert.equal(cfg, '0x') + }) + + it('allows upkeep manager to set privilege config', async () => { + const tx = await registry + .connect(personas.Norbert) + .setUpkeepPrivilegeConfig(upkeepId, '0x1234') + await expect(tx) + .to.emit(registry, 'UpkeepPrivilegeConfigSet') + .withArgs(upkeepId, '0x1234') + + const cfg = await registry.getUpkeepPrivilegeConfig(upkeepId) + assert.equal(cfg, '0x1234') + }) + }) + + describe('#setAdminPrivilegeConfig() / #getAdminPrivilegeConfig()', () => { + const admin = randomAddress() + + it('reverts when non manager tries to set privilege config', async () => { + await evmRevert( + registry.connect(payee3).setAdminPrivilegeConfig(admin, '0x1234'), + 'OnlyCallableByUpkeepPrivilegeManager()', + ) + }) + + it('returns empty bytes for upkeep privilege config before setting', async () => { + const cfg = await registry.getAdminPrivilegeConfig(admin) + assert.equal(cfg, '0x') + }) + + it('allows upkeep manager to set privilege config', async () => { + const tx = await registry + .connect(personas.Norbert) + .setAdminPrivilegeConfig(admin, '0x1234') + await expect(tx) + .to.emit(registry, 'AdminPrivilegeConfigSet') + .withArgs(admin, '0x1234') + + const cfg = await registry.getAdminPrivilegeConfig(admin) + assert.equal(cfg, '0x1234') + }) + }) + + describe('transmitterPremiumSplit [ @skip-coverage ]', () => { + beforeEach(async () => { + await linkToken.connect(owner).approve(registry.address, toWei('100')) + await registry.connect(owner).addFunds(upkeepId, toWei('100')) + }) + + it('splits premium evenly across transmitters', async () => { + // Do a transmit from keeper1 + await getTransmitTx(registry, keeper1, [upkeepId]) + + const registryPremium = (await registry.getState()).state.totalPremium + assert.isTrue(registryPremium.gt(BigNumber.from(0))) + + const premiumPerTransmitter = registryPremium.div( + BigNumber.from(keeperAddresses.length), + ) + const k1Balance = ( + await registry.getTransmitterInfo(await keeper1.getAddress()) + ).balance + // transmitter should be reimbursed for gas and get the premium + assert.isTrue(k1Balance.gt(premiumPerTransmitter)) + const k1GasReimbursement = k1Balance.sub(premiumPerTransmitter) + + const k2Balance = ( + await registry.getTransmitterInfo(await keeper2.getAddress()) + ).balance + // non transmitter should get its share of premium + assert.isTrue(k2Balance.eq(premiumPerTransmitter)) + + // Now do a transmit from keeper 2 + await getTransmitTx(registry, keeper2, [upkeepId]) + const registryPremiumNew = (await registry.getState()).state.totalPremium + assert.isTrue(registryPremiumNew.gt(registryPremium)) + const premiumPerTransmitterNew = registryPremiumNew.div( + BigNumber.from(keeperAddresses.length), + ) + const additionalPremium = premiumPerTransmitterNew.sub( + premiumPerTransmitter, + ) + + const k1BalanceNew = ( + await registry.getTransmitterInfo(await keeper1.getAddress()) + ).balance + // k1 should get the new premium + assert.isTrue( + k1BalanceNew.eq(k1GasReimbursement.add(premiumPerTransmitterNew)), + ) + + const k2BalanceNew = ( + await registry.getTransmitterInfo(await keeper2.getAddress()) + ).balance + // k2 should get gas reimbursement in addition to new premium + assert.isTrue(k2BalanceNew.gt(k2Balance.add(additionalPremium))) + }) + + it('updates last collected upon payment withdrawn', async () => { + // Do a transmit from keeper1 + await getTransmitTx(registry, keeper1, [upkeepId]) + + const registryPremium = (await registry.getState()).state.totalPremium + const k1 = await registry.getTransmitterInfo(await keeper1.getAddress()) + const k2 = await registry.getTransmitterInfo(await keeper2.getAddress()) + + // Withdrawing for first time, last collected = 0 + assert.isTrue(k1.lastCollected.eq(BigNumber.from(0))) + assert.isTrue(k2.lastCollected.eq(BigNumber.from(0))) + + //// Do the thing + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + + const k1New = await registry.getTransmitterInfo( + await keeper1.getAddress(), + ) + const k2New = await registry.getTransmitterInfo( + await keeper2.getAddress(), + ) + + // transmitter info lastCollected should be updated for k1, not for k2 + assert.isTrue( + k1New.lastCollected.eq( + registryPremium.sub(registryPremium.mod(keeperAddresses.length)), + ), + ) + assert.isTrue(k2New.lastCollected.eq(BigNumber.from(0))) + }) + + itMaybe( + 'maintains consistent balance information across all parties', + async () => { + // throughout transmits, withdrawals, setConfigs total claim on balances should remain less than expected balance + // some spare change can get lost but it should be less than maxAllowedSpareChange + + let maxAllowedSpareChange = BigNumber.from('0') + await verifyConsistentAccounting(maxAllowedSpareChange) + + await getTransmitTx(registry, keeper1, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee2) + .withdrawPayment( + await keeper2.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await getTransmitTx(registry, keeper1, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('31')) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry.connect(owner).setConfigTypeSafe( + signerAddresses.slice(2, 15), // only use 2-14th index keepers + keeperAddresses.slice(2, 15), + f, + config, + offchainVersion, + offchainBytes, + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await getTransmitTx(registry, keeper3, [upkeepId], { + startingSignerIndex: 2, + }) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('13')) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee3) + .withdrawPayment( + await keeper3.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry.connect(owner).setConfigTypeSafe( + signerAddresses.slice(0, 4), // only use 0-3rd index keepers + keeperAddresses.slice(0, 4), + f, + config, + offchainVersion, + offchainBytes, + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + await getTransmitTx(registry, keeper1, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) + await getTransmitTx(registry, keeper3, [upkeepId]) + maxAllowedSpareChange = maxAllowedSpareChange.add(BigNumber.from('4')) + + await verifyConsistentAccounting(maxAllowedSpareChange) + await registry + .connect(payee5) + .withdrawPayment( + await keeper5.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + + await registry + .connect(payee1) + .withdrawPayment( + await keeper1.getAddress(), + await nonkeeper.getAddress(), + ) + await verifyConsistentAccounting(maxAllowedSpareChange) + }, + ) + }) +}) diff --git a/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts b/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts index 76a3dcfff1b..2627bee34a3 100644 --- a/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts +++ b/contracts/test/v0.8/automation/LinkAvailableBalanceMonitor.test.ts @@ -26,8 +26,6 @@ const TARGET_PERFORM_GAS_LIMIT = 2_000_000 const TARGET_CHECK_GAS_LIMIT = 3_500_000 // // ////////////////////////////////////////////////////////////////////////////////////////////////// - -const OWNABLE_ERR = 'Only callable by owner' const INVALID_WATCHLIST_ERR = `InvalidWatchList()` const PAUSED_ERR = 'Pausable: paused' @@ -35,7 +33,6 @@ const zeroLINK = ethers.utils.parseEther('0') const oneLINK = ethers.utils.parseEther('1') const twoLINK = ethers.utils.parseEther('2') const fourLINK = ethers.utils.parseEther('4') -const fiveLINK = ethers.utils.parseEther('5') const tenLINK = ethers.utils.parseEther('10') const oneHundredLINK = ethers.utils.parseEther('100') @@ -61,6 +58,7 @@ let directTarget2: MockContract let watchListAddresses: string[] let watchListMinBalances: BigNumber[] let watchListTopUpAmounts: BigNumber[] +let watchListDstChainSelectors: number[] async function assertContractLinkBalances( balance1: BigNumber, @@ -123,6 +121,7 @@ const setup = async () => { ] watchListMinBalances = [oneLINK, oneLINK, oneLINK, twoLINK, twoLINK] watchListTopUpAmounts = [twoLINK, twoLINK, twoLINK, twoLINK, twoLINK] + watchListDstChainSelectors = [1, 2, 3, 4, 5] await proxy1.mock.aggregator.returns(aggregator1.address) await proxy2.mock.aggregator.returns(aggregator2.address) @@ -152,6 +151,7 @@ const setup = async () => { lt = (await ltFactory.deploy()) as LinkToken labm = await labmFactory.deploy( + owner.address, lt.address, minWaitPeriodSeconds, maxPerform, @@ -171,6 +171,7 @@ const setup = async () => { watchListAddresses, watchListMinBalances, watchListTopUpAmounts, + watchListDstChainSelectors, ) await setTx.wait() } @@ -223,6 +224,42 @@ describe('LinkAvailableBalanceMonitor', () => { }) }) + describe('setMaxPerform()', () => { + it('configures the MaxPerform', async () => { + await labm.connect(owner).setMaxPerform(BigNumber.from(100)) + const report = await labm.getMaxPerform() + assert.equal(report.toString(), '100') + }) + + it('is only callable by the owner', async () => { + await expect(labm.connect(stranger).setMaxPerform(100)).to.be.reverted + }) + }) + + describe('setMaxCheck()', () => { + it('configures the MaxCheck', async () => { + await labm.connect(owner).setMaxCheck(BigNumber.from(100)) + const report = await labm.getMaxCheck() + assert.equal(report.toString(), '100') + }) + + it('is only callable by the owner', async () => { + await expect(labm.connect(stranger).setMaxCheck(100)).to.be.reverted + }) + }) + + describe('setUpkeepInterval()', () => { + it('configures the UpkeepInterval', async () => { + await labm.connect(owner).setUpkeepInterval(BigNumber.from(100)) + const report = await labm.getUpkeepInterval() + assert.equal(report.toString(), '100') + }) + + it('is only callable by the owner', async () => { + await expect(labm.connect(stranger).setUpkeepInterval(100)).to.be.reverted + }) + }) + describe('withdraw()', () => { beforeEach(async () => { const tx = await lt.connect(owner).transfer(labm.address, oneLINK) @@ -260,7 +297,7 @@ describe('LinkAvailableBalanceMonitor', () => { it('Should not allow strangers to withdraw', async () => { const tx = labm.connect(stranger).withdraw(oneLINK, owner.address) - await expect(tx).to.be.revertedWith(OWNABLE_ERR) + await expect(tx).to.be.reverted }) }) @@ -274,22 +311,22 @@ describe('LinkAvailableBalanceMonitor', () => { it('Should not allow strangers to pause / unpause', async () => { const pauseTxStranger = labm.connect(stranger).pause() - await expect(pauseTxStranger).to.be.revertedWith(OWNABLE_ERR) + await expect(pauseTxStranger).to.be.reverted const pauseTxOwner = await labm.connect(owner).pause() await pauseTxOwner.wait() const unpauseTxStranger = labm.connect(stranger).unpause() - await expect(unpauseTxStranger).to.be.revertedWith(OWNABLE_ERR) + await expect(unpauseTxStranger).to.be.reverted }) }) - describe('setWatchList() / addToWatchList() / removeFromWatchlist() / getWatchList()', () => { + describe('setWatchList() / addToWatchListOrDecomissionOrDecomission() / removeFromWatchlist() / getWatchList()', () => { const watchAddress1 = randAddr() const watchAddress2 = randAddr() const watchAddress3 = randAddr() beforeEach(async () => { // reset watchlist to empty before running these tests - await labm.connect(owner).setWatchList([], [], []) + await labm.connect(owner).setWatchList([], [], [], []) const watchList = await labm.getWatchList() assert.deepEqual(watchList, []) }) @@ -298,7 +335,7 @@ describe('LinkAvailableBalanceMonitor', () => { // add first watchlist let tx = await labm .connect(owner) - .setWatchList([watchAddress1], [oneLINK], [oneLINK]) + .setWatchList([watchAddress1], [oneLINK], [oneLINK], [0]) let watchList = await labm.getWatchList() assert.deepEqual(watchList[0], watchAddress1) // add more to watchlist @@ -308,6 +345,7 @@ describe('LinkAvailableBalanceMonitor', () => { [watchAddress1, watchAddress2, watchAddress3], [oneLINK, oneLINK, oneLINK], [oneLINK, oneLINK, oneLINK], + [1, 2, 3], ) await tx.wait() watchList = await labm.getWatchList() @@ -322,6 +360,7 @@ describe('LinkAvailableBalanceMonitor', () => { [watchAddress1, watchAddress2, watchAddress1], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) await expect(tx).to.be.revertedWith(errMsg) }) @@ -334,6 +373,7 @@ describe('LinkAvailableBalanceMonitor', () => { [watchAddress1, watchAddress2, watchAddress1], [oneLINK, oneLINK, oneLINK], [oneLINK, oneLINK, oneLINK], + [1, 2, 3], ) await expect(tx).to.be.revertedWith(errMsg) }) @@ -341,8 +381,8 @@ describe('LinkAvailableBalanceMonitor', () => { it('Should not allow strangers to set the watchlist', async () => { const setTxStranger = labm .connect(stranger) - .setWatchList([watchAddress1], [oneLINK], [oneLINK]) - await expect(setTxStranger).to.be.revertedWith(OWNABLE_ERR) + .setWatchList([watchAddress1], [oneLINK], [oneLINK], [0]) + await expect(setTxStranger).to.be.reverted }) it('Should revert if any of the addresses are empty', async () => { @@ -352,9 +392,143 @@ describe('LinkAvailableBalanceMonitor', () => { [watchAddress1, ethers.constants.AddressZero], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) await expect(tx).to.be.revertedWith(INVALID_WATCHLIST_ERR) }) + + it('Should allow owner to add multiple addresses with dstChainSelector 0 to the watchlist', async () => { + let tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress1, 0) + await tx.wait + let watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress1) + + tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress2, 0) + await tx.wait + watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress1) + assert.deepEqual(watchList[1], watchAddress2) + + tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress3, 0) + await tx.wait + watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress1) + assert.deepEqual(watchList[1], watchAddress2) + assert.deepEqual(watchList[2], watchAddress3) + }) + + it('Should allow owner to add only one address with an unique non-zero dstChainSelector 0 to the watchlist', async () => { + let tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress1, 1) + await tx.wait + let watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress1) + + // 1 is active + let report = await labm.getAccountInfo(watchAddress1) + assert.isTrue(report.isActive) + + tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress2, 1) + await tx.wait + watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress2) + + // 2 is active, 1 should be false + report = await labm.getAccountInfo(watchAddress2) + assert.isTrue(report.isActive) + report = await labm.getAccountInfo(watchAddress1) + assert.isFalse(report.isActive) + + tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress3, 1) + await tx.wait + watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress3) + + // 3 is active, 1 and 2 should be false + report = await labm.getAccountInfo(watchAddress3) + assert.isTrue(report.isActive) + report = await labm.getAccountInfo(watchAddress2) + assert.isFalse(report.isActive) + report = await labm.getAccountInfo(watchAddress1) + assert.isFalse(report.isActive) + }) + + it('Should not add address 0 to the watchlist', async () => { + await labm + .connect(owner) + .addToWatchListOrDecomission(ethers.constants.AddressZero, 1) + expect(await labm.getWatchList()).to.not.contain( + ethers.constants.AddressZero, + ) + }) + + it('Should not allow stangers to add addresses to the watchlist', async () => { + await expect( + labm.connect(stranger).addToWatchListOrDecomission(watchAddress1, 1), + ).to.be.reverted + }) + + it('Should allow owner to remove addresses from the watchlist', async () => { + let tx = await labm + .connect(owner) + .addToWatchListOrDecomission(watchAddress1, 1) + await tx.wait + let watchList = await labm.getWatchList() + assert.deepEqual(watchList[0], watchAddress1) + let report = await labm.getAccountInfo(watchAddress1) + assert.isTrue(report.isActive) + + // remove address + tx = await labm.connect(owner).removeFromWatchList(watchAddress1) + + // address should be false + report = await labm.getAccountInfo(watchAddress1) + assert.isFalse(report.isActive) + + watchList = await labm.getWatchList() + assert.deepEqual(watchList, []) + }) + + it('Should allow only one address per dstChainSelector', async () => { + // add address1 + await labm.connect(owner).addToWatchListOrDecomission(watchAddress1, 1) + expect(await labm.getWatchList()).to.contain(watchAddress1) + + // add address2 + await labm.connect(owner).addToWatchListOrDecomission(watchAddress2, 1) + + // only address2 has to be in the watchlist + const watchlist = await labm.getWatchList() + expect(watchlist).to.not.contain(watchAddress1) + expect(watchlist).to.contain(watchAddress2) + }) + + it('Should delete the onRamp address on a zero-address with same dstChainSelector', async () => { + // add address1 + await labm.connect(owner).addToWatchListOrDecomission(watchAddress1, 1) + expect(await labm.getWatchList()).to.contain(watchAddress1) + + // simulates an onRampSet(zeroAddress, same dstChainSelector) + await labm + .connect(owner) + .addToWatchListOrDecomission(ethers.constants.AddressZero, 1) + + // address1 should be cleaned + const watchlist = await labm.getWatchList() + expect(watchlist).to.not.contain(watchAddress1) + assert.deepEqual(watchlist, []) + }) }) describe('checkUpkeep() / sampleUnderfundedAddresses() [ @skip-coverage ]', () => { @@ -368,6 +542,7 @@ describe('LinkAvailableBalanceMonitor', () => { watchListAddresses, watchListMinBalances, watchListTopUpAmounts, + watchListDstChainSelectors, ) const [should, payload] = await labm.checkUpkeep('0x') @@ -393,6 +568,7 @@ describe('LinkAvailableBalanceMonitor', () => { [aggregator2.address, directTarget1.address, directTarget2.address], [oneLINK, twoLINK, twoLINK], [oneLINK, oneLINK, oneLINK], + [1, 2, 3], ) // all of them are underfunded, return 3 @@ -441,6 +617,7 @@ describe('LinkAvailableBalanceMonitor', () => { let minBalances: BigNumber[] let topUpAmount: BigNumber[] let aggregators: MockContract[] + let dstChainSelectors: number[] beforeEach(async () => { MAX_PERFORM = await labm.getMaxPerform() @@ -449,6 +626,7 @@ describe('LinkAvailableBalanceMonitor', () => { minBalances = [] topUpAmount = [] aggregators = [] + dstChainSelectors = [] const numAggregators = MAX_CHECK + 50 for (let idx = 0; idx < numAggregators; idx++) { const proxy = await deployMockContract( @@ -465,8 +643,14 @@ describe('LinkAvailableBalanceMonitor', () => { minBalances.push(oneLINK) topUpAmount.push(oneLINK) aggregators.push(aggregator) + dstChainSelectors.push(0) } - await labm.setWatchList(proxyAddresses, minBalances, topUpAmount) + await labm.setWatchList( + proxyAddresses, + minBalances, + topUpAmount, + dstChainSelectors, + ) let watchlist = await labm.getWatchList() expect(watchlist).to.deep.equalInAnyOrder(proxyAddresses) assert.equal(watchlist.length, minBalances.length) @@ -521,6 +705,7 @@ describe('LinkAvailableBalanceMonitor', () => { watchListAddresses, watchListMinBalances, watchListTopUpAmounts, + watchListDstChainSelectors, ) }) @@ -563,6 +748,7 @@ describe('LinkAvailableBalanceMonitor', () => { const proxyAddresses = [] const minBalances = [] const topUpAmount = [] + const dstChainSelectors = [] for (let idx = 0; idx < MAX_PERFORM; idx++) { const proxy = await deployMockContract( owner, @@ -577,8 +763,14 @@ describe('LinkAvailableBalanceMonitor', () => { proxyAddresses.push(proxy.address) minBalances.push(oneLINK) topUpAmount.push(oneLINK) + dstChainSelectors.push(0) } - await labm.setWatchList(proxyAddresses, minBalances, topUpAmount) + await labm.setWatchList( + proxyAddresses, + minBalances, + topUpAmount, + dstChainSelectors, + ) let watchlist = await labm.getWatchList() expect(watchlist).to.deep.equalInAnyOrder(proxyAddresses) assert.equal(watchlist.length, minBalances.length) @@ -691,6 +883,7 @@ describe('LinkAvailableBalanceMonitor', () => { [proxy1.address, directTarget1.address], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) const tx = await labm .connect(keeperRegistry) @@ -728,6 +921,7 @@ describe('LinkAvailableBalanceMonitor', () => { [proxy1.address, proxy4.address], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) const tx = await labm .connect(keeperRegistry) @@ -746,6 +940,7 @@ describe('LinkAvailableBalanceMonitor', () => { [proxy1.address, proxy4.address], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) const tx = await labm .connect(keeperRegistry) @@ -765,6 +960,7 @@ describe('LinkAvailableBalanceMonitor', () => { [proxy1.address, proxy4.address], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) const tx = await labm .connect(keeperRegistry) @@ -783,6 +979,7 @@ describe('LinkAvailableBalanceMonitor', () => { [proxy1.address, directTarget1.address], [oneLINK, oneLINK], [oneLINK, oneLINK], + [1, 2], ) const tx = await labm .connect(keeperRegistry) diff --git a/contracts/test/v0.8/automation/helpers.ts b/contracts/test/v0.8/automation/helpers.ts index e2aa762577a..3490bc72c4d 100644 --- a/contracts/test/v0.8/automation/helpers.ts +++ b/contracts/test/v0.8/automation/helpers.ts @@ -3,6 +3,9 @@ import { ethers } from 'hardhat' import { KeeperRegistryLogicB2_1__factory as KeeperRegistryLogicBFactory } from '../../../typechain/factories/KeeperRegistryLogicB2_1__factory' import { IKeeperRegistryMaster as IKeeperRegistry } from '../../../typechain/IKeeperRegistryMaster' import { IKeeperRegistryMaster__factory as IKeeperRegistryMasterFactory } from '../../../typechain/factories/IKeeperRegistryMaster__factory' +import { AutomationRegistryLogicB2_2__factory as AutomationRegistryLogicBFactory } from '../../../typechain/factories/AutomationRegistryLogicB2_2__factory' +import { IAutomationRegistryMaster as IAutomationRegistry } from '../../../typechain/IAutomationRegistryMaster' +import { IAutomationRegistryMaster__factory as IAutomationRegistryMasterFactory } from '../../../typechain/factories/IAutomationRegistryMaster__factory' export const deployRegistry21 = async ( from: Signer, @@ -29,3 +32,31 @@ export const deployRegistry21 = async ( const master = await registryFactory.connect(from).deploy(logicA.address) return IKeeperRegistryMasterFactory.connect(master.address, from) } + +export const deployRegistry22 = async ( + from: Signer, + mode: Parameters[0], + link: Parameters[1], + linkNative: Parameters[2], + fastgas: Parameters[3], +): Promise => { + const logicBFactory = await ethers.getContractFactory( + 'AutomationRegistryLogicB2_2', + ) + const logicAFactory = await ethers.getContractFactory( + 'AutomationRegistryLogicA2_2', + ) + const registryFactory = await ethers.getContractFactory( + 'AutomationRegistry2_2', + ) + const forwarderLogicFactory = await ethers.getContractFactory( + 'AutomationForwarderLogic', + ) + const forwarderLogic = await forwarderLogicFactory.connect(from).deploy() + const logicB = await logicBFactory + .connect(from) + .deploy(mode, link, linkNative, fastgas, forwarderLogic.address) + const logicA = await logicAFactory.connect(from).deploy(logicB.address) + const master = await registryFactory.connect(from).deploy(logicA.address) + return IAutomationRegistryMasterFactory.connect(master.address, from) +} diff --git a/contracts/test/v0.8/dev/ScrollCrossDomainForwarder.test.ts b/contracts/test/v0.8/dev/ScrollCrossDomainForwarder.test.ts new file mode 100644 index 00000000000..923d41326ae --- /dev/null +++ b/contracts/test/v0.8/dev/ScrollCrossDomainForwarder.test.ts @@ -0,0 +1,259 @@ +import { ethers } from 'hardhat' +import { assert, expect } from 'chai' +import { Contract, ContractFactory } from 'ethers' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { publicAbi } from '../../test-helpers/helpers' + +let owner: SignerWithAddress +let stranger: SignerWithAddress +let l1OwnerAddress: string +let newL1OwnerAddress: string +let forwarderFactory: ContractFactory +let greeterFactory: ContractFactory +let crossDomainMessengerFactory: ContractFactory +let crossDomainMessenger: Contract +let forwarder: Contract +let greeter: Contract + +before(async () => { + const accounts = await ethers.getSigners() + owner = accounts[0] + stranger = accounts[1] + + // forwarder config + l1OwnerAddress = owner.address + newL1OwnerAddress = stranger.address + + // Contract factories + forwarderFactory = await ethers.getContractFactory( + 'src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol:ScrollCrossDomainForwarder', + owner, + ) + greeterFactory = await ethers.getContractFactory( + 'src/v0.8/tests/Greeter.sol:Greeter', + owner, + ) + crossDomainMessengerFactory = await ethers.getContractFactory( + 'src/v0.8/vendor/MockScrollCrossDomainMessenger.sol:MockScrollCrossDomainMessenger', + ) +}) + +describe('ScrollCrossDomainForwarder', () => { + beforeEach(async () => { + crossDomainMessenger = + await crossDomainMessengerFactory.deploy(l1OwnerAddress) + forwarder = await forwarderFactory.deploy( + crossDomainMessenger.address, + l1OwnerAddress, + ) + greeter = await greeterFactory.deploy(forwarder.address) + }) + + it('has a limited public interface [ @skip-coverage ]', async () => { + publicAbi(forwarder, [ + 'typeAndVersion', + 'crossDomainMessenger', + 'forward', + 'l1Owner', + 'transferL1Ownership', + 'acceptL1Ownership', + // ConfirmedOwner methods: + 'owner', + 'transferOwnership', + 'acceptOwnership', + ]) + }) + + describe('#constructor', () => { + it('should set the owner correctly', async () => { + const response = await forwarder.owner() + assert.equal(response, owner.address) + }) + + it('should set the l1Owner correctly', async () => { + const response = await forwarder.l1Owner() + assert.equal(response, l1OwnerAddress) + }) + + it('should set the crossdomain messenger correctly', async () => { + const response = await forwarder.crossDomainMessenger() + assert.equal(response, crossDomainMessenger.address) + }) + + it('should set the typeAndVersion correctly', async () => { + const response = await forwarder.typeAndVersion() + assert.equal(response, 'ScrollCrossDomainForwarder 1.0.0') + }) + }) + + describe('#forward', () => { + it('should not be callable by unknown address', async () => { + await expect( + forwarder.connect(stranger).forward(greeter.address, '0x'), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should be callable by crossdomain messenger address / L1 owner', async () => { + const newGreeting = 'hello' + const setGreetingData = greeterFactory.interface.encodeFunctionData( + 'setGreeting', + [newGreeting], + ) + const forwardData = forwarderFactory.interface.encodeFunctionData( + 'forward', + [greeter.address, setGreetingData], + ) + await crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ) + + const updatedGreeting = await greeter.greeting() + assert.equal(updatedGreeting, newGreeting) + }) + + it('should revert when contract call reverts', async () => { + const setGreetingData = greeterFactory.interface.encodeFunctionData( + 'setGreeting', + [''], + ) + const forwardData = forwarderFactory.interface.encodeFunctionData( + 'forward', + [greeter.address, setGreetingData], + ) + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Invalid greeting length') + }) + }) + + describe('#transferL1Ownership', () => { + it('should not be callable by non-owners', async () => { + await expect( + forwarder.connect(stranger).transferL1Ownership(stranger.address), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should not be callable by L2 owner', async () => { + const forwarderOwner = await forwarder.owner() + assert.equal(forwarderOwner, owner.address) + + await expect( + forwarder.connect(owner).transferL1Ownership(stranger.address), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should be callable by current L1 owner', async () => { + const currentL1Owner = await forwarder.l1Owner() + const forwardData = forwarderFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [newL1OwnerAddress], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ) + .to.emit(forwarder, 'L1OwnershipTransferRequested') + .withArgs(currentL1Owner, newL1OwnerAddress) + }) + + it('should be callable by current L1 owner to zero address', async () => { + const currentL1Owner = await forwarder.l1Owner() + const forwardData = forwarderFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [ethers.constants.AddressZero], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ) + .to.emit(forwarder, 'L1OwnershipTransferRequested') + .withArgs(currentL1Owner, ethers.constants.AddressZero) + }) + }) + + describe('#acceptL1Ownership', () => { + it('should not be callable by non pending-owners', async () => { + const forwardData = forwarderFactory.interface.encodeFunctionData( + 'acceptL1Ownership', + [], + ) + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Must be proposed L1 owner') + }) + + it('should be callable by pending L1 owner', async () => { + const currentL1Owner = await forwarder.l1Owner() + + // Transfer ownership + const forwardTransferData = forwarderFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [newL1OwnerAddress], + ) + await crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardTransferData, // message + 0, // gasLimit + ) + + const forwardAcceptData = forwarderFactory.interface.encodeFunctionData( + 'acceptL1Ownership', + [], + ) + // Simulate cross-chain message from another sender + await crossDomainMessenger._setMockMessageSender(newL1OwnerAddress) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + forwarder.address, // target + 0, // value + forwardAcceptData, // message + 0, // gasLimit + ), + ) + .to.emit(forwarder, 'L1OwnershipTransferred') + .withArgs(currentL1Owner, newL1OwnerAddress) + + const updatedL1Owner = await forwarder.l1Owner() + assert.equal(updatedL1Owner, newL1OwnerAddress) + }) + }) +}) diff --git a/contracts/test/v0.8/dev/ScrollCrossDomainGovernor.test.ts b/contracts/test/v0.8/dev/ScrollCrossDomainGovernor.test.ts new file mode 100644 index 00000000000..adb78c26248 --- /dev/null +++ b/contracts/test/v0.8/dev/ScrollCrossDomainGovernor.test.ts @@ -0,0 +1,459 @@ +import { ethers } from 'hardhat' +import { assert, expect } from 'chai' +import etherslib, { Contract, ContractFactory } from 'ethers' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { publicAbi, stripHexPrefix } from '../../test-helpers/helpers' + +let owner: SignerWithAddress +let stranger: SignerWithAddress +let l1OwnerAddress: string +let newL1OwnerAddress: string +let governorFactory: ContractFactory +let greeterFactory: ContractFactory +let multisendFactory: ContractFactory +let crossDomainMessengerFactory: ContractFactory +let crossDomainMessenger: Contract +let governor: Contract +let greeter: Contract +let multisend: Contract + +before(async () => { + const accounts = await ethers.getSigners() + owner = accounts[0] + stranger = accounts[1] + + // governor config + l1OwnerAddress = owner.address + newL1OwnerAddress = stranger.address + + // Contract factories + governorFactory = await ethers.getContractFactory( + 'src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol:ScrollCrossDomainGovernor', + owner, + ) + greeterFactory = await ethers.getContractFactory( + 'src/v0.8/tests/Greeter.sol:Greeter', + owner, + ) + multisendFactory = await ethers.getContractFactory( + 'src/v0.8/vendor/MultiSend.sol:MultiSend', + owner, + ) + crossDomainMessengerFactory = await ethers.getContractFactory( + 'src/v0.8/vendor/MockScrollCrossDomainMessenger.sol:MockScrollCrossDomainMessenger', + ) +}) + +describe('ScrollCrossDomainGovernor', () => { + beforeEach(async () => { + crossDomainMessenger = + await crossDomainMessengerFactory.deploy(l1OwnerAddress) + governor = await governorFactory.deploy( + crossDomainMessenger.address, + l1OwnerAddress, + ) + greeter = await greeterFactory.deploy(governor.address) + multisend = await multisendFactory.deploy() + }) + + it('has a limited public interface [ @skip-coverage ]', async () => { + publicAbi(governor, [ + 'typeAndVersion', + 'crossDomainMessenger', + 'forward', + 'forwardDelegate', + 'l1Owner', + 'transferL1Ownership', + 'acceptL1Ownership', + // ConfirmedOwner methods: + 'owner', + 'transferOwnership', + 'acceptOwnership', + ]) + }) + + describe('#constructor', () => { + it('should set the owner correctly', async () => { + const response = await governor.owner() + assert.equal(response, owner.address) + }) + + it('should set the l1Owner correctly', async () => { + const response = await governor.l1Owner() + assert.equal(response, l1OwnerAddress) + }) + + it('should set the crossdomain messenger correctly', async () => { + const response = await governor.crossDomainMessenger() + assert.equal(response, crossDomainMessenger.address) + }) + + it('should set the typeAndVersion correctly', async () => { + const response = await governor.typeAndVersion() + assert.equal(response, 'ScrollCrossDomainGovernor 1.0.0') + }) + }) + + describe('#forward', () => { + it('should not be callable by unknown address', async () => { + await expect( + governor.connect(stranger).forward(greeter.address, '0x'), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should be callable by crossdomain messenger address / L1 owner', async () => { + const newGreeting = 'hello' + const setGreetingData = greeterFactory.interface.encodeFunctionData( + 'setGreeting', + [newGreeting], + ) + const forwardData = governorFactory.interface.encodeFunctionData( + 'forward', + [greeter.address, setGreetingData], + ) + await crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ) + + const updatedGreeting = await greeter.greeting() + assert.equal(updatedGreeting, newGreeting) + }) + + it('should be callable by L2 owner', async () => { + const newGreeting = 'hello' + const setGreetingData = greeterFactory.interface.encodeFunctionData( + 'setGreeting', + [newGreeting], + ) + await governor.connect(owner).forward(greeter.address, setGreetingData) + + const updatedGreeting = await greeter.greeting() + assert.equal(updatedGreeting, newGreeting) + }) + + it('should revert when contract call reverts', async () => { + const setGreetingData = greeterFactory.interface.encodeFunctionData( + 'setGreeting', + [''], + ) + const forwardData = governorFactory.interface.encodeFunctionData( + 'forward', + [greeter.address, setGreetingData], + ) + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Invalid greeting length') + }) + }) + + describe('#forwardDelegate', () => { + it('should not be callable by unknown address', async () => { + await expect( + governor.connect(stranger).forwardDelegate(multisend.address, '0x'), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should be callable by crossdomain messenger address / L1 owner', async () => { + const calls = [ + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + 'foo', + ]), + value: 0, + }, + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + 'bar', + ]), + value: 0, + }, + ] + const multisendData = encodeMultisendData(multisend.interface, calls) + const forwardData = governorFactory.interface.encodeFunctionData( + 'forwardDelegate', + [multisend.address, multisendData], + ) + + await crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ) + + const updatedGreeting = await greeter.greeting() + assert.equal(updatedGreeting, 'bar') + }) + + it('should be callable by L2 owner', async () => { + const calls = [ + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + 'foo', + ]), + value: 0, + }, + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + 'bar', + ]), + value: 0, + }, + ] + const multisendData = encodeMultisendData(multisend.interface, calls) + await governor + .connect(owner) + .forwardDelegate(multisend.address, multisendData) + + const updatedGreeting = await greeter.greeting() + assert.equal(updatedGreeting, 'bar') + }) + + it('should revert batch when one call fails', async () => { + const calls = [ + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + 'foo', + ]), + value: 0, + }, + { + to: greeter.address, + data: greeterFactory.interface.encodeFunctionData('setGreeting', [ + '', // should revert + ]), + value: 0, + }, + ] + const multisendData = encodeMultisendData(multisend.interface, calls) + const forwardData = governorFactory.interface.encodeFunctionData( + 'forwardDelegate', + [multisend.address, multisendData], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Governor delegatecall reverted') + + const greeting = await greeter.greeting() + assert.equal(greeting, '') // Unchanged + }) + + it('should bubble up revert when contract call reverts', async () => { + const triggerRevertData = + greeterFactory.interface.encodeFunctionData('triggerRevert') + const forwardData = governorFactory.interface.encodeFunctionData( + 'forwardDelegate', + [greeter.address, triggerRevertData], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Greeter: revert triggered') + }) + }) + + describe('#transferL1Ownership', () => { + it('should not be callable by non-owners', async () => { + await expect( + governor.connect(stranger).transferL1Ownership(stranger.address), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should not be callable by L2 owner', async () => { + const governorOwner = await governor.owner() + assert.equal(governorOwner, owner.address) + + await expect( + governor.connect(owner).transferL1Ownership(stranger.address), + ).to.be.revertedWith('Sender is not the L2 messenger') + }) + + it('should be callable by current L1 owner', async () => { + const currentL1Owner = await governor.l1Owner() + const forwardData = governorFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [newL1OwnerAddress], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ) + .to.emit(governor, 'L1OwnershipTransferRequested') + .withArgs(currentL1Owner, newL1OwnerAddress) + }) + + it('should be callable by current L1 owner to zero address', async () => { + const currentL1Owner = await governor.l1Owner() + const forwardData = governorFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [ethers.constants.AddressZero], + ) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ) + .to.emit(governor, 'L1OwnershipTransferRequested') + .withArgs(currentL1Owner, ethers.constants.AddressZero) + }) + }) + + describe('#acceptL1Ownership', () => { + it('should not be callable by non pending-owners', async () => { + const forwardData = governorFactory.interface.encodeFunctionData( + 'acceptL1Ownership', + [], + ) + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardData, // message + 0, // gasLimit + ), + ).to.be.revertedWith('Must be proposed L1 owner') + }) + + it('should be callable by pending L1 owner', async () => { + const currentL1Owner = await governor.l1Owner() + + // Transfer ownership + const forwardTransferData = governorFactory.interface.encodeFunctionData( + 'transferL1Ownership', + [newL1OwnerAddress], + ) + await crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardTransferData, // message + 0, // gasLimit + ) + + const forwardAcceptData = governorFactory.interface.encodeFunctionData( + 'acceptL1Ownership', + [], + ) + // Simulate cross-chain message from another sender + await crossDomainMessenger._setMockMessageSender(newL1OwnerAddress) + + await expect( + crossDomainMessenger // Simulate cross-chain message + .connect(stranger) + ['sendMessage(address,uint256,bytes,uint256)']( + governor.address, // target + 0, // value + forwardAcceptData, // message + 0, // gasLimit + ), + ) + .to.emit(governor, 'L1OwnershipTransferred') + .withArgs(currentL1Owner, newL1OwnerAddress) + + const updatedL1Owner = await governor.l1Owner() + assert.equal(updatedL1Owner, newL1OwnerAddress) + }) + }) +}) + +// Multisend contract helpers + +/** + * Encodes an underlying transaction for the Multisend contract + * + * @param operation 0 for CALL, 1 for DELEGATECALL + * @param to tx target address + * @param value tx value + * @param data tx data + */ +export function encodeTxData( + operation: number, + to: string, + value: number, + data: string, +): string { + const dataBuffer = Buffer.from(stripHexPrefix(data), 'hex') + const types = ['uint8', 'address', 'uint256', 'uint256', 'bytes'] + const values = [operation, to, value, dataBuffer.length, dataBuffer] + const encoded = ethers.utils.solidityPack(types, values) + return stripHexPrefix(encoded) +} + +/** + * Encodes a Multisend call + * + * @param MultisendInterface Ethers Interface object of the Multisend contract + * @param transactions one or more transactions to include in the Multisend call + * @param to tx target address + * @param value tx value + * @param data tx data + */ +export function encodeMultisendData( + MultisendInterface: etherslib.utils.Interface, + transactions: { to: string; value: number; data: string }[], +): string { + let nestedTransactionData = '0x' + for (const transaction of transactions) { + nestedTransactionData += encodeTxData( + 0, + transaction.to, + transaction.value, + transaction.data, + ) + } + const encodedMultisendFnData = MultisendInterface.encodeFunctionData( + 'multiSend', + [nestedTransactionData], + ) + return encodedMultisendFnData +} diff --git a/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts b/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts new file mode 100644 index 00000000000..1d93497b9fa --- /dev/null +++ b/contracts/test/v0.8/dev/ScrollSequencerUptimeFeed.test.ts @@ -0,0 +1,426 @@ +import { ethers, network } from 'hardhat' +import { BigNumber, Contract } from 'ethers' +import { expect } from 'chai' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' + +describe('ScrollSequencerUptimeFeed', () => { + let l2CrossDomainMessenger: Contract + let scrollUptimeFeed: Contract + let uptimeFeedConsumer: Contract + let deployer: SignerWithAddress + let l1Owner: SignerWithAddress + let l2Messenger: SignerWithAddress + let dummy: SignerWithAddress + const gasUsedDeviation = 100 + const initialStatus = 0 + + before(async () => { + const accounts = await ethers.getSigners() + deployer = accounts[0] + l1Owner = accounts[1] + dummy = accounts[3] + + const l2CrossDomainMessengerFactory = await ethers.getContractFactory( + 'src/v0.8/l2ep/test/mocks/scroll/MockScrollL2CrossDomainMessenger.sol:MockScrollL2CrossDomainMessenger', + deployer, + ) + + l2CrossDomainMessenger = await l2CrossDomainMessengerFactory.deploy() + + // Pretend we're on L2 + await network.provider.request({ + method: 'hardhat_impersonateAccount', + params: [l2CrossDomainMessenger.address], + }) + l2Messenger = await ethers.getSigner(l2CrossDomainMessenger.address) + // Credit the L2 messenger with some ETH + await dummy.sendTransaction({ + to: l2Messenger.address, + value: ethers.utils.parseEther('10'), + }) + }) + + beforeEach(async () => { + const scrollSequencerStatusRecorderFactory = + await ethers.getContractFactory( + 'src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol:ScrollSequencerUptimeFeed', + deployer, + ) + scrollUptimeFeed = await scrollSequencerStatusRecorderFactory.deploy( + l1Owner.address, + l2CrossDomainMessenger.address, + initialStatus, + ) + + // Set mock sender in mock L2 messenger contract + await l2CrossDomainMessenger.setSender(l1Owner.address) + + // Mock consumer + const statusFeedConsumerFactory = await ethers.getContractFactory( + 'src/v0.8/tests/FeedConsumer.sol:FeedConsumer', + deployer, + ) + uptimeFeedConsumer = await statusFeedConsumerFactory.deploy( + scrollUptimeFeed.address, + ) + }) + + describe('constructor', () => { + it('should have been deployed with the correct initial state', async () => { + const l1Sender = await scrollUptimeFeed.l1Sender() + expect(l1Sender).to.equal(l1Owner.address) + const { roundId, answer } = await scrollUptimeFeed.latestRoundData() + expect(roundId).to.equal(1) + expect(answer).to.equal(initialStatus) + }) + }) + + describe('#updateStatus', () => { + it('should revert if called by an address that is not the L2 Cross Domain Messenger', async () => { + const timestamp = await scrollUptimeFeed.latestTimestamp() + expect( + scrollUptimeFeed.connect(dummy).updateStatus(true, timestamp), + ).to.be.revertedWith('InvalidSender') + }) + + it('should revert if called by an address that is not the L2 Cross Domain Messenger and is not the L1 sender', async () => { + const timestamp = await scrollUptimeFeed.latestTimestamp() + await l2CrossDomainMessenger.setSender(dummy.address) + expect( + scrollUptimeFeed.connect(dummy).updateStatus(true, timestamp), + ).to.be.revertedWith('InvalidSender') + }) + + it(`should update status when status has not changed and incoming timestamp is the same as latest`, async () => { + const timestamp = await scrollUptimeFeed.latestTimestamp() + let tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(1, 2 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + + const latestRoundBeforeUpdate = await scrollUptimeFeed.latestRoundData() + + tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp.add(200)) + + // Submit another status update with the same status + const latestBlock = await ethers.provider.getBlock('latest') + + await expect(tx) + .to.emit(scrollUptimeFeed, 'RoundUpdated') + .withArgs(1, latestBlock.timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + expect(await scrollUptimeFeed.latestTimestamp()).to.equal(timestamp) + + // Verify that latest round has been properly updated + const latestRoundDataAfterUpdate = + await scrollUptimeFeed.latestRoundData() + expect(latestRoundDataAfterUpdate.roundId).to.equal( + latestRoundBeforeUpdate.roundId, + ) + expect(latestRoundDataAfterUpdate.answer).to.equal( + latestRoundBeforeUpdate.answer, + ) + expect(latestRoundDataAfterUpdate.startedAt).to.equal( + latestRoundBeforeUpdate.startedAt, + ) + expect(latestRoundDataAfterUpdate.answeredInRound).to.equal( + latestRoundBeforeUpdate.answeredInRound, + ) + expect(latestRoundDataAfterUpdate.updatedAt).to.equal( + latestBlock.timestamp, + ) + }) + + it(`should update status when status has changed and incoming timestamp is newer than the latest`, async () => { + let timestamp = await scrollUptimeFeed.latestTimestamp() + let tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(1, 2 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + + // Submit another status update, different status, newer timestamp should update + timestamp = timestamp.add(2000) + tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(false, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(0, 3 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(0) + expect(await scrollUptimeFeed.latestTimestamp()).to.equal(timestamp) + }) + + it(`should update status when status has changed and incoming timestamp is the same as latest`, async () => { + const timestamp = await scrollUptimeFeed.latestTimestamp() + let tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(1, 2 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + + // Submit another status update, different status, same timestamp should update + tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(false, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(0, 3 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(0) + expect(await scrollUptimeFeed.latestTimestamp()).to.equal(timestamp) + }) + + it('should ignore out-of-order updates', async () => { + const timestamp = (await scrollUptimeFeed.latestTimestamp()).add(10_000) + // Update status + let tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + await expect(tx) + .to.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(1, 2 /** roundId */, timestamp) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + + // Update with different status, but stale timestamp, should be ignored + const staleTimestamp = timestamp.sub(1000) + tx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(false, staleTimestamp) + await expect(tx) + .to.not.emit(scrollUptimeFeed, 'AnswerUpdated') + .withArgs(1, 2 /** roundId */, timestamp) + await expect(tx).to.emit(scrollUptimeFeed, 'UpdateIgnored') + }) + }) + + describe('AggregatorV3Interface', () => { + it('should return valid answer from getRoundData and latestRoundData', async () => { + let [roundId, answer, startedAt, updatedAt, answeredInRound] = + await scrollUptimeFeed.latestRoundData() + expect(roundId).to.equal(1) + expect(answer).to.equal(0) + expect(answeredInRound).to.equal(roundId) + expect(startedAt).to.equal(updatedAt) + + // Submit status update with different status and newer timestamp, should update + const timestamp = (startedAt as BigNumber).add(1000) + await scrollUptimeFeed.connect(l2Messenger).updateStatus(true, timestamp) + ;[roundId, answer, startedAt, updatedAt, answeredInRound] = + await scrollUptimeFeed.getRoundData(2) + expect(roundId).to.equal(2) + expect(answer).to.equal(1) + expect(answeredInRound).to.equal(roundId) + expect(startedAt).to.equal(timestamp) + expect(updatedAt.lte(startedAt)).to.be.true + + // Check that last round is still returning the correct data + ;[roundId, answer, startedAt, updatedAt, answeredInRound] = + await scrollUptimeFeed.getRoundData(1) + expect(roundId).to.equal(1) + expect(answer).to.equal(0) + expect(answeredInRound).to.equal(roundId) + expect(startedAt).to.equal(updatedAt) + + // Assert latestRoundData corresponds to latest round id + expect(await scrollUptimeFeed.getRoundData(2)).to.deep.equal( + await scrollUptimeFeed.latestRoundData(), + ) + }) + + it('should revert from #getRoundData when round does not yet exist (future roundId)', async () => { + expect(scrollUptimeFeed.getRoundData(2)).to.be.revertedWith( + 'NoDataPresent()', + ) + }) + + it('should revert from #getAnswer when round does not yet exist (future roundId)', async () => { + expect(scrollUptimeFeed.getAnswer(2)).to.be.revertedWith( + 'NoDataPresent()', + ) + }) + + it('should revert from #getTimestamp when round does not yet exist (future roundId)', async () => { + expect(scrollUptimeFeed.getTimestamp(2)).to.be.revertedWith( + 'NoDataPresent()', + ) + }) + }) + + describe('Protect reads on AggregatorV2V3Interface functions', () => { + it('should disallow reads on AggregatorV2V3Interface functions when consuming contract is not whitelisted', async () => { + // Sanity - consumer is not whitelisted + expect(await scrollUptimeFeed.checkEnabled()).to.be.true + expect( + await scrollUptimeFeed.hasAccess(uptimeFeedConsumer.address, '0x00'), + ).to.be.false + + // Assert reads are not possible from consuming contract + await expect(uptimeFeedConsumer.latestAnswer()).to.be.revertedWith( + 'No access', + ) + await expect(uptimeFeedConsumer.latestRoundData()).to.be.revertedWith( + 'No access', + ) + }) + + it('should allow reads on AggregatorV2V3Interface functions when consuming contract is whitelisted', async () => { + // Whitelist consumer + await scrollUptimeFeed.addAccess(uptimeFeedConsumer.address) + // Sanity - consumer is whitelisted + expect(await scrollUptimeFeed.checkEnabled()).to.be.true + expect( + await scrollUptimeFeed.hasAccess(uptimeFeedConsumer.address, '0x00'), + ).to.be.true + + // Assert reads are possible from consuming contract + expect(await uptimeFeedConsumer.latestAnswer()).to.be.equal('0') + const [roundId, answer] = await uptimeFeedConsumer.latestRoundData() + expect(roundId).to.equal(1) + expect(answer).to.equal(0) + }) + }) + + describe('Gas costs', () => { + it('should consume a known amount of gas for updates @skip-coverage', async () => { + // Sanity - start at flag = 0 (`false`) + expect(await scrollUptimeFeed.latestAnswer()).to.equal(0) + let timestamp = await scrollUptimeFeed.latestTimestamp() + + // Gas for no update + timestamp = timestamp.add(1000) + const _noUpdateTx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(false, timestamp) + const noUpdateTx = await _noUpdateTx.wait(1) + // Assert no update + expect(await scrollUptimeFeed.latestAnswer()).to.equal(0) + expect(noUpdateTx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 38594, + gasUsedDeviation, + ) + + // Gas for update + timestamp = timestamp.add(1000) + const _updateTx = await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + const updateTx = await _updateTx.wait(1) + // Assert update + expect(await scrollUptimeFeed.latestAnswer()).to.equal(1) + expect(updateTx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 58458, + gasUsedDeviation, + ) + }) + + describe('Aggregator interface', () => { + beforeEach(async () => { + const timestamp = (await scrollUptimeFeed.latestTimestamp()).add(1000) + // Initialise a round + await scrollUptimeFeed + .connect(l2Messenger) + .updateStatus(true, timestamp) + }) + + it('should consume a known amount of gas for getRoundData(uint80) @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.getRoundData(1), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 30952, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for latestRoundData() @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.latestRoundData(), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 28523, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for latestAnswer() @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.latestAnswer(), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 28229, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for latestTimestamp() @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.latestTimestamp(), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 28129, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for latestRound() @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.latestRound(), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 28145, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for getAnswer(roundId) @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.getAnswer(1), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 30682, + gasUsedDeviation, + ) + }) + + it('should consume a known amount of gas for getTimestamp(roundId) @skip-coverage', async () => { + const _tx = await l2Messenger.sendTransaction( + await scrollUptimeFeed + .connect(l2Messenger) + .populateTransaction.getTimestamp(1), + ) + const tx = await _tx.wait(1) + expect(tx.cumulativeGasUsed.toNumber()).to.be.closeTo( + 30570, + gasUsedDeviation, + ) + }) + }) + }) +}) diff --git a/contracts/test/v0.8/dev/ScrollValidator.test.ts b/contracts/test/v0.8/dev/ScrollValidator.test.ts new file mode 100644 index 00000000000..c5ec59c5c99 --- /dev/null +++ b/contracts/test/v0.8/dev/ScrollValidator.test.ts @@ -0,0 +1,118 @@ +import { ethers } from 'hardhat' +import { BigNumber, Contract, ContractFactory } from 'ethers' +import { expect } from 'chai' +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' + +describe('ScrollValidator', () => { + const GAS_LIMIT = BigNumber.from(1_900_000) + /** Fake L2 target */ + const L2_SEQ_STATUS_RECORDER_ADDRESS = + '0x491B1dDA0A8fa069bbC1125133A975BF4e85a91b' + let scrollValidator: Contract + let scrollUptimeFeedFactory: ContractFactory + let mockScrollL1CrossDomainMessenger: Contract + let deployer: SignerWithAddress + let eoaValidator: SignerWithAddress + + before(async () => { + const accounts = await ethers.getSigners() + deployer = accounts[0] + eoaValidator = accounts[1] + }) + + beforeEach(async () => { + // Required for building the calldata + scrollUptimeFeedFactory = await ethers.getContractFactory( + 'src/v0.8/l2ep/dev/scroll/ScrollSequencerUptimeFeed.sol:ScrollSequencerUptimeFeed', + deployer, + ) + + // Scroll Messenger contract on L1 + const mockScrollL1CrossDomainMessengerFactory = + await ethers.getContractFactory( + 'src/v0.8/l2ep/test/mocks/scroll/MockScrollL1CrossDomainMessenger.sol:MockScrollL1CrossDomainMessenger', + ) + mockScrollL1CrossDomainMessenger = + await mockScrollL1CrossDomainMessengerFactory.deploy() + + // Contract under test + const scrollValidatorFactory = await ethers.getContractFactory( + 'src/v0.8/l2ep/dev/scroll/ScrollValidator.sol:ScrollValidator', + deployer, + ) + + scrollValidator = await scrollValidatorFactory.deploy( + mockScrollL1CrossDomainMessenger.address, + L2_SEQ_STATUS_RECORDER_ADDRESS, + GAS_LIMIT, + ) + }) + + describe('#setGasLimit', () => { + it('correctly updates the gas limit', async () => { + const newGasLimit = BigNumber.from(2_000_000) + const tx = await scrollValidator.setGasLimit(newGasLimit) + await tx.wait() + const currentGasLimit = await scrollValidator.getGasLimit() + expect(currentGasLimit).to.equal(newGasLimit) + }) + }) + + describe('#validate', () => { + it('reverts if called by account with no access', async () => { + await expect( + scrollValidator.connect(eoaValidator).validate(0, 0, 1, 1), + ).to.be.revertedWith('No access') + }) + + it('posts sequencer status when there is not status change', async () => { + await scrollValidator.addAccess(eoaValidator.address) + + const currentBlock = await ethers.provider.getBlock('latest') + const futureTimestamp = currentBlock.timestamp + 5000 + + await ethers.provider.send('evm_setNextBlockTimestamp', [futureTimestamp]) + const sequencerStatusRecorderCallData = + scrollUptimeFeedFactory.interface.encodeFunctionData('updateStatus', [ + false, + futureTimestamp, + ]) + + await expect(scrollValidator.connect(eoaValidator).validate(0, 0, 0, 0)) + .to.emit(mockScrollL1CrossDomainMessenger, 'SentMessage') + .withArgs( + scrollValidator.address, // sender + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + 0, // value + 0, // nonce + GAS_LIMIT, // gas limit + sequencerStatusRecorderCallData, // message + ) + }) + + it('post sequencer offline', async () => { + await scrollValidator.addAccess(eoaValidator.address) + + const currentBlock = await ethers.provider.getBlock('latest') + const futureTimestamp = currentBlock.timestamp + 10000 + + await ethers.provider.send('evm_setNextBlockTimestamp', [futureTimestamp]) + const sequencerStatusRecorderCallData = + scrollUptimeFeedFactory.interface.encodeFunctionData('updateStatus', [ + true, + futureTimestamp, + ]) + + await expect(scrollValidator.connect(eoaValidator).validate(0, 0, 1, 1)) + .to.emit(mockScrollL1CrossDomainMessenger, 'SentMessage') + .withArgs( + scrollValidator.address, // sender + L2_SEQ_STATUS_RECORDER_ADDRESS, // target + 0, // value + 0, // nonce + GAS_LIMIT, // gas limit + sequencerStatusRecorderCallData, // message + ) + }) + }) +}) diff --git a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol index d7a54d6223c..b6056286261 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFCoordinatorV2Plus_Migration.t.sol @@ -331,8 +331,8 @@ contract VRFCoordinatorV2Plus_Migration is BaseTest { function registerProvingKey() public { uint256[2] memory uncompressedKeyParts = this.getProvingKeyParts(UNCOMPRESSED_PUBLIC_KEY); - v1Coordinator.registerProvingKey(OWNER, uncompressedKeyParts); - v1Coordinator_noLink.registerProvingKey(OWNER, uncompressedKeyParts); + v1Coordinator.registerProvingKey(uncompressedKeyParts); + v1Coordinator_noLink.registerProvingKey(uncompressedKeyParts); } // note: Call this function via this.getProvingKeyParts to be able to pass memory as calldata and diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol index e2734f17288..62c08533d3f 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2Plus.t.sol @@ -124,12 +124,12 @@ contract VRFV2Plus is BaseTest { // Should revert when already registered. uint256[2] memory uncompressedKeyParts = this.getProvingKeyParts(vrfUncompressedPublicKey); vm.expectRevert(abi.encodeWithSelector(VRFCoordinatorV2_5.ProvingKeyAlreadyRegistered.selector, vrfKeyHash)); - s_testCoordinator.registerProvingKey(LINK_WHALE, uncompressedKeyParts); + s_testCoordinator.registerProvingKey(uncompressedKeyParts); } function registerProvingKey() public { uint256[2] memory uncompressedKeyParts = this.getProvingKeyParts(vrfUncompressedPublicKey); - s_testCoordinator.registerProvingKey(LINK_WHALE, uncompressedKeyParts); + s_testCoordinator.registerProvingKey(uncompressedKeyParts); } // note: Call this function via this.getProvingKeyParts to be able to pass memory as calldata and diff --git a/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol b/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol index 335e64ff7ef..0f34003d9ae 100644 --- a/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol +++ b/contracts/test/v0.8/foundry/vrf/VRFV2PlusSubscriptionAPI.t.sol @@ -315,25 +315,25 @@ contract VRFV2PlusSubscriptionAPITest is BaseTest { assertEq(address(s_subscriptionAPI).balance, s_subscriptionAPI.s_totalNativeBalance()); } - function testOracleWithdrawNoLink() public { + function testWithdrawNoLink() public { // CASE: no link token set vm.expectRevert(SubscriptionAPI.LinkNotSet.selector); - s_subscriptionAPI.oracleWithdraw(OWNER, 1 ether); + s_subscriptionAPI.withdraw(OWNER); } - function testOracleWithdrawInsufficientBalance() public { + function testWithdrawInsufficientBalance() public { // CASE: link token set, trying to withdraw // more than balance MockLinkToken linkToken = new MockLinkToken(); s_subscriptionAPI.setLINKAndLINKNativeFeed(address(linkToken), address(0)); assertEq(address(s_subscriptionAPI.LINK()), address(linkToken)); - // call oracleWithdraw + // call withdraw vm.expectRevert(SubscriptionAPI.InsufficientBalance.selector); - s_subscriptionAPI.oracleWithdraw(OWNER, 1 ether); + s_subscriptionAPI.withdraw(OWNER); } - function testOracleWithdrawSufficientBalanceLinkSet() public { + function testWithdrawSufficientBalanceLinkSet() public { // CASE: link token set, trying to withdraw // less than balance MockLinkToken linkToken = new MockLinkToken(); @@ -344,58 +344,72 @@ contract VRFV2PlusSubscriptionAPITest is BaseTest { bool success = linkToken.transfer(address(s_subscriptionAPI), 10 ether); assertTrue(success, "failed link transfer"); - // set the withdrawable tokens of the oracle to be 1 ether - address oracle = makeAddr("oracle"); - s_subscriptionAPI.setWithdrawableTokensTestingOnlyXXX(oracle, 1 ether); - assertEq(s_subscriptionAPI.getWithdrawableTokensTestingOnlyXXX(oracle), 1 ether); + // set the withdrawable tokens of the contract to be 1 ether + s_subscriptionAPI.setWithdrawableTokensTestingOnlyXXX(1 ether); + assertEq(s_subscriptionAPI.getWithdrawableTokensTestingOnlyXXX(), 1 ether); // set the total balance to be the same as the link balance for consistency // (this is not necessary for the test, but just to be sane) s_subscriptionAPI.setTotalBalanceTestingOnlyXXX(10 ether); - // call oracleWithdraw from oracle address - changePrank(oracle); - s_subscriptionAPI.oracleWithdraw(oracle, 1 ether); - // assert link balance of oracle - assertEq(linkToken.balanceOf(oracle), 1 ether, "oracle link balance incorrect"); + // call Withdraw from owner address + uint256 ownerBalance = linkToken.balanceOf(OWNER); + changePrank(OWNER); + s_subscriptionAPI.withdraw(OWNER); + // assert link balance of owner + assertEq(linkToken.balanceOf(OWNER) - ownerBalance, 1 ether, "owner link balance incorrect"); // assert state of subscription api - assertEq(s_subscriptionAPI.getWithdrawableTokensTestingOnlyXXX(oracle), 0, "oracle withdrawable tokens incorrect"); + assertEq(s_subscriptionAPI.getWithdrawableTokensTestingOnlyXXX(), 0, "owner withdrawable tokens incorrect"); // assert that total balance is changed by the withdrawn amount assertEq(s_subscriptionAPI.s_totalBalance(), 9 ether, "total balance incorrect"); } - function testOracleWithdrawNativeInsufficientBalance() public { + function testWithdrawNativeInsufficientBalance() public { // CASE: trying to withdraw more than balance // should revert with InsufficientBalance - // call oracleWithdrawNative + // call WithdrawNative + changePrank(OWNER); vm.expectRevert(SubscriptionAPI.InsufficientBalance.selector); - s_subscriptionAPI.oracleWithdrawNative(payable(OWNER), 1 ether); + s_subscriptionAPI.withdrawNative(payable(OWNER)); + } + + function testWithdrawLinkInvalidOwner() public { + address invalidAddress = makeAddr("invalidAddress"); + changePrank(invalidAddress); + vm.expectRevert("Only callable by owner"); + s_subscriptionAPI.withdraw(payable(OWNER)); } - function testOracleWithdrawNativeSufficientBalance() public { + function testWithdrawNativeInvalidOwner() public { + address invalidAddress = makeAddr("invalidAddress"); + changePrank(invalidAddress); + vm.expectRevert("Only callable by owner"); + s_subscriptionAPI.withdrawNative(payable(OWNER)); + } + + function testWithdrawNativeSufficientBalance() public { // CASE: trying to withdraw less than balance // should withdraw successfully // transfer 10 ether to the contract to withdraw vm.deal(address(s_subscriptionAPI), 10 ether); - // set the withdrawable eth of the oracle to be 1 ether - address oracle = makeAddr("oracle"); - s_subscriptionAPI.setWithdrawableNativeTestingOnlyXXX(oracle, 1 ether); - assertEq(s_subscriptionAPI.getWithdrawableNativeTestingOnlyXXX(oracle), 1 ether); + // set the withdrawable eth of the contract to be 1 ether + s_subscriptionAPI.setWithdrawableNativeTestingOnlyXXX(1 ether); + assertEq(s_subscriptionAPI.getWithdrawableNativeTestingOnlyXXX(), 1 ether); // set the total balance to be the same as the eth balance for consistency // (this is not necessary for the test, but just to be sane) s_subscriptionAPI.setTotalNativeBalanceTestingOnlyXXX(10 ether); - // call oracleWithdrawNative from oracle address - changePrank(oracle); - s_subscriptionAPI.oracleWithdrawNative(payable(oracle), 1 ether); - // assert native balance of oracle - assertEq(address(oracle).balance, 1 ether, "oracle native balance incorrect"); + // call WithdrawNative from owner address + changePrank(OWNER); + s_subscriptionAPI.withdrawNative(payable(OWNER)); + // assert native balance + assertEq(address(OWNER).balance, 1 ether, "owner native balance incorrect"); // assert state of subscription api - assertEq(s_subscriptionAPI.getWithdrawableNativeTestingOnlyXXX(oracle), 0, "oracle withdrawable native incorrect"); + assertEq(s_subscriptionAPI.getWithdrawableNativeTestingOnlyXXX(), 0, "owner withdrawable native incorrect"); // assert that total balance is changed by the withdrawn amount assertEq(s_subscriptionAPI.s_totalNativeBalance(), 9 ether, "total native balance incorrect"); } diff --git a/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts b/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts index aecad5466bb..e484283e80b 100644 --- a/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts +++ b/contracts/test/v0.8/functions/v1/FunctionsRouter.test.ts @@ -20,7 +20,7 @@ describe('Functions Router - Request lifecycle', () => { describe('Config', () => { it('#typeAndVersion', async () => { expect(await contracts.router.typeAndVersion()).to.be.equal( - 'Functions Router v1.0.0', + 'Functions Router v2.0.0', ) }) it('non-owner is unable to update config', async () => { diff --git a/core/bridges/mocks/orm.go b/core/bridges/mocks/orm.go index ba8c7526d1c..2c92a7e8024 100644 --- a/core/bridges/mocks/orm.go +++ b/core/bridges/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type ORM struct { func (_m *ORM) BridgeTypes(offset int, limit int) ([]bridges.BridgeType, int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for BridgeTypes") + } + var r0 []bridges.BridgeType var r1 int var r2 error @@ -53,6 +57,10 @@ func (_m *ORM) BridgeTypes(offset int, limit int) ([]bridges.BridgeType, int, er func (_m *ORM) CreateBridgeType(bt *bridges.BridgeType) error { ret := _m.Called(bt) + if len(ret) == 0 { + panic("no return value specified for CreateBridgeType") + } + var r0 error if rf, ok := ret.Get(0).(func(*bridges.BridgeType) error); ok { r0 = rf(bt) @@ -67,6 +75,10 @@ func (_m *ORM) CreateBridgeType(bt *bridges.BridgeType) error { func (_m *ORM) CreateExternalInitiator(externalInitiator *bridges.ExternalInitiator) error { ret := _m.Called(externalInitiator) + if len(ret) == 0 { + panic("no return value specified for CreateExternalInitiator") + } + var r0 error if rf, ok := ret.Get(0).(func(*bridges.ExternalInitiator) error); ok { r0 = rf(externalInitiator) @@ -81,6 +93,10 @@ func (_m *ORM) CreateExternalInitiator(externalInitiator *bridges.ExternalInitia func (_m *ORM) DeleteBridgeType(bt *bridges.BridgeType) error { ret := _m.Called(bt) + if len(ret) == 0 { + panic("no return value specified for DeleteBridgeType") + } + var r0 error if rf, ok := ret.Get(0).(func(*bridges.BridgeType) error); ok { r0 = rf(bt) @@ -95,6 +111,10 @@ func (_m *ORM) DeleteBridgeType(bt *bridges.BridgeType) error { func (_m *ORM) DeleteExternalInitiator(name string) error { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for DeleteExternalInitiator") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(name) @@ -109,6 +129,10 @@ func (_m *ORM) DeleteExternalInitiator(name string) error { func (_m *ORM) ExternalInitiators(offset int, limit int) ([]bridges.ExternalInitiator, int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for ExternalInitiators") + } + var r0 []bridges.ExternalInitiator var r1 int var r2 error @@ -142,6 +166,10 @@ func (_m *ORM) ExternalInitiators(offset int, limit int) ([]bridges.ExternalInit func (_m *ORM) FindBridge(name bridges.BridgeName) (bridges.BridgeType, error) { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for FindBridge") + } + var r0 bridges.BridgeType var r1 error if rf, ok := ret.Get(0).(func(bridges.BridgeName) (bridges.BridgeType, error)); ok { @@ -166,6 +194,10 @@ func (_m *ORM) FindBridge(name bridges.BridgeName) (bridges.BridgeType, error) { func (_m *ORM) FindBridges(name []bridges.BridgeName) ([]bridges.BridgeType, error) { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for FindBridges") + } + var r0 []bridges.BridgeType var r1 error if rf, ok := ret.Get(0).(func([]bridges.BridgeName) ([]bridges.BridgeType, error)); ok { @@ -192,6 +224,10 @@ func (_m *ORM) FindBridges(name []bridges.BridgeName) ([]bridges.BridgeType, err func (_m *ORM) FindExternalInitiator(eia *auth.Token) (*bridges.ExternalInitiator, error) { ret := _m.Called(eia) + if len(ret) == 0 { + panic("no return value specified for FindExternalInitiator") + } + var r0 *bridges.ExternalInitiator var r1 error if rf, ok := ret.Get(0).(func(*auth.Token) (*bridges.ExternalInitiator, error)); ok { @@ -218,6 +254,10 @@ func (_m *ORM) FindExternalInitiator(eia *auth.Token) (*bridges.ExternalInitiato func (_m *ORM) FindExternalInitiatorByName(iname string) (bridges.ExternalInitiator, error) { ret := _m.Called(iname) + if len(ret) == 0 { + panic("no return value specified for FindExternalInitiatorByName") + } + var r0 bridges.ExternalInitiator var r1 error if rf, ok := ret.Get(0).(func(string) (bridges.ExternalInitiator, error)); ok { @@ -242,6 +282,10 @@ func (_m *ORM) FindExternalInitiatorByName(iname string) (bridges.ExternalInitia func (_m *ORM) GetCachedResponse(dotId string, specId int32, maxElapsed time.Duration) ([]byte, error) { ret := _m.Called(dotId, specId, maxElapsed) + if len(ret) == 0 { + panic("no return value specified for GetCachedResponse") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, int32, time.Duration) ([]byte, error)); ok { @@ -268,6 +312,10 @@ func (_m *ORM) GetCachedResponse(dotId string, specId int32, maxElapsed time.Dur func (_m *ORM) UpdateBridgeType(bt *bridges.BridgeType, btr *bridges.BridgeTypeRequest) error { ret := _m.Called(bt, btr) + if len(ret) == 0 { + panic("no return value specified for UpdateBridgeType") + } + var r0 error if rf, ok := ret.Get(0).(func(*bridges.BridgeType, *bridges.BridgeTypeRequest) error); ok { r0 = rf(bt, btr) @@ -282,6 +330,10 @@ func (_m *ORM) UpdateBridgeType(bt *bridges.BridgeType, btr *bridges.BridgeTypeR func (_m *ORM) UpsertBridgeResponse(dotId string, specId int32, response []byte) error { ret := _m.Called(dotId, specId, response) + if len(ret) == 0 { + panic("no return value specified for UpsertBridgeResponse") + } + var r0 error if rf, ok := ret.Get(0).(func(string, int32, []byte) error); ok { r0 = rf(dotId, specId, response) diff --git a/core/bridges/orm.go b/core/bridges/orm.go index cfad1da836e..8ae6b855c88 100644 --- a/core/bridges/orm.go +++ b/core/bridges/orm.go @@ -150,6 +150,7 @@ func (o *orm) CreateBridgeType(bt *BridgeType) error { if err != nil { return err } + defer stmt.Close() return stmt.Get(bt, bt) }) if err == nil { @@ -222,6 +223,7 @@ func (o *orm) CreateExternalInitiator(externalInitiator *ExternalInitiator) (err if err != nil { return errors.Wrap(err, "failed to prepare named stmt") } + defer stmt.Close() return errors.Wrap(stmt.Get(externalInitiator, externalInitiator), "failed to load external_initiator") }) return errors.Wrap(err, "CreateExternalInitiator failed") diff --git a/core/cbor/cbor_test.go b/core/cbor/cbor_test.go index 39a2da479b7..cf1390cc908 100644 --- a/core/cbor/cbor_test.go +++ b/core/cbor/cbor_test.go @@ -10,14 +10,14 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_ParseCBOR(t *testing.T) { t.Parallel() - address, err := utils.TryParseHex("0x8bd112d3f8f92e41c861939545ad387307af9703") + address, err := hex.DecodeString("0x8bd112d3f8f92e41c861939545ad387307af9703") require.NoError(t, err) tests := []struct { diff --git a/core/chainlink.devspace.Dockerfile b/core/chainlink.devspace.Dockerfile index 88d3cec16ad..c639190a80f 100644 --- a/core/chainlink.devspace.Dockerfile +++ b/core/chainlink.devspace.Dockerfile @@ -17,6 +17,22 @@ COPY . . # Build the golang binary RUN make install-chainlink +# Link LOOP Plugin source dirs with simple names +RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-feeds | xargs -I % ln -s % /chainlink-feeds +RUN go list -m -f "{{.Dir}}" github.com/smartcontractkit/chainlink-solana | xargs -I % ln -s % /chainlink-solana + +# Build image: Plugins +FROM golang:1.21-bullseye as buildplugins +RUN go version + +WORKDIR /chainlink-feeds +COPY --from=buildgo /chainlink-feeds . +RUN go install ./cmd/chainlink-feeds + +WORKDIR /chainlink-solana +COPY --from=buildgo /chainlink-solana . +RUN go install ./pkg/solana/cmd/chainlink-solana + # Final image: ubuntu with chainlink binary FROM golang:1.21-bullseye @@ -32,6 +48,10 @@ RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ COPY --from=buildgo /go/bin/chainlink /usr/local/bin/ +# Install (but don't enable) LOOP Plugins +COPY --from=buildplugins /go/bin/chainlink-feeds /usr/local/bin/ +COPY --from=buildplugins /go/bin/chainlink-solana /usr/local/bin/ + # Dependency of CosmWasm/wasmd COPY --from=buildgo /go/pkg/mod/github.com/\!cosm\!wasm/wasmvm@v*/internal/api/libwasmvm.*.so /usr/lib/ RUN chmod 755 /usr/lib/libwasmvm.*.so diff --git a/core/chains/evm/assets/assets.go b/core/chains/evm/assets/assets.go index 377e92a855a..738ba5c817b 100644 --- a/core/chains/evm/assets/assets.go +++ b/core/chains/evm/assets/assets.go @@ -7,7 +7,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/utils/bytes" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/shopspring/decimal" ) @@ -108,10 +108,10 @@ func (e *Eth) ToInt() *big.Int { // Scan reads the database value and returns an instance. func (e *Eth) Scan(value interface{}) error { - return (*utils.Big)(e).Scan(value) + return (*ubig.Big)(e).Scan(value) } // Value returns the Eth value for serialization to database. func (e Eth) Value() (driver.Value, error) { - return (utils.Big)(e).Value() + return (ubig.Big)(e).Value() } diff --git a/core/chains/evm/assets/wei.go b/core/chains/evm/assets/wei.go index be0143b3a86..8bacabfdb4a 100644 --- a/core/chains/evm/assets/wei.go +++ b/core/chains/evm/assets/wei.go @@ -11,7 +11,7 @@ import ( "golang.org/x/exp/constraints" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) const ( @@ -58,10 +58,10 @@ func suffixExp(suf string) int32 { } } -// Wei extends utils.Big to implement encoding.TextMarshaler and +// Wei extends ubig.Big to implement encoding.TextMarshaler and // encoding.TextUnmarshaler with support for unit suffixes, as well as // additional functions -type Wei utils.Big +type Wei ubig.Big func MaxWei(w, x *Wei) *Wei { return NewWei(bigmath.Max(w.ToInt(), x.ToInt())) @@ -271,10 +271,10 @@ func (w *Wei) AddPercentage(percentage uint16) *Wei { // Scan reads the database value and returns an instance. func (w *Wei) Scan(value interface{}) error { - return (*utils.Big)(w).Scan(value) + return (*ubig.Big)(w).Scan(value) } // Value returns this instance serialized for database storage. func (w Wei) Value() (driver.Value, error) { - return (utils.Big)(w).Value() + return (ubig.Big)(w).Value() } diff --git a/core/chains/evm/client/chain_client.go b/core/chains/evm/client/chain_client.go index 3efc5645e22..5dd70992382 100644 --- a/core/chains/evm/client/chain_client.go +++ b/core/chains/evm/client/chain_client.go @@ -37,11 +37,11 @@ type chainClient struct { *evmtypes.Head, RPCCLient, ] - logger logger.Logger + logger logger.SugaredLogger } func NewChainClient( - logger logger.Logger, + lggr logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, @@ -64,7 +64,7 @@ func NewChainClient( *evmtypes.Head, RPCCLient, ]( - logger, + lggr, selectionMode, leaseDuration, noNewHeadsThreshold, @@ -77,7 +77,7 @@ func NewChainClient( ) return &chainClient{ multiNode: multiNode, - logger: logger, + logger: logger.Sugared(lggr), } } @@ -216,7 +216,8 @@ func (c *chainClient) SendTransaction(ctx context.Context, tx *types.Transaction func (c *chainClient) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commonclient.SendTxReturnCode, error) { err := c.SendTransaction(ctx, tx) - return ClassifySendError(err, c.logger, tx, fromAddress, c.IsL2()) + returnCode := ClassifySendError(err, c.logger, tx, fromAddress, c.IsL2()) + return returnCode, err } func (c *chainClient) SequenceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (evmtypes.Nonce, error) { diff --git a/core/chains/evm/client/chain_id_sub.go b/core/chains/evm/client/chain_id_sub.go index 8ea4e207970..c3162b300c7 100644 --- a/core/chains/evm/client/chain_id_sub.go +++ b/core/chains/evm/client/chain_id_sub.go @@ -6,7 +6,7 @@ import ( "github.com/ethereum/go-ethereum" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) var _ ethereum.Subscription = &chainIDSubForwarder{} @@ -64,7 +64,7 @@ func (c *chainIDSubForwarder) forwardLoop() { return case h := <-c.srcCh: - h.EVMChainID = utils.NewBig(c.chainID) + h.EVMChainID = ubig.New(c.chainID) select { case c.destCh <- h: case <-c.unSub: diff --git a/core/chains/evm/client/chain_id_sub_test.go b/core/chains/evm/client/chain_id_sub_test.go index 211ba812fbe..c71b45c489e 100644 --- a/core/chains/evm/client/chain_id_sub_test.go +++ b/core/chains/evm/client/chain_id_sub_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) type mockSubscription struct { @@ -111,7 +111,7 @@ func TestChainIDSubForwarder(t *testing.T) { forwarder.srcCh <- head receivedHead := <-ch assert.Equal(t, head, receivedHead) - assert.Equal(t, utils.NewBig(chainID), receivedHead.EVMChainID) + assert.Equal(t, ubig.New(chainID), receivedHead.EVMChainID) expectedErr := errors.New("error") sub.Errors <- expectedErr diff --git a/core/chains/evm/client/client.go b/core/chains/evm/client/client.go index 688cc3c9bea..61635c59c6b 100644 --- a/core/chains/evm/client/client.go +++ b/core/chains/evm/client/client.go @@ -14,7 +14,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/common/config" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -101,7 +102,7 @@ func ContextWithDefaultTimeout() (ctx context.Context, cancel context.CancelFunc // client represents an abstract client that manages connections to // multiple nodes for a single chain id type client struct { - logger logger.Logger + logger logger.SugaredLogger pool *Pool } @@ -112,10 +113,10 @@ var _ htrktypes.Client[*evmtypes.Head, ethereum.Subscription, *big.Int, common.H // Currently only supports one primary // // Deprecated: use [NewChainClient] -func NewClientWithNodes(logger logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, primaryNodes []Node, sendOnlyNodes []SendOnlyNode, chainID *big.Int, chainType config.ChainType) (*client, error) { - pool := NewPool(logger, selectionMode, leaseDuration, noNewHeadsThreshold, primaryNodes, sendOnlyNodes, chainID, chainType) +func NewClientWithNodes(lggr logger.Logger, selectionMode string, leaseDuration time.Duration, noNewHeadsThreshold time.Duration, primaryNodes []Node, sendOnlyNodes []SendOnlyNode, chainID *big.Int, chainType config.ChainType) (*client, error) { + pool := NewPool(lggr, selectionMode, leaseDuration, noNewHeadsThreshold, primaryNodes, sendOnlyNodes, chainID, chainType) return &client{ - logger: logger, + logger: logger.Sugared(lggr), pool: pool, }, nil } @@ -219,7 +220,8 @@ func (client *client) HeaderByHash(ctx context.Context, h common.Hash) (*types.H func (client *client) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commonclient.SendTxReturnCode, error) { err := client.SendTransaction(ctx, tx) - return ClassifySendError(err, client.logger, tx, fromAddress, client.pool.ChainType().IsL2()) + returnCode := ClassifySendError(err, client.logger, tx, fromAddress, client.pool.ChainType().IsL2()) + return returnCode, err } // SendTransaction also uses the sendonly HTTP RPC URLs if set @@ -286,7 +288,7 @@ func (client *client) HeadByNumber(ctx context.Context, number *big.Int) (head * err = ethereum.NotFound return } - head.EVMChainID = utils.NewBig(client.ConfiguredChainID()) + head.EVMChainID = ubig.New(client.ConfiguredChainID()) return } @@ -299,7 +301,7 @@ func (client *client) HeadByHash(ctx context.Context, hash common.Hash) (head *e err = ethereum.NotFound return } - head.EVMChainID = utils.NewBig(client.ConfiguredChainID()) + head.EVMChainID = ubig.New(client.ConfiguredChainID()) return } diff --git a/core/chains/evm/client/client_test.go b/core/chains/evm/client/client_test.go index 631b5722dec..281b8bf4227 100644 --- a/core/chains/evm/client/client_test.go +++ b/core/chains/evm/client/client_test.go @@ -26,9 +26,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "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/utils" ) func mustNewClient(t *testing.T, wsURL string, sendonlys ...url.URL) client.Client { @@ -417,7 +417,7 @@ func TestEthClient_HeaderByNumber(t *testing.T) { func TestEthClient_SendTransaction_NoSecondaryURL(t *testing.T) { t.Parallel() - tx := types.NewTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + tx := cltest.NewLegacyTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { @@ -449,7 +449,7 @@ func TestEthClient_SendTransaction_NoSecondaryURL(t *testing.T) { func TestEthClient_SendTransaction_WithSecondaryURLs(t *testing.T) { t.Parallel() - tx := types.NewTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + tx := cltest.NewLegacyTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { switch method { @@ -494,7 +494,7 @@ func TestEthClient_SendTransactionReturnCode(t *testing.T) { t.Parallel() fromAddress := testutils.NewAddress() - tx := types.NewTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + tx := cltest.NewLegacyTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) t.Run("returns Fatal error type when error message is fatal", func(t *testing.T) { wsURL := testutils.NewWSServer(t, &cltest.FixtureChainID, func(method string, params gjson.Result) (resp testutils.JSONRPCResponse) { diff --git a/core/chains/evm/client/errors.go b/core/chains/evm/client/errors.go index 143a5f8806f..6488ba495c9 100644 --- a/core/chains/evm/client/errors.go +++ b/core/chains/evm/client/errors.go @@ -413,73 +413,78 @@ func ExtractRPCError(baseErr error) (*JsonError, error) { return &jErr, nil } -func ClassifySendError(err error, lggr logger.Logger, tx *types.Transaction, fromAddress common.Address, isL2 bool) (commonclient.SendTxReturnCode, error) { +func ClassifySendError(err error, lggr logger.SugaredLogger, tx *types.Transaction, fromAddress common.Address, isL2 bool) commonclient.SendTxReturnCode { sendError := NewSendError(err) if sendError == nil { - return commonclient.Successful, err + return commonclient.Successful } if sendError.Fatal() { - logger.Criticalw(lggr, "Fatal error sending transaction", "err", sendError, "etx", tx) + lggr.Criticalw("Fatal error sending transaction", "err", sendError, "etx", tx) // Attempt is thrown away in this case; we don't need it since it never got accepted by a node - return commonclient.Fatal, err + return commonclient.Fatal } if sendError.IsNonceTooLowError() || sendError.IsTransactionAlreadyMined() { + lggr.Debugw(fmt.Sprintf("Transaction already confirmed for this nonce: %d", tx.Nonce()), "err", sendError, "etx", tx) // Nonce too low indicated that a transaction at this nonce was confirmed already. // Mark it as TransactionAlreadyKnown. - return commonclient.TransactionAlreadyKnown, err + return commonclient.TransactionAlreadyKnown } if sendError.IsReplacementUnderpriced() { lggr.Errorw(fmt.Sprintf("Replacement transaction underpriced for eth_tx %x. "+ - "Eth node returned error: '%s'. "+ "Please note that using your node's private keys outside of the chainlink node is NOT SUPPORTED and can lead to missed transactions.", - tx.Hash(), err), "gasPrice", tx.GasPrice, "gasTipCap", tx.GasTipCap, "gasFeeCap", tx.GasFeeCap) + tx.Hash()), "gasPrice", tx.GasPrice, "gasTipCap", tx.GasTipCap, "gasFeeCap", tx.GasFeeCap, "err", sendError, "etx", tx) // Assume success and hand off to the next cycle. - return commonclient.Successful, err + return commonclient.Successful } if sendError.IsTransactionAlreadyInMempool() { - lggr.Debugw("Transaction already in mempool", "txHash", tx.Hash, "nodeErr", sendError.Error()) - return commonclient.Successful, err + lggr.Debugw("Transaction already in mempool", "etx", tx, "err", sendError) + return commonclient.Successful } if sendError.IsTemporarilyUnderpriced() { - lggr.Infow("Transaction temporarily underpriced", "err", sendError.Error()) - return commonclient.Successful, err + lggr.Infow("Transaction temporarily underpriced", "err", sendError) + return commonclient.Successful } if sendError.IsTerminallyUnderpriced() { - return commonclient.Underpriced, err + lggr.Errorw("Transaction terminally underpriced", "etx", tx, "err", sendError) + return commonclient.Underpriced } if sendError.L2FeeTooLow() || sendError.IsL2FeeTooHigh() || sendError.IsL2Full() { if isL2 { - return commonclient.FeeOutOfValidRange, err + lggr.Errorw("Transaction fee out of range", "err", sendError, "etx", tx) + return commonclient.FeeOutOfValidRange } - return commonclient.Unsupported, errors.Wrap(sendError, "this error type only handled for L2s") + lggr.Errorw("this error type only handled for L2s", "err", sendError, "etx", tx) + return commonclient.Unsupported } if sendError.IsNonceTooHighError() { // This error occurs when the tx nonce is greater than current_nonce + tx_count_in_mempool, // instead of keeping the tx in mempool. This can happen if previous transactions haven't // reached the client yet. The correct thing to do is to mark it as retryable. - lggr.Warnw("Transaction has a nonce gap.", "err", err) - return commonclient.Retryable, err + lggr.Warnw("Transaction has a nonce gap.", "err", sendError, "etx", tx) + return commonclient.Retryable } if sendError.IsInsufficientEth() { - logger.Criticalw(lggr, fmt.Sprintf("Tx %x with type 0x%d was rejected due to insufficient eth: %s\n"+ + lggr.Criticalw(fmt.Sprintf("Tx %x with type 0x%d was rejected due to insufficient eth: %s\n"+ "ACTION REQUIRED: Chainlink wallet with address 0x%x is OUT OF FUNDS", tx.Hash(), tx.Type(), sendError.Error(), fromAddress, - ), "err", sendError) - return commonclient.InsufficientFunds, err + ), "err", sendError, "etx", tx) + return commonclient.InsufficientFunds } if sendError.IsTimeout() { - return commonclient.Retryable, errors.Wrapf(sendError, "timeout while sending transaction %s", tx.Hash().Hex()) + lggr.Errorw(fmt.Sprintf("timeout while sending transaction %x", tx.Hash()), "err", sendError, "etx", tx) + return commonclient.Retryable } if sendError.IsTxFeeExceedsCap() { - logger.Criticalw(lggr, fmt.Sprintf("Sending transaction failed: %s", label.RPCTxFeeCapConfiguredIncorrectlyWarning), + lggr.Criticalw(fmt.Sprintf("Sending transaction failed: %s", label.RPCTxFeeCapConfiguredIncorrectlyWarning), "etx", tx, "err", sendError, "id", "RPCTxFeeCapExceeded", ) - return commonclient.ExceedsMaxFee, err + return commonclient.ExceedsMaxFee } - return commonclient.Unknown, err + lggr.Errorw("Unknown error encountered when sending transaction", "err", err, "etx", tx) + return commonclient.Unknown } // ClassifySendOnlyError handles SendOnly nodes error codes. In that case, we don't assume there is another transaction that will be correctly diff --git a/core/chains/evm/client/helpers_test.go b/core/chains/evm/client/helpers_test.go index 27b335534da..c2f60e13f55 100644 --- a/core/chains/evm/client/helpers_test.go +++ b/core/chains/evm/client/helpers_test.go @@ -42,7 +42,7 @@ func NewClientWithTestNode(t *testing.T, nodePoolCfg config.NodePool, noNewHeads return nil, errors.Errorf("ethereum url scheme must be websocket: %s", parsed.String()) } - lggr := logger.Test(t) + lggr := logger.Sugared(logger.Test(t)) n := NewNode(nodePoolCfg, noNewHeadsThreshold, lggr, *parsed, rpcHTTPURL, "eth-primary-0", id, chainID, 1) n.(*node).setLatestReceived(0, big.NewInt(0)) primaries := []Node{n} diff --git a/core/chains/evm/client/mocks/batch_sender.go b/core/chains/evm/client/mocks/batch_sender.go index 7f1a5bdee69..3d65749b5bc 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type BatchSender struct { func (_m *BatchSender) 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) diff --git a/core/chains/evm/client/mocks/client.go b/core/chains/evm/client/mocks/client.go index 22498370a2a..0b45894cf28 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -33,6 +33,10 @@ type Client struct { func (_m *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for BalanceAt") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (*big.Int, error)); ok { @@ -59,6 +63,10 @@ func (_m *Client) BalanceAt(ctx context.Context, account common.Address, blockNu func (_m *Client) 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) @@ -73,6 +81,10 @@ func (_m *Client) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error func (_m *Client) BatchCallContextAll(ctx context.Context, b []rpc.BatchElem) error { ret := _m.Called(ctx, b) + if len(ret) == 0 { + panic("no return value specified for BatchCallContextAll") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []rpc.BatchElem) error); ok { r0 = rf(ctx, b) @@ -87,6 +99,10 @@ func (_m *Client) BatchCallContextAll(ctx context.Context, b []rpc.BatchElem) er func (_m *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { ret := _m.Called(ctx, hash) + if len(ret) == 0 { + panic("no return value specified for BlockByHash") + } + var r0 *types.Block var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Block, error)); ok { @@ -113,6 +129,10 @@ func (_m *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo func (_m *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { ret := _m.Called(ctx, number) + if len(ret) == 0 { + panic("no return value specified for BlockByNumber") + } + var r0 *types.Block var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Block, error)); ok { @@ -142,6 +162,10 @@ func (_m *Client) CallContext(ctx context.Context, result interface{}, method st _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...) @@ -156,6 +180,10 @@ func (_m *Client) CallContext(ctx context.Context, result interface{}, method st func (_m *Client) 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 { @@ -182,6 +210,10 @@ func (_m *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockN func (_m *Client) ChainID() (*big.Int, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func() (*big.Int, error)); ok { @@ -213,6 +245,10 @@ func (_m *Client) Close() { func (_m *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for CodeAt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]byte, error)); ok { @@ -239,6 +275,10 @@ func (_m *Client) CodeAt(ctx context.Context, account common.Address, blockNumbe func (_m *Client) 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() @@ -255,6 +295,10 @@ func (_m *Client) ConfiguredChainID() *big.Int { func (_m *Client) Dial(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Dial") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -269,6 +313,10 @@ func (_m *Client) Dial(ctx context.Context) error { func (_m *Client) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { ret := _m.Called(ctx, call) + if len(ret) == 0 { + panic("no return value specified for EstimateGas") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg) (uint64, error)); ok { @@ -293,6 +341,10 @@ func (_m *Client) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint6 func (_m *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { ret := _m.Called(ctx, q) + if len(ret) == 0 { + panic("no return value specified for FilterLogs") + } + var r0 []types.Log var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery) ([]types.Log, error)); ok { @@ -319,6 +371,10 @@ func (_m *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]typ func (_m *Client) HeadByHash(ctx context.Context, n common.Hash) (*evmtypes.Head, error) { ret := _m.Called(ctx, n) + if len(ret) == 0 { + panic("no return value specified for HeadByHash") + } + var r0 *evmtypes.Head var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*evmtypes.Head, error)); ok { @@ -345,6 +401,10 @@ func (_m *Client) HeadByHash(ctx context.Context, n common.Hash) (*evmtypes.Head func (_m *Client) HeadByNumber(ctx context.Context, n *big.Int) (*evmtypes.Head, error) { ret := _m.Called(ctx, n) + if len(ret) == 0 { + panic("no return value specified for HeadByNumber") + } + var r0 *evmtypes.Head var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*evmtypes.Head, error)); ok { @@ -371,6 +431,10 @@ func (_m *Client) HeadByNumber(ctx context.Context, n *big.Int) (*evmtypes.Head, func (_m *Client) HeaderByHash(ctx context.Context, h common.Hash) (*types.Header, error) { ret := _m.Called(ctx, h) + if len(ret) == 0 { + panic("no return value specified for HeaderByHash") + } + var r0 *types.Header var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Header, error)); ok { @@ -397,6 +461,10 @@ func (_m *Client) HeaderByHash(ctx context.Context, h common.Hash) (*types.Heade func (_m *Client) HeaderByNumber(ctx context.Context, n *big.Int) (*types.Header, error) { ret := _m.Called(ctx, n) + if len(ret) == 0 { + panic("no return value specified for HeaderByNumber") + } + var r0 *types.Header var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Header, error)); ok { @@ -423,6 +491,10 @@ func (_m *Client) HeaderByNumber(ctx context.Context, n *big.Int) (*types.Header func (_m *Client) IsL2() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsL2") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -437,6 +509,10 @@ func (_m *Client) IsL2() bool { func (_m *Client) LINKBalance(ctx context.Context, address common.Address, linkAddress common.Address) (*assets.Link, error) { ret := _m.Called(ctx, address, linkAddress) + if len(ret) == 0 { + panic("no return value specified for LINKBalance") + } + var r0 *assets.Link var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, common.Address) (*assets.Link, error)); ok { @@ -463,6 +539,10 @@ func (_m *Client) LINKBalance(ctx context.Context, address common.Address, linkA func (_m *Client) LatestBlockHeight(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for LatestBlockHeight") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -489,6 +569,10 @@ func (_m *Client) LatestBlockHeight(ctx context.Context) (*big.Int, error) { func (_m *Client) NodeStates() map[string]string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for NodeStates") + } + var r0 map[string]string if rf, ok := ret.Get(0).(func() map[string]string); ok { r0 = rf() @@ -505,6 +589,10 @@ func (_m *Client) NodeStates() map[string]string { func (_m *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { ret := _m.Called(ctx, account) + if len(ret) == 0 { + panic("no return value specified for PendingCodeAt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) ([]byte, error)); ok { @@ -531,6 +619,10 @@ func (_m *Client) PendingCodeAt(ctx context.Context, account common.Address) ([] func (_m *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { ret := _m.Called(ctx, account) + if len(ret) == 0 { + panic("no return value specified for PendingNonceAt") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) (uint64, error)); ok { @@ -555,6 +647,10 @@ func (_m *Client) PendingNonceAt(ctx context.Context, account common.Address) (u func (_m *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error { ret := _m.Called(ctx, tx) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction) error); ok { r0 = rf(ctx, tx) @@ -569,6 +665,10 @@ func (_m *Client) SendTransaction(ctx context.Context, tx *types.Transaction) er func (_m *Client) SendTransactionReturnCode(ctx context.Context, tx *types.Transaction, fromAddress common.Address) (commonclient.SendTxReturnCode, error) { ret := _m.Called(ctx, tx, fromAddress) + if len(ret) == 0 { + panic("no return value specified for SendTransactionReturnCode") + } + var r0 commonclient.SendTxReturnCode var r1 error if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction, common.Address) (commonclient.SendTxReturnCode, error)); ok { @@ -593,6 +693,10 @@ func (_m *Client) SendTransactionReturnCode(ctx context.Context, tx *types.Trans func (_m *Client) SequenceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (evmtypes.Nonce, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for SequenceAt") + } + var r0 evmtypes.Nonce var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (evmtypes.Nonce, error)); ok { @@ -617,6 +721,10 @@ func (_m *Client) SequenceAt(ctx context.Context, account common.Address, blockN func (_m *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { ret := _m.Called(ctx, q, ch) + if len(ret) == 0 { + panic("no return value specified for SubscribeFilterLogs") + } + var r0 ethereum.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- types.Log) (ethereum.Subscription, error)); ok { @@ -643,6 +751,10 @@ func (_m *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuer func (_m *Client) SubscribeNewHead(ctx context.Context, ch chan<- *evmtypes.Head) (ethereum.Subscription, error) { ret := _m.Called(ctx, ch) + if len(ret) == 0 { + panic("no return value specified for SubscribeNewHead") + } + var r0 ethereum.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, chan<- *evmtypes.Head) (ethereum.Subscription, error)); ok { @@ -669,6 +781,10 @@ func (_m *Client) SubscribeNewHead(ctx context.Context, ch chan<- *evmtypes.Head func (_m *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for SuggestGasPrice") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -695,6 +811,10 @@ func (_m *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { func (_m *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for SuggestGasTipCap") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -721,6 +841,10 @@ func (_m *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { func (_m *Client) TokenBalance(ctx context.Context, address common.Address, contractAddress common.Address) (*big.Int, error) { ret := _m.Called(ctx, address, contractAddress) + if len(ret) == 0 { + panic("no return value specified for TokenBalance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, common.Address) (*big.Int, error)); ok { @@ -747,6 +871,10 @@ func (_m *Client) TokenBalance(ctx context.Context, address common.Address, cont func (_m *Client) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionByHash") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Transaction, error)); ok { @@ -773,6 +901,10 @@ func (_m *Client) TransactionByHash(ctx context.Context, txHash common.Hash) (*t func (_m *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionReceipt") + } + var r0 *types.Receipt var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Receipt, error)); ok { diff --git a/core/chains/evm/client/mocks/tx_sender.go b/core/chains/evm/client/mocks/tx_sender.go index 889069dcfca..a769a786a18 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type TxSender struct { func (_m *TxSender) ChainID(_a0 context.Context) (*big.Int, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -47,6 +51,10 @@ func (_m *TxSender) ChainID(_a0 context.Context) (*big.Int, error) { func (_m *TxSender) SendTransaction(ctx context.Context, tx *types.Transaction) error { ret := _m.Called(ctx, tx) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction) error); ok { r0 = rf(ctx, tx) diff --git a/core/chains/evm/client/node.go b/core/chains/evm/client/node.go index a2c8b807ba2..a27321535ed 100644 --- a/core/chains/evm/client/node.go +++ b/core/chains/evm/client/node.go @@ -137,7 +137,7 @@ type rawclient struct { type node struct { services.StateMachine lfcLog logger.Logger - rpcLog logger.Logger + rpcLog logger.SugaredLogger name string id int32 chainID *big.Int @@ -206,7 +206,7 @@ func NewNode(nodeCfg config.NodePool, noNewHeadsThreshold time.Duration, lggr lo "mode", n.getNodeMode(), ) n.lfcLog = logger.Named(lggr, "Lifecycle") - n.rpcLog = logger.Named(lggr, "RPC") + n.rpcLog = logger.Sugared(lggr).Named("RPC") n.stateLatestBlockNumber = -1 return n @@ -453,7 +453,7 @@ func (n *node) CallContext(ctx context.Context, result interface{}, method strin return err } defer cancel() - lggr := logger.With(n.newRqLggr(), + lggr := n.newRqLggr().With( "method", method, "args", args, ) @@ -478,9 +478,9 @@ func (n *node) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { return err } defer cancel() - lggr := logger.With(n.newRqLggr(), "nBatchElems", len(b), "batchElems", b) + lggr := n.newRqLggr().With("nBatchElems", len(b), "batchElems", b) - logger.Trace(lggr, "RPC call: evmclient.Client#BatchCallContext") + lggr.Trace("RPC call: evmclient.Client#BatchCallContext") start := time.Now() if http != nil { err = n.wrapHTTP(http.rpc.BatchCallContext(ctx, b)) @@ -500,7 +500,7 @@ func (n *node) EthSubscribe(ctx context.Context, channel chan<- *evmtypes.Head, return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "args", args) + lggr := n.newRqLggr().With("args", args) lggr.Debug("RPC call: evmclient.Client#EthSubscribe") start := time.Now() @@ -523,7 +523,7 @@ func (n *node) TransactionReceipt(ctx context.Context, txHash common.Hash) (rece return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "txHash", txHash) + lggr := n.newRqLggr().With("txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionReceipt") @@ -550,7 +550,7 @@ func (n *node) TransactionByHash(ctx context.Context, txHash common.Hash) (tx *t return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "txHash", txHash) + lggr := n.newRqLggr().With("txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionByHash") @@ -577,7 +577,7 @@ func (n *node) HeaderByNumber(ctx context.Context, number *big.Int) (header *typ return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "number", number) + lggr := n.newRqLggr().With("number", number) lggr.Debug("RPC call: evmclient.Client#HeaderByNumber") start := time.Now() @@ -601,7 +601,7 @@ func (n *node) HeaderByHash(ctx context.Context, hash common.Hash) (header *type return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "hash", hash) + lggr := n.newRqLggr().With("hash", hash) lggr.Debug("RPC call: evmclient.Client#HeaderByHash") start := time.Now() @@ -627,7 +627,7 @@ func (n *node) SendTransaction(ctx context.Context, tx *types.Transaction) error return err } defer cancel() - lggr := logger.With(n.newRqLggr(), "tx", tx) + lggr := n.newRqLggr().With("tx", tx) lggr.Debug("RPC call: evmclient.Client#SendTransaction") start := time.Now() @@ -650,7 +650,7 @@ func (n *node) PendingNonceAt(ctx context.Context, account common.Address) (nonc return 0, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "account", account) + lggr := n.newRqLggr().With("account", account) lggr.Debug("RPC call: evmclient.Client#PendingNonceAt") start := time.Now() @@ -679,7 +679,7 @@ func (n *node) NonceAt(ctx context.Context, account common.Address, blockNumber return 0, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "account", account, "blockNumber", blockNumber) + lggr := n.newRqLggr().With("account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#NonceAt") start := time.Now() @@ -705,7 +705,7 @@ func (n *node) PendingCodeAt(ctx context.Context, account common.Address) (code return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "account", account) + lggr := n.newRqLggr().With("account", account) lggr.Debug("RPC call: evmclient.Client#PendingCodeAt") start := time.Now() @@ -731,7 +731,7 @@ func (n *node) CodeAt(ctx context.Context, account common.Address, blockNumber * return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "account", account, "blockNumber", blockNumber) + lggr := n.newRqLggr().With("account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#CodeAt") start := time.Now() @@ -757,7 +757,7 @@ func (n *node) EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint return 0, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "call", call) + lggr := n.newRqLggr().With("call", call) lggr.Debug("RPC call: evmclient.Client#EstimateGas") start := time.Now() @@ -809,7 +809,7 @@ func (n *node) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumb return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "callMsg", msg, "blockNumber", blockNumber) + lggr := n.newRqLggr().With("callMsg", msg, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#CallContract") start := time.Now() @@ -836,7 +836,7 @@ func (n *node) BlockByNumber(ctx context.Context, number *big.Int) (b *types.Blo return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "number", number) + lggr := n.newRqLggr().With("number", number) lggr.Debug("RPC call: evmclient.Client#BlockByNumber") start := time.Now() @@ -862,7 +862,7 @@ func (n *node) BlockByHash(ctx context.Context, hash common.Hash) (b *types.Bloc return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "hash", hash) + lggr := n.newRqLggr().With("hash", hash) lggr.Debug("RPC call: evmclient.Client#BlockByHash") start := time.Now() @@ -914,7 +914,7 @@ func (n *node) BalanceAt(ctx context.Context, account common.Address, blockNumbe return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "account", account.Hex(), "blockNumber", blockNumber) + lggr := n.newRqLggr().With("account", account.Hex(), "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#BalanceAt") start := time.Now() @@ -940,7 +940,7 @@ func (n *node) FilterLogs(ctx context.Context, q ethereum.FilterQuery) (l []type return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "q", q) + lggr := n.newRqLggr().With("q", q) lggr.Debug("RPC call: evmclient.Client#FilterLogs") start := time.Now() @@ -966,7 +966,7 @@ func (n *node) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, return nil, err } defer cancel() - lggr := logger.With(n.newRqLggr(), "q", q) + lggr := n.newRqLggr().With("q", q) lggr.Debug("RPC call: evmclient.Client#SubscribeFilterLogs") start := time.Now() @@ -1011,10 +1011,8 @@ func (n *node) SuggestGasTipCap(ctx context.Context) (tipCap *big.Int, err error func (n *node) ChainID() (chainID *big.Int) { return n.chainID } // newRqLggr generates a new logger with a unique request ID -func (n *node) newRqLggr() logger.Logger { - return logger.With(n.rpcLog, - "requestID", uuid.New(), - ) +func (n *node) newRqLggr() logger.SugaredLogger { + return n.rpcLog.With("requestID", uuid.New()) } func (n *node) logResult( @@ -1025,17 +1023,14 @@ func (n *node) logResult( callName string, results ...interface{}, ) { - lggr = logger.With(lggr, "duration", callDuration, "rpcDomain", rpcDomain, "callName", callName) + slggr := logger.Sugared(lggr).With("duration", callDuration, "rpcDomain", rpcDomain, "callName", callName) promEVMPoolRPCNodeCalls.WithLabelValues(n.chainID.String(), n.name).Inc() if err == nil { promEVMPoolRPCNodeCallsSuccess.WithLabelValues(n.chainID.String(), n.name).Inc() - logger.Tracew(lggr, - fmt.Sprintf("evmclient.Client#%s RPC call success", callName), - results..., - ) + slggr.Tracew(fmt.Sprintf("evmclient.Client#%s RPC call success", callName), results...) } else { promEVMPoolRPCNodeCallsFailed.WithLabelValues(n.chainID.String(), n.name).Inc() - lggr.Debugw( + slggr.Debugw( fmt.Sprintf("evmclient.Client#%s RPC call failure", callName), append(results, "err", err)..., ) @@ -1062,7 +1057,7 @@ func (n *node) wrapHTTP(err error) error { if err != nil { n.rpcLog.Debugw("Call failed", "err", err) } else { - logger.Trace(n.rpcLog, "Call succeeded") + n.rpcLog.Trace("Call succeeded") } return err } diff --git a/core/chains/evm/client/node_lifecycle.go b/core/chains/evm/client/node_lifecycle.go index f838325a646..f2232a14935 100644 --- a/core/chains/evm/client/node_lifecycle.go +++ b/core/chains/evm/client/node_lifecycle.go @@ -12,10 +12,11 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/logger" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) var ( @@ -50,7 +51,7 @@ func zombieNodeCheckInterval(noNewHeadsThreshold time.Duration) time.Duration { if interval <= 0 || interval > queryTimeout { interval = queryTimeout } - return utils.WithJitter(interval) + return cutils.WithJitter(interval) } func (n *node) setLatestReceived(blockNumber int64, totalDifficulty *big.Int) { @@ -91,9 +92,8 @@ func (n *node) aliveLoop() { pollFailureThreshold := n.nodePoolCfg.PollFailureThreshold() pollInterval := n.nodePoolCfg.PollInterval() - lggr := logger.Named(n.lfcLog, "Alive") - lggr = logger.With(lggr, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) - logger.Tracew(lggr, "Alive loop starting", "nodeState", n.State()) + lggr := logger.Sugared(n.lfcLog).Named("Alive").With("noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold, "pollInterval", pollInterval, "pollFailureThreshold", pollFailureThreshold) + lggr.Tracew("Alive loop starting", "nodeState", n.State()) headsC := make(chan *evmtypes.Head) sub, err := n.EthSubscribe(n.nodeCtx, headsC, "newHeads") @@ -142,7 +142,7 @@ func (n *node) aliveLoop() { case <-pollCh: var version string promEVMPoolRPCNodePolls.WithLabelValues(n.chainID.String(), n.name).Inc() - logger.Tracew(lggr, "Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) + lggr.Tracew("Polling for version", "nodeState", n.State(), "pollFailures", pollFailures) ctx, cancel := context.WithTimeout(n.nodeCtx, pollInterval) ctx, cancel2 := n.makeQueryCtx(ctx) err := n.CallContext(ctx, &version, "web3_clientVersion") @@ -164,7 +164,7 @@ func (n *node) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint failed to respond to %d consecutive polls", pollFailures), "pollFailures", pollFailures, "nodeState", n.State()) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - logger.Criticalf(lggr, "RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint failed to respond to polls; %s %s", msgCannotDisable, msgDegradedState) continue } } @@ -176,7 +176,7 @@ func (n *node) aliveLoop() { // note: there must be another live node for us to be out of sync lggr.Errorw("RPC endpoint has fallen behind", "blockNumber", num, "totalDifficulty", td, "nodeState", n.State()) if liveNodes < 2 { - logger.Criticalf(lggr, "RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState) continue } n.declareOutOfSync(n.isOutOfSync) @@ -189,13 +189,13 @@ func (n *node) aliveLoop() { return } promEVMPoolRPCNodeNumSeenBlocks.WithLabelValues(n.chainID.String(), n.name).Inc() - logger.Tracew(lggr, "Got head", "head", bh) + lggr.Tracew("Got head", "head", bh) if bh.Number > highestReceivedBlockNumber { promEVMPoolRPCNodeHighestSeenBlock.WithLabelValues(n.chainID.String(), n.name).Set(float64(bh.Number)) - logger.Tracew(lggr, "Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) + lggr.Tracew("Got higher block number, resetting timer", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) highestReceivedBlockNumber = bh.Number } else { - logger.Tracew(lggr, "Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) + lggr.Tracew("Ignoring previously seen block number", "latestReceivedBlockNumber", highestReceivedBlockNumber, "blockNumber", bh.Number, "nodeState", n.State()) } if outOfSyncT != nil { outOfSyncT.Reset(noNewHeadsTimeoutThreshold) @@ -211,7 +211,7 @@ func (n *node) aliveLoop() { lggr.Errorw(fmt.Sprintf("RPC endpoint detected out of sync; no new heads received for %s (last head received was %v)", noNewHeadsTimeoutThreshold, highestReceivedBlockNumber), "nodeState", n.State(), "latestReceivedBlockNumber", highestReceivedBlockNumber, "noNewHeadsTimeoutThreshold", noNewHeadsTimeoutThreshold) if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 2 { - logger.Criticalf(lggr, "RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) + lggr.Criticalf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState) // We don't necessarily want to wait the full timeout to check again, we should // check regularly and log noisily in this state outOfSyncT.Reset(zombieNodeCheckInterval(n.noNewHeadsThreshold)) @@ -277,7 +277,7 @@ func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *big.Int) bool) { outOfSyncAt := time.Now() - lggr := logger.Named(n.lfcLog, "OutOfSync") + lggr := logger.Sugared(logger.Named(n.lfcLog, "OutOfSync")) lggr.Debugw("Trying to revive out-of-sync RPC node", "nodeState", n.State()) // Need to redial since out-of-sync nodes are automatically disconnected @@ -294,7 +294,7 @@ func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *big.Int) bool) { return } - logger.Tracew(lggr, "Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) + lggr.Tracew("Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) ch := make(chan *evmtypes.Head) subCtx, cancel := n.makeQueryCtx(n.nodeCtx) @@ -329,7 +329,7 @@ func (n *node) outOfSyncLoop(isOutOfSync func(num int64, td *big.Int) bool) { case <-time.After(zombieNodeCheckInterval(n.noNewHeadsThreshold)): if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 1 { - logger.Critical(lggr, "RPC endpoint is still out of sync, but there are no other available nodes. This RPC node will be forcibly moved back into the live pool in a degraded state") + lggr.Critical("RPC endpoint is still out of sync, but there are no other available nodes. This RPC node will be forcibly moved back into the live pool in a degraded state") n.declareInSync() return } @@ -359,7 +359,7 @@ func (n *node) unreachableLoop() { unreachableAt := time.Now() - lggr := logger.Named(n.lfcLog, "Unreachable") + lggr := logger.Sugared(logger.Named(n.lfcLog, "Unreachable")) lggr.Debugw("Trying to revive unreachable RPC node", "nodeState", n.State()) dialRetryBackoff := utils.NewRedialBackoff() @@ -369,7 +369,7 @@ func (n *node) unreachableLoop() { case <-n.nodeCtx.Done(): return case <-time.After(dialRetryBackoff.Duration()): - logger.Tracew(lggr, "Trying to re-dial RPC node", "nodeState", n.State()) + lggr.Tracew("Trying to re-dial RPC node", "nodeState", n.State()) err := n.dial(n.nodeCtx) if err != nil { diff --git a/core/chains/evm/client/node_lifecycle_test.go b/core/chains/evm/client/node_lifecycle_test.go index f097c2bc078..0fcaf54ae3d 100644 --- a/core/chains/evm/client/node_lifecycle_test.go +++ b/core/chains/evm/client/node_lifecycle_test.go @@ -556,7 +556,7 @@ func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { return }) - iN := NewNode(cfg, time.Duration(time.Second), logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) + iN := NewNode(cfg, time.Second, logger.Test(t), *s.WSURL(), nil, "test node", 42, testutils.FixtureChainID, 1) n := iN.(*node) dial(t, n) diff --git a/core/chains/evm/client/pool.go b/core/chains/evm/client/pool.go index 6c36cc3e987..b2d5a4847a5 100644 --- a/core/chains/evm/client/pool.go +++ b/core/chains/evm/client/pool.go @@ -17,10 +17,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/common/config" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -68,7 +68,7 @@ type Pool struct { sendonlys []SendOnlyNode chainID *big.Int chainType config.ChainType - logger logger.Logger + logger logger.SugaredLogger selectionMode string noNewHeadsThreshold time.Duration nodeSelector NodeSelector @@ -113,7 +113,7 @@ func NewPool(lggr logger.Logger, selectionMode string, leaseDuration time.Durati sendonlys: sendonlys, chainID: chainID, chainType: chainType, - logger: lggr, + logger: logger.Sugared(lggr), selectionMode: selectionMode, noNewHeadsThreshold: noNewHeadsTreshold, nodeSelector: nodeSelector, @@ -272,10 +272,10 @@ func (p *Pool) report() { } live := total - dead - logger.Tracew(p.logger, fmt.Sprintf("Pool state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) + p.logger.Tracew(fmt.Sprintf("Pool state: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) if total == dead { rerr := fmt.Errorf("no EVM primary nodes available: 0/%d nodes are alive", total) - logger.Criticalw(p.logger, rerr.Error(), "nodeStates", nodeStates) + p.logger.Criticalw(rerr.Error(), "nodeStates", nodeStates) p.SvcErrBuffer.Append(rerr) } else if dead > 0 { p.logger.Errorw(fmt.Sprintf("At least one EVM primary node is dead: %d/%d nodes are alive", live, total), "nodeStates", nodeStates) @@ -320,7 +320,7 @@ func (p *Pool) selectNode() (node Node) { p.activeNode = p.nodeSelector.Select() if p.activeNode == nil { - logger.Criticalw(p.logger, "No live RPC nodes available", "NodeSelectionMode", p.nodeSelector.Name()) + p.logger.Criticalw("No live RPC nodes available", "NodeSelectionMode", p.nodeSelector.Name()) errmsg := fmt.Errorf("no live nodes available for chain %s", p.chainID.String()) p.SvcErrBuffer.Append(errmsg) return &erroringNode{errMsg: errmsg.Error()} @@ -367,7 +367,7 @@ func (p *Pool) BatchCallContextAll(ctx context.Context, b []rpc.BatchElem) error if err != nil { p.logger.Debugw("Secondary node BatchCallContext failed", "err", err) } else { - logger.Trace(p.logger, "Secondary node BatchCallContext success") + p.logger.Trace("Secondary node BatchCallContext success") } }(n) } diff --git a/core/chains/evm/client/rpc_client.go b/core/chains/evm/client/rpc_client.go index 01851c4ae90..ac8c44ef901 100644 --- a/core/chains/evm/client/rpc_client.go +++ b/core/chains/evm/client/rpc_client.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" @@ -24,7 +25,8 @@ import ( commontypes "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // RPCCLient includes all the necessary generalized RPC methods along with any additional chain-specific methods. @@ -54,7 +56,7 @@ type RPCCLient interface { } type rpcClient struct { - rpcLog logger.Logger + rpcLog logger.SugaredLogger name string id int32 chainID *big.Int @@ -105,7 +107,7 @@ func NewRPCClient( "client", r.String(), "evmChainID", chainID, ) - r.rpcLog = logger.Named(lggr, "RPC") + r.rpcLog = logger.Sugared(lggr).Named("RPC") return r } @@ -116,9 +118,9 @@ func (r *rpcClient) Dial(callerCtx context.Context) error { defer cancel() promEVMPoolRPCNodeDials.WithLabelValues(r.chainID.String(), r.name).Inc() - lggr := logger.With(r.rpcLog, "wsuri", r.ws.uri.Redacted()) + lggr := r.rpcLog.With("wsuri", r.ws.uri.Redacted()) if r.http != nil { - lggr = logger.With(lggr, "httpuri", r.http.uri.Redacted()) + lggr = lggr.With("httpuri", r.http.uri.Redacted()) } lggr.Debugw("RPC dial: evmclient.Client#dial") @@ -147,7 +149,7 @@ func (r *rpcClient) Dial(callerCtx context.Context) error { // It can only return error if the URL is malformed. func (r *rpcClient) DialHTTP() error { promEVMPoolRPCNodeDials.WithLabelValues(r.chainID.String(), r.name).Inc() - lggr := logger.With(r.rpcLog, "httpuri", r.ws.uri.Redacted()) + lggr := r.rpcLog.With("httpuri", r.ws.uri.Redacted()) lggr.Debugw("RPC dial: evmclient.Client#dial") var httprpc *rpc.Client @@ -205,10 +207,7 @@ func (r *rpcClient) logResult( promEVMPoolRPCNodeCalls.WithLabelValues(r.chainID.String(), r.name).Inc() if err == nil { promEVMPoolRPCNodeCallsSuccess.WithLabelValues(r.chainID.String(), r.name).Inc() - logger.Tracew(lggr, - fmt.Sprintf("evmclient.Client#%s RPC call success", callName), - results..., - ) + logger.Sugared(lggr).Tracew(fmt.Sprintf("evmclient.Client#%s RPC call success", callName), results...) } else { promEVMPoolRPCNodeCallsFailed.WithLabelValues(r.chainID.String(), r.name).Inc() lggr.Debugw( @@ -298,7 +297,7 @@ func (r *rpcClient) CallContext(ctx context.Context, result interface{}, method return err } defer cancel() - lggr := logger.With(r.newRqLggr(), + lggr := r.newRqLggr().With( "method", method, "args", args, ) @@ -327,9 +326,9 @@ func (r *rpcClient) BatchCallContext(ctx context.Context, b []any) error { batch[i] = arg.(rpc.BatchElem) } defer cancel() - lggr := logger.With(r.newRqLggr(), "nBatchElems", len(b), "batchElems", b) + lggr := r.newRqLggr().With("nBatchElems", len(b), "batchElems", b) - logger.Trace(lggr, "RPC call: evmclient.Client#BatchCallContext") + lggr.Trace("RPC call: evmclient.Client#BatchCallContext") start := time.Now() if http != nil { err = r.wrapHTTP(http.rpc.BatchCallContext(ctx, batch)) @@ -349,7 +348,7 @@ func (r *rpcClient) Subscribe(ctx context.Context, channel chan<- *evmtypes.Head return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "args", args) + lggr := r.newRqLggr().With("args", args) lggr.Debug("RPC call: evmclient.Client#EthSubscribe") start := time.Now() @@ -384,7 +383,7 @@ func (r *rpcClient) TransactionReceiptGeth(ctx context.Context, txHash common.Ha return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "txHash", txHash) + lggr := r.newRqLggr().With("txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionReceipt") @@ -410,7 +409,7 @@ func (r *rpcClient) TransactionByHash(ctx context.Context, txHash common.Hash) ( return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "txHash", txHash) + lggr := r.newRqLggr().With("txHash", txHash) lggr.Debug("RPC call: evmclient.Client#TransactionByHash") @@ -437,7 +436,7 @@ func (r *rpcClient) HeaderByNumber(ctx context.Context, number *big.Int) (header return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "number", number) + lggr := r.newRqLggr().With("number", number) lggr.Debug("RPC call: evmclient.Client#HeaderByNumber") start := time.Now() @@ -461,7 +460,7 @@ func (r *rpcClient) HeaderByHash(ctx context.Context, hash common.Hash) (header return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "hash", hash) + lggr := r.newRqLggr().With("hash", hash) lggr.Debug("RPC call: evmclient.Client#HeaderByHash") start := time.Now() @@ -491,7 +490,7 @@ func (r *rpcClient) BlockByNumber(ctx context.Context, number *big.Int) (head *e err = ethereum.NotFound return } - head.EVMChainID = utils.NewBig(r.chainID) + head.EVMChainID = ubig.New(r.chainID) return } @@ -504,7 +503,7 @@ func (r *rpcClient) BlockByHash(ctx context.Context, hash common.Hash) (head *ev err = ethereum.NotFound return } - head.EVMChainID = utils.NewBig(r.chainID) + head.EVMChainID = ubig.New(r.chainID) return } @@ -514,7 +513,7 @@ func (r *rpcClient) BlockByHashGeth(ctx context.Context, hash common.Hash) (bloc return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "hash", hash) + lggr := r.newRqLggr().With("hash", hash) lggr.Debug("RPC call: evmclient.Client#BlockByHash") start := time.Now() @@ -540,7 +539,7 @@ func (r *rpcClient) BlockByNumberGeth(ctx context.Context, number *big.Int) (blo return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "number", number) + lggr := r.newRqLggr().With("number", number) lggr.Debug("RPC call: evmclient.Client#BlockByNumber") start := time.Now() @@ -566,7 +565,7 @@ func (r *rpcClient) SendTransaction(ctx context.Context, tx *types.Transaction) return err } defer cancel() - lggr := logger.With(r.newRqLggr(), "tx", tx) + lggr := r.newRqLggr().With("tx", tx) lggr.Debug("RPC call: evmclient.Client#SendTransaction") start := time.Now() @@ -606,7 +605,7 @@ func (r *rpcClient) PendingSequenceAt(ctx context.Context, account common.Addres return 0, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "account", account) + lggr := r.newRqLggr().With("account", account) lggr.Debug("RPC call: evmclient.Client#PendingNonceAt") start := time.Now() @@ -638,7 +637,7 @@ func (r *rpcClient) SequenceAt(ctx context.Context, account common.Address, bloc return 0, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "account", account, "blockNumber", blockNumber) + lggr := r.newRqLggr().With("account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#NonceAt") start := time.Now() @@ -667,7 +666,7 @@ func (r *rpcClient) PendingCodeAt(ctx context.Context, account common.Address) ( return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "account", account) + lggr := r.newRqLggr().With("account", account) lggr.Debug("RPC call: evmclient.Client#PendingCodeAt") start := time.Now() @@ -693,7 +692,7 @@ func (r *rpcClient) CodeAt(ctx context.Context, account common.Address, blockNum return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "account", account, "blockNumber", blockNumber) + lggr := r.newRqLggr().With("account", account, "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#CodeAt") start := time.Now() @@ -720,7 +719,7 @@ func (r *rpcClient) EstimateGas(ctx context.Context, c interface{}) (gas uint64, } defer cancel() call := c.(ethereum.CallMsg) - lggr := logger.With(r.newRqLggr(), "call", call) + lggr := r.newRqLggr().With("call", call) lggr.Debug("RPC call: evmclient.Client#EstimateGas") start := time.Now() @@ -772,18 +771,22 @@ func (r *rpcClient) CallContract(ctx context.Context, msg interface{}, blockNumb return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "callMsg", msg, "blockNumber", blockNumber) + lggr := r.newRqLggr().With("callMsg", msg, "blockNumber", blockNumber) message := msg.(ethereum.CallMsg) lggr.Debug("RPC call: evmclient.Client#CallContract") start := time.Now() + var hex hexutil.Bytes if http != nil { - val, err = http.geth.CallContract(ctx, message, blockNumber) + err = http.rpc.CallContext(ctx, &hex, "eth_call", toCallArg(message), toBlockNumArg(blockNumber)) err = r.wrapHTTP(err) } else { - val, err = ws.geth.CallContract(ctx, message, blockNumber) + err = ws.rpc.CallContext(ctx, &hex, "eth_call", toCallArg(message), toBlockNumArg(blockNumber)) err = r.wrapWS(err) } + if err == nil { + val = hex + } duration := time.Since(start) r.logResult(lggr, err, duration, r.getRPCDomain(), "CallContract", @@ -791,7 +794,82 @@ func (r *rpcClient) CallContract(ctx context.Context, msg interface{}, blockNumb ) return +} + +func (r *rpcClient) PendingCallContract(ctx context.Context, msg interface{}) (val []byte, err error) { + ctx, cancel, ws, http, err := r.makeLiveQueryCtxAndSafeGetClients(ctx) + if err != nil { + return nil, err + } + defer cancel() + lggr := r.newRqLggr().With("callMsg", msg) + message := msg.(ethereum.CallMsg) + + lggr.Debug("RPC call: evmclient.Client#PendingCallContract") + start := time.Now() + var hex hexutil.Bytes + if http != nil { + err = http.rpc.CallContext(ctx, &hex, "eth_call", toCallArg(message), "pending") + err = r.wrapHTTP(err) + } else { + err = ws.rpc.CallContext(ctx, &hex, "eth_call", toCallArg(message), "pending") + err = r.wrapWS(err) + } + if err == nil { + val = hex + } + duration := time.Since(start) + + r.logResult(lggr, err, duration, r.getRPCDomain(), "PendingCallContract", + "val", val, + ) + + return +} + +// COPIED FROM go-ethereum/ethclient/gethclient - must be kept up to date! +func toBlockNumArg(number *big.Int) string { + if number == nil { + return "latest" + } + if number.Sign() >= 0 { + return hexutil.EncodeBig(number) + } + // It's negative. + if number.IsInt64() { + return rpc.BlockNumber(number.Int64()).String() + } + // It's negative and large, which is invalid. + return fmt.Sprintf("", number) +} +// COPIED FROM go-ethereum/ethclient/gethclient - must be kept up to date! +// Modified to include legacy 'data' as well as 'input' in order to support non-compliant servers. +func toCallArg(msg ethereum.CallMsg) interface{} { + arg := map[string]interface{}{ + "from": msg.From, + "to": msg.To, + } + if len(msg.Data) > 0 { + arg["input"] = hexutil.Bytes(msg.Data) + arg["data"] = hexutil.Bytes(msg.Data) // duplicate legacy field for compatibility + } + if msg.Value != nil { + arg["value"] = (*hexutil.Big)(msg.Value) + } + if msg.Gas != 0 { + arg["gas"] = hexutil.Uint64(msg.Gas) + } + if msg.GasPrice != nil { + arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) + } + if msg.GasFeeCap != nil { + arg["maxFeePerGas"] = (*hexutil.Big)(msg.GasFeeCap) + } + if msg.GasTipCap != nil { + arg["maxPriorityFeePerGas"] = (*hexutil.Big)(msg.GasTipCap) + } + return arg } func (r *rpcClient) LatestBlockHeight(ctx context.Context) (*big.Int, error) { @@ -832,7 +910,7 @@ func (r *rpcClient) BalanceAt(ctx context.Context, account common.Address, block return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "account", account.Hex(), "blockNumber", blockNumber) + lggr := r.newRqLggr().With("account", account.Hex(), "blockNumber", blockNumber) lggr.Debug("RPC call: evmclient.Client#BalanceAt") start := time.Now() @@ -891,7 +969,7 @@ func (r *rpcClient) FilterLogs(ctx context.Context, q ethereum.FilterQuery) (l [ return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "q", q) + lggr := r.newRqLggr().With("q", q) lggr.Debug("RPC call: evmclient.Client#FilterLogs") start := time.Now() @@ -922,7 +1000,7 @@ func (r *rpcClient) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQu return nil, err } defer cancel() - lggr := logger.With(r.newRqLggr(), "q", q) + lggr := r.newRqLggr().With("q", q) lggr.Debug("RPC call: evmclient.Client#SubscribeFilterLogs") start := time.Now() @@ -982,10 +1060,8 @@ func (r *rpcClient) ChainID(ctx context.Context) (chainID *big.Int, err error) { } // newRqLggr generates a new logger with a unique request ID -func (r *rpcClient) newRqLggr() logger.Logger { - return logger.With(r.rpcLog, - "requestID", uuid.New(), - ) +func (r *rpcClient) newRqLggr() logger.SugaredLogger { + return r.rpcLog.With("requestID", uuid.New()) } func wrapCallError(err error, tp string) error { @@ -1008,7 +1084,7 @@ func (r *rpcClient) wrapHTTP(err error) error { if err != nil { r.rpcLog.Debugw("Call failed", "err", err) } else { - logger.Trace(r.rpcLog, "Call succeeded") + r.rpcLog.Trace("Call succeeded") } return err } diff --git a/core/chains/evm/client/send_only_node_lifecycle.go b/core/chains/evm/client/send_only_node_lifecycle.go index 9d704e49389..127a5c6678c 100644 --- a/core/chains/evm/client/send_only_node_lifecycle.go +++ b/core/chains/evm/client/send_only_node_lifecycle.go @@ -4,7 +4,7 @@ import ( "fmt" "time" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) // verifyLoop may only be triggered once, on Start, if initial chain ID check diff --git a/core/chains/evm/client/send_only_node_test.go b/core/chains/evm/client/send_only_node_test.go index 760f7f4d3eb..c2fdad06ec1 100644 --- a/core/chains/evm/client/send_only_node_test.go +++ b/core/chains/evm/client/send_only_node_test.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) @@ -95,7 +96,7 @@ func createSignedTx(t *testing.T, chainID *big.Int, nonce uint64, data []byte) * require.NoError(t, err) sender, err := bind.NewKeyedTransactorWithChainID(key, chainID) require.NoError(t, err) - tx := types.NewTransaction( + tx := cltest.NewLegacyTransaction( nonce, sender.From, assets.Ether(100).ToInt(), 21000, big.NewInt(1000000000), data, diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index 293bf64badc..bd2e959d9bc 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -23,7 +23,7 @@ import ( commonclient "github.com/smartcontractkit/chainlink/v2/common/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) func init() { @@ -197,7 +197,7 @@ func (c *SimulatedBackendClient) HeadByNumber(ctx context.Context, n *big.Int) ( return nil, ethereum.NotFound } return &evmtypes.Head{ - EVMChainID: utils.NewBigI(c.chainId.Int64()), + EVMChainID: ubig.NewI(c.chainId.Int64()), Hash: header.Hash(), Number: header.Number.Int64(), ParentHash: header.ParentHash, @@ -214,7 +214,7 @@ func (c *SimulatedBackendClient) HeadByHash(ctx context.Context, h common.Hash) return nil, ethereum.NotFound } return &evmtypes.Head{ - EVMChainID: utils.NewBigI(c.chainId.Int64()), + EVMChainID: ubig.NewI(c.chainId.Int64()), Hash: header.Hash(), Number: header.Number.Int64(), ParentHash: header.ParentHash, @@ -302,7 +302,7 @@ func (c *SimulatedBackendClient) SubscribeNewHead( case h := <-ch: var head *evmtypes.Head if h != nil { - head = &evmtypes.Head{Difficulty: h.Difficulty, Timestamp: time.Unix(int64(h.Time), 0), Number: h.Number.Int64(), Hash: h.Hash(), ParentHash: h.ParentHash, Parent: lastHead, EVMChainID: utils.NewBig(c.chainId)} + head = &evmtypes.Head{Difficulty: h.Difficulty, Timestamp: time.Unix(int64(h.Time), 0), Number: h.Number.Int64(), Hash: h.Hash(), ParentHash: h.ParentHash, Parent: lastHead, EVMChainID: ubig.New(c.chainId)} lastHead = head } select { diff --git a/core/chains/evm/config/config_test.go b/core/chains/evm/config/config_test.go index d34d1eae63e..cd1967b9582 100644 --- a/core/chains/evm/config/config_test.go +++ b/core/chains/evm/config/config_test.go @@ -11,23 +11,23 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + configurl "github.com/smartcontractkit/chainlink-common/pkg/config" 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/config/toml" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config" "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/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestChainScopedConfig(t *testing.T) { t.Parallel() gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - id := utils.NewBig(big.NewInt(rand.Int63())) + id := ubig.New(big.NewInt(rand.Int63())) c.EVM[0] = &toml.EVMConfig{ ChainID: id, Chain: toml.Defaults(id, &toml.Chain{ @@ -38,7 +38,7 @@ func TestChainScopedConfig(t *testing.T) { cfg := evmtest.NewChainScopedConfig(t, gcfg) overrides := func(c *chainlink.Config, s *chainlink.Secrets) { - id := utils.NewBig(big.NewInt(rand.Int63())) + id := ubig.New(big.NewInt(rand.Int63())) c.EVM[0] = &toml.EVMConfig{ ChainID: id, Chain: toml.Defaults(id, &toml.Chain{ @@ -65,12 +65,12 @@ func TestChainScopedConfig(t *testing.T) { t.Run("uses customer configured value when set", func(t *testing.T) { var override uint32 = 10 gasBumpOverrides := func(c *chainlink.Config, s *chainlink.Secrets) { - id := utils.NewBig(big.NewInt(rand.Int63())) + id := ubig.New(big.NewInt(rand.Int63())) c.EVM[0] = &toml.EVMConfig{ ChainID: id, Chain: toml.Defaults(id, &toml.Chain{ GasEstimator: toml.GasEstimator{ - BumpTxDepth: ptr(uint32(override)), + BumpTxDepth: ptr(override), }, }), } @@ -292,7 +292,7 @@ func TestChainScopedConfig_GasEstimator(t *testing.T) { func TestChainScopedConfig_BSCDefaults(t *testing.T) { chainID := big.NewInt(56) gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, secrets *chainlink.Secrets) { - id := utils.NewBig(chainID) + id := ubig.New(chainID) cfg := toml.Defaults(id) c.EVM[0] = &toml.EVMConfig{ ChainID: id, @@ -344,7 +344,7 @@ func TestChainScopedConfig_Profiles(t *testing.T) { t.Parallel() gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, secrets *chainlink.Secrets) { - id := utils.NewBigI(tt.chainID) + id := ubig.NewI(tt.chainID) cfg := toml.Defaults(id) c.EVM[0] = &toml.EVMConfig{ ChainID: id, @@ -379,12 +379,12 @@ func TestChainScopedConfig_HeadTracker(t *testing.T) { func Test_chainScopedConfig_Validate(t *testing.T) { configWithChains := func(t *testing.T, id int64, chains ...*toml.Chain) config.AppConfig { return configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - chainID := utils.NewBigI(id) + chainID := ubig.NewI(id) c.EVM[0] = &toml.EVMConfig{ChainID: chainID, Enabled: ptr(true), Chain: toml.Defaults(chainID, chains...), Nodes: toml.EVMNodes{{ Name: ptr("fake"), - WSURL: models.MustParseURL("wss://foo.test/ws"), - HTTPURL: models.MustParseURL("http://foo.test"), + WSURL: configurl.MustParseURL("wss://foo.test/ws"), + HTTPURL: configurl.MustParseURL("http://foo.test"), }}} }) } @@ -462,7 +462,7 @@ func Test_chainScopedConfig_Validate(t *testing.T) { func TestNodePoolConfig(t *testing.T) { gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - id := utils.NewBig(big.NewInt(rand.Int63())) + id := ubig.New(big.NewInt(rand.Int63())) c.EVM[0] = &toml.EVMConfig{ ChainID: id, Chain: toml.Defaults(id, &toml.Chain{}), diff --git a/core/chains/evm/config/mocks/chain_scoped_config.go b/core/chains/evm/config/mocks/chain_scoped_config.go index cb18282f495..badba1d69f3 100644 --- a/core/chains/evm/config/mocks/chain_scoped_config.go +++ b/core/chains/evm/config/mocks/chain_scoped_config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ type ChainScopedConfig struct { 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() @@ -40,6 +44,10 @@ func (_m *ChainScopedConfig) AppID() uuid.UUID { 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() @@ -56,6 +64,10 @@ func (_m *ChainScopedConfig) AuditLogger() coreconfig.AuditLogger { 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() @@ -72,6 +84,10 @@ func (_m *ChainScopedConfig) AutoPprof() coreconfig.AutoPprof { 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() @@ -86,6 +102,10 @@ func (_m *ChainScopedConfig) CosmosEnabled() bool { 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() @@ -102,6 +122,10 @@ func (_m *ChainScopedConfig) Database() coreconfig.Database { func (_m *ChainScopedConfig) EVM() config.EVM { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVM") + } + var r0 config.EVM if rf, ok := ret.Get(0).(func() config.EVM); ok { r0 = rf() @@ -118,6 +142,10 @@ func (_m *ChainScopedConfig) EVM() config.EVM { 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() @@ -132,6 +160,10 @@ func (_m *ChainScopedConfig) EVMEnabled() bool { 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() @@ -146,6 +178,10 @@ func (_m *ChainScopedConfig) EVMRPCEnabled() bool { 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() @@ -162,6 +198,10 @@ func (_m *ChainScopedConfig) Feature() coreconfig.Feature { 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() @@ -178,6 +218,10 @@ func (_m *ChainScopedConfig) FluxMonitor() coreconfig.FluxMonitor { 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() @@ -194,6 +238,10 @@ func (_m *ChainScopedConfig) Insecure() coreconfig.Insecure { 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() @@ -208,6 +256,10 @@ func (_m *ChainScopedConfig) InsecureFastScrypt() bool { 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() @@ -224,6 +276,10 @@ func (_m *ChainScopedConfig) JobPipeline() coreconfig.JobPipeline { 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() @@ -240,6 +296,10 @@ func (_m *ChainScopedConfig) Keeper() coreconfig.Keeper { 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() @@ -261,6 +321,10 @@ func (_m *ChainScopedConfig) LogConfiguration(log coreconfig.LogfFn, warn coreco 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() @@ -277,6 +341,10 @@ func (_m *ChainScopedConfig) Mercury() coreconfig.Mercury { 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() @@ -293,6 +361,10 @@ func (_m *ChainScopedConfig) OCR() coreconfig.OCR { 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() @@ -309,6 +381,10 @@ func (_m *ChainScopedConfig) OCR2() coreconfig.OCR2 { 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() @@ -325,6 +401,10 @@ func (_m *ChainScopedConfig) P2P() coreconfig.P2P { 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() @@ -341,6 +421,10 @@ func (_m *ChainScopedConfig) Password() coreconfig.Password { 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() @@ -357,6 +441,10 @@ func (_m *ChainScopedConfig) Prometheus() coreconfig.Prometheus { 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() @@ -373,6 +461,10 @@ func (_m *ChainScopedConfig) Pyroscope() coreconfig.Pyroscope { 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() @@ -387,6 +479,10 @@ func (_m *ChainScopedConfig) RootDir() string { 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() @@ -403,6 +499,10 @@ func (_m *ChainScopedConfig) Sentry() coreconfig.Sentry { 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) @@ -427,6 +527,10 @@ func (_m *ChainScopedConfig) SetPasswords(keystore *string, vrf *string) { 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() @@ -441,6 +545,10 @@ func (_m *ChainScopedConfig) ShutdownGracePeriod() time.Duration { 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() @@ -455,6 +563,10 @@ func (_m *ChainScopedConfig) SolanaEnabled() bool { 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() @@ -469,6 +581,10 @@ func (_m *ChainScopedConfig) StarkNetEnabled() bool { 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() @@ -485,6 +601,10 @@ func (_m *ChainScopedConfig) TelemetryIngress() coreconfig.TelemetryIngress { 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() @@ -501,6 +621,10 @@ func (_m *ChainScopedConfig) Threshold() coreconfig.Threshold { 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() @@ -517,6 +641,10 @@ func (_m *ChainScopedConfig) Tracing() coreconfig.Tracing { 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() @@ -531,6 +659,10 @@ func (_m *ChainScopedConfig) Validate() error { 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() @@ -545,6 +677,10 @@ func (_m *ChainScopedConfig) ValidateDB() error { 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() diff --git a/core/chains/evm/config/mocks/gas_estimator.go b/core/chains/evm/config/mocks/gas_estimator.go index 6260b3cd501..69a2c852757 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type GasEstimator struct { func (_m *GasEstimator) BlockHistory() config.BlockHistory { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockHistory") + } + var r0 config.BlockHistory if rf, ok := ret.Get(0).(func() config.BlockHistory); ok { r0 = rf() @@ -36,6 +40,10 @@ func (_m *GasEstimator) BlockHistory() config.BlockHistory { func (_m *GasEstimator) BumpMin() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BumpMin") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -52,6 +60,10 @@ func (_m *GasEstimator) BumpMin() *assets.Wei { func (_m *GasEstimator) BumpPercent() uint16 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BumpPercent") + } + var r0 uint16 if rf, ok := ret.Get(0).(func() uint16); ok { r0 = rf() @@ -66,6 +78,10 @@ func (_m *GasEstimator) BumpPercent() uint16 { func (_m *GasEstimator) BumpThreshold() uint64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BumpThreshold") + } + var r0 uint64 if rf, ok := ret.Get(0).(func() uint64); ok { r0 = rf() @@ -80,6 +96,10 @@ func (_m *GasEstimator) BumpThreshold() uint64 { func (_m *GasEstimator) BumpTxDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BumpTxDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -94,6 +114,10 @@ func (_m *GasEstimator) BumpTxDepth() uint32 { func (_m *GasEstimator) EIP1559DynamicFees() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EIP1559DynamicFees") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -108,6 +132,10 @@ func (_m *GasEstimator) EIP1559DynamicFees() bool { func (_m *GasEstimator) FeeCapDefault() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FeeCapDefault") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -124,6 +152,10 @@ func (_m *GasEstimator) FeeCapDefault() *assets.Wei { func (_m *GasEstimator) LimitDefault() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitDefault") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -138,6 +170,10 @@ func (_m *GasEstimator) LimitDefault() uint32 { func (_m *GasEstimator) LimitJobType() config.LimitJobType { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitJobType") + } + var r0 config.LimitJobType if rf, ok := ret.Get(0).(func() config.LimitJobType); ok { r0 = rf() @@ -154,6 +190,10 @@ func (_m *GasEstimator) LimitJobType() config.LimitJobType { func (_m *GasEstimator) LimitMax() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitMax") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -168,6 +208,10 @@ func (_m *GasEstimator) LimitMax() uint32 { func (_m *GasEstimator) LimitMultiplier() float32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitMultiplier") + } + var r0 float32 if rf, ok := ret.Get(0).(func() float32); ok { r0 = rf() @@ -182,6 +226,10 @@ func (_m *GasEstimator) LimitMultiplier() float32 { func (_m *GasEstimator) LimitTransfer() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitTransfer") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -196,6 +244,10 @@ func (_m *GasEstimator) LimitTransfer() uint32 { func (_m *GasEstimator) Mode() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Mode") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -210,6 +262,10 @@ func (_m *GasEstimator) Mode() string { func (_m *GasEstimator) PriceDefault() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for PriceDefault") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -226,6 +282,10 @@ func (_m *GasEstimator) PriceDefault() *assets.Wei { func (_m *GasEstimator) PriceMax() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for PriceMax") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -242,6 +302,10 @@ func (_m *GasEstimator) PriceMax() *assets.Wei { func (_m *GasEstimator) PriceMaxKey(_a0 common.Address) *assets.Wei { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for PriceMaxKey") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func(common.Address) *assets.Wei); ok { r0 = rf(_a0) @@ -258,6 +322,10 @@ func (_m *GasEstimator) PriceMaxKey(_a0 common.Address) *assets.Wei { func (_m *GasEstimator) PriceMin() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for PriceMin") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -274,6 +342,10 @@ func (_m *GasEstimator) PriceMin() *assets.Wei { func (_m *GasEstimator) TipCapDefault() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TipCapDefault") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() @@ -290,6 +362,10 @@ func (_m *GasEstimator) TipCapDefault() *assets.Wei { func (_m *GasEstimator) TipCapMin() *assets.Wei { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TipCapMin") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func() *assets.Wei); ok { r0 = rf() diff --git a/core/chains/evm/config/toml/config.go b/core/chains/evm/config/toml/config.go index 9e51d5be790..2348e648696 100644 --- a/core/chains/evm/config/toml/config.go +++ b/core/chains/evm/config/toml/config.go @@ -6,24 +6,22 @@ import ( "slices" "strconv" - "github.com/ethereum/go-ethereum/core/txpool" + "github.com/ethereum/go-ethereum/core/txpool/legacypool" "github.com/pelletier/go-toml/v2" "github.com/shopspring/decimal" "go.uber.org/multierr" "gopkg.in/guregu/null.v4" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" - configutils "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) type HasEVMConfigs interface { @@ -38,41 +36,41 @@ func (cs EVMConfigs) ValidateConfig() (err error) { func (cs EVMConfigs) validateKeys() (err error) { // Unique chain IDs - chainIDs := configutils.UniqueStrings{} + chainIDs := commonconfig.UniqueStrings{} for i, c := range cs { if chainIDs.IsDupeFmt(c.ChainID) { - err = multierr.Append(err, configutils.NewErrDuplicate(fmt.Sprintf("%d.ChainID", i), c.ChainID.String())) + err = multierr.Append(err, commonconfig.NewErrDuplicate(fmt.Sprintf("%d.ChainID", i), c.ChainID.String())) } } // Unique node names - names := configutils.UniqueStrings{} + names := commonconfig.UniqueStrings{} for i, c := range cs { for j, n := range c.Nodes { if names.IsDupe(n.Name) { - err = multierr.Append(err, configutils.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.Name", i, j), *n.Name)) + err = multierr.Append(err, commonconfig.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.Name", i, j), *n.Name)) } } } // Unique node WSURLs - wsURLs := configutils.UniqueStrings{} + wsURLs := commonconfig.UniqueStrings{} for i, c := range cs { for j, n := range c.Nodes { u := (*url.URL)(n.WSURL) if wsURLs.IsDupeFmt(u) { - err = multierr.Append(err, configutils.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.WSURL", i, j), u.String())) + err = multierr.Append(err, commonconfig.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.WSURL", i, j), u.String())) } } } // Unique node HTTPURLs - httpURLs := configutils.UniqueStrings{} + httpURLs := commonconfig.UniqueStrings{} for i, c := range cs { for j, n := range c.Nodes { u := (*url.URL)(n.HTTPURL) if httpURLs.IsDupeFmt(u) { - err = multierr.Append(err, configutils.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.HTTPURL", i, j), u.String())) + err = multierr.Append(err, commonconfig.NewErrDuplicate(fmt.Sprintf("%d.Nodes.%d.HTTPURL", i, j), u.String())) } } } @@ -107,7 +105,7 @@ func (cs EVMConfigs) totalChains() int { } return total } -func (cs EVMConfigs) Chains(ids ...relay.ChainID) (r []commontypes.ChainStatus, total int, err error) { +func (cs EVMConfigs) Chains(ids ...string) (r []commontypes.ChainStatus, total int, err error) { total = cs.totalChains() for _, ch := range cs { if ch == nil { @@ -154,14 +152,14 @@ func (cs EVMConfigs) NodeStatus(name string) (commontypes.NodeStatus, error) { for i := range cs { for _, n := range cs[i].Nodes { if n.Name != nil && *n.Name == name { - return nodeStatus(n, relay.ChainID(cs[i].ChainID.String())) + return nodeStatus(n, cs[i].ChainID.String()) } } } return commontypes.NodeStatus{}, fmt.Errorf("node %s: %w", name, chains.ErrNotFound) } -func legacyNode(n *Node, chainID *utils.Big) (v2 types.Node) { +func legacyNode(n *Node, chainID *big.Big) (v2 types.Node) { v2.Name = *n.Name v2.EVMChainID = *chainID if n.HTTPURL != nil { @@ -179,7 +177,7 @@ func legacyNode(n *Node, chainID *utils.Big) (v2 types.Node) { return } -func nodeStatus(n *Node, chainID relay.ChainID) (commontypes.NodeStatus, error) { +func nodeStatus(n *Node, chainID string) (commontypes.NodeStatus, error) { var s commontypes.NodeStatus s.ChainID = chainID s.Name = *n.Name @@ -191,7 +189,7 @@ func nodeStatus(n *Node, chainID relay.ChainID) (commontypes.NodeStatus, error) return s, nil } -func (cs EVMConfigs) nodes(id relay.ChainID) (ns EVMNodes) { +func (cs EVMConfigs) nodes(id string) (ns EVMNodes) { for _, c := range cs { if c.ChainID.String() == id { return c.Nodes @@ -200,7 +198,7 @@ func (cs EVMConfigs) nodes(id relay.ChainID) (ns EVMNodes) { return nil } -func (cs EVMConfigs) Nodes(chainID relay.ChainID) (ns []types.Node, err error) { +func (cs EVMConfigs) Nodes(chainID string) (ns []types.Node, err error) { evmID, err := ChainIDInt64(chainID) if err != nil { return nil, fmt.Errorf("invalid evm chain id %q : %w", chainID, err) @@ -215,19 +213,19 @@ func (cs EVMConfigs) Nodes(chainID relay.ChainID) (ns []types.Node, err error) { continue } - ns = append(ns, legacyNode(n, utils.NewBigI(evmID))) + ns = append(ns, legacyNode(n, big.NewI(evmID))) } return } -func (cs EVMConfigs) NodeStatuses(chainIDs ...relay.ChainID) (ns []commontypes.NodeStatus, err error) { +func (cs EVMConfigs) NodeStatuses(chainIDs ...string) (ns []commontypes.NodeStatus, err error) { if len(chainIDs) == 0 { for i := range cs { for _, n := range cs[i].Nodes { if n == nil { continue } - n2, err := nodeStatus(n, relay.ChainID(cs[i].ChainID.String())) + n2, err := nodeStatus(n, cs[i].ChainID.String()) if err != nil { return nil, err } @@ -268,7 +266,7 @@ func (ns *EVMNodes) SetFrom(fs *EVMNodes) { } type EVMConfig struct { - ChainID *utils.Big + ChainID *big.Big Enabled *bool Chain Nodes EVMNodes @@ -291,29 +289,29 @@ func (c *EVMConfig) SetFrom(f *EVMConfig) { func (c *EVMConfig) ValidateConfig() (err error) { if c.ChainID == nil { - err = multierr.Append(err, configutils.ErrMissing{Name: "ChainID", Msg: "required for all chains"}) + err = multierr.Append(err, commonconfig.ErrMissing{Name: "ChainID", Msg: "required for all chains"}) } else if c.ChainID.String() == "" { - err = multierr.Append(err, configutils.ErrEmpty{Name: "ChainID", Msg: "required for all chains"}) + err = multierr.Append(err, commonconfig.ErrEmpty{Name: "ChainID", Msg: "required for all chains"}) } else if must, ok := ChainTypeForID(c.ChainID); ok { // known chain id if c.ChainType == nil && must != "" { - err = multierr.Append(err, configutils.ErrMissing{Name: "ChainType", + err = multierr.Append(err, commonconfig.ErrMissing{Name: "ChainType", Msg: fmt.Sprintf("only %q can be used with this chain id", must)}) } else if c.ChainType != nil && *c.ChainType != string(must) { if *c.ChainType == "" { - err = multierr.Append(err, configutils.ErrEmpty{Name: "ChainType", + err = multierr.Append(err, commonconfig.ErrEmpty{Name: "ChainType", Msg: fmt.Sprintf("only %q can be used with this chain id", must)}) } else if must == "" { - err = multierr.Append(err, configutils.ErrInvalid{Name: "ChainType", Value: *c.ChainType, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "ChainType", Value: *c.ChainType, Msg: "must not be set with this chain id"}) } else { - err = multierr.Append(err, configutils.ErrInvalid{Name: "ChainType", Value: *c.ChainType, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "ChainType", Value: *c.ChainType, Msg: fmt.Sprintf("only %q can be used with this chain id", must)}) } } } if len(c.Nodes) == 0 { - err = multierr.Append(err, configutils.ErrMissing{Name: "Nodes", Msg: "must have at least one node"}) + err = multierr.Append(err, commonconfig.ErrMissing{Name: "Nodes", Msg: "must have at least one node"}) } else { var hasPrimary bool for _, n := range c.Nodes { @@ -324,7 +322,7 @@ func (c *EVMConfig) ValidateConfig() (err error) { break } if !hasPrimary { - err = multierr.Append(err, configutils.ErrMissing{Name: "Nodes", + err = multierr.Append(err, commonconfig.ErrMissing{Name: "Nodes", Msg: "must have at least one primary node with WSURL"}) } } @@ -352,12 +350,12 @@ type Chain struct { FlagsContractAddress *ethkey.EIP55Address LinkContractAddress *ethkey.EIP55Address LogBackfillBatchSize *uint32 - LogPollInterval *models.Duration + LogPollInterval *commonconfig.Duration LogKeepBlocksDepth *uint32 MinIncomingConfirmations *uint32 MinContractPayment *commonassets.Link NonceAutoSync *bool - NoNewHeadsThreshold *models.Duration + NoNewHeadsThreshold *commonconfig.Duration OperatorFactoryAddress *ethkey.EIP55Address RPCDefaultBatchSize *uint32 RPCBlockQueryDelay *uint16 @@ -378,24 +376,24 @@ func (c *Chain) ValidateConfig() (err error) { chainType = config.ChainType(*c.ChainType) } if !chainType.IsValid() { - err = multierr.Append(err, configutils.ErrInvalid{Name: "ChainType", Value: *c.ChainType, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "ChainType", Value: *c.ChainType, Msg: config.ErrInvalidChainType.Error()}) } - if c.GasEstimator.BumpTxDepth != nil && uint32(*c.GasEstimator.BumpTxDepth) > *c.Transactions.MaxInFlight { - err = multierr.Append(err, configutils.ErrInvalid{Name: "GasEstimator.BumpTxDepth", Value: *c.GasEstimator.BumpTxDepth, + if c.GasEstimator.BumpTxDepth != nil && *c.GasEstimator.BumpTxDepth > *c.Transactions.MaxInFlight { + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "GasEstimator.BumpTxDepth", Value: *c.GasEstimator.BumpTxDepth, Msg: "must be less than or equal to Transactions.MaxInFlight"}) } if *c.HeadTracker.HistoryDepth < *c.FinalityDepth { - err = multierr.Append(err, configutils.ErrInvalid{Name: "HeadTracker.HistoryDepth", Value: *c.HeadTracker.HistoryDepth, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "HeadTracker.HistoryDepth", Value: *c.HeadTracker.HistoryDepth, Msg: "must be equal to or greater than FinalityDepth"}) } if *c.FinalityDepth < 1 { - err = multierr.Append(err, configutils.ErrInvalid{Name: "FinalityDepth", Value: *c.FinalityDepth, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "FinalityDepth", Value: *c.FinalityDepth, Msg: "must be greater than or equal to 1"}) } if *c.MinIncomingConfirmations < 1 { - err = multierr.Append(err, configutils.ErrInvalid{Name: "MinIncomingConfirmations", Value: *c.MinIncomingConfirmations, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "MinIncomingConfirmations", Value: *c.MinIncomingConfirmations, Msg: "must be greater than or equal to 1"}) } return @@ -405,9 +403,9 @@ type Transactions struct { ForwardersEnabled *bool MaxInFlight *uint32 MaxQueued *uint32 - ReaperInterval *models.Duration - ReaperThreshold *models.Duration - ResendAfterThreshold *models.Duration + ReaperInterval *commonconfig.Duration + ReaperThreshold *commonconfig.Duration + ResendAfterThreshold *commonconfig.Duration } func (t *Transactions) setFrom(f *Transactions) { @@ -487,37 +485,37 @@ type GasEstimator struct { } func (e *GasEstimator) ValidateConfig() (err error) { - if uint64(*e.BumpPercent) < txpool.DefaultConfig.PriceBump { - err = multierr.Append(err, configutils.ErrInvalid{Name: "BumpPercent", Value: *e.BumpPercent, - Msg: fmt.Sprintf("may not be less than Geth's default of %d", txpool.DefaultConfig.PriceBump)}) + if uint64(*e.BumpPercent) < legacypool.DefaultConfig.PriceBump { + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "BumpPercent", Value: *e.BumpPercent, + Msg: fmt.Sprintf("may not be less than Geth's default of %d", legacypool.DefaultConfig.PriceBump)}) } if e.TipCapDefault.Cmp(e.TipCapMin) < 0 { - err = multierr.Append(err, configutils.ErrInvalid{Name: "TipCapDefault", Value: e.TipCapDefault, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "TipCapDefault", Value: e.TipCapDefault, Msg: "must be greater than or equal to TipCapMinimum"}) } if e.FeeCapDefault.Cmp(e.TipCapDefault) < 0 { - err = multierr.Append(err, configutils.ErrInvalid{Name: "FeeCapDefault", Value: e.TipCapDefault, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "FeeCapDefault", Value: e.TipCapDefault, Msg: "must be greater than or equal to TipCapDefault"}) } if *e.Mode == "FixedPrice" && *e.BumpThreshold == 0 && *e.EIP1559DynamicFees && e.FeeCapDefault.Cmp(e.PriceMax) != 0 { - err = multierr.Append(err, configutils.ErrInvalid{Name: "FeeCapDefault", Value: e.FeeCapDefault, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "FeeCapDefault", Value: e.FeeCapDefault, Msg: fmt.Sprintf("must be equal to PriceMax (%s) since you are using FixedPrice estimation with gas bumping disabled in "+ "EIP1559 mode - PriceMax will be used as the FeeCap for transactions instead of FeeCapDefault", e.PriceMax)}) } else if e.FeeCapDefault.Cmp(e.PriceMax) > 0 { - err = multierr.Append(err, configutils.ErrInvalid{Name: "FeeCapDefault", Value: e.FeeCapDefault, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "FeeCapDefault", Value: e.FeeCapDefault, Msg: fmt.Sprintf("must be less than or equal to PriceMax (%s)", e.PriceMax)}) } if e.PriceMin.Cmp(e.PriceDefault) > 0 { - err = multierr.Append(err, configutils.ErrInvalid{Name: "PriceMin", Value: e.PriceMin, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "PriceMin", Value: e.PriceMin, Msg: "must be less than or equal to PriceDefault"}) } if e.PriceMax.Cmp(e.PriceDefault) < 0 { - err = multierr.Append(err, configutils.ErrInvalid{Name: "PriceMax", Value: e.PriceMin, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "PriceMax", Value: e.PriceMin, Msg: "must be greater than or equal to PriceDefault"}) } if *e.Mode == "BlockHistory" && *e.BlockHistory.BlockHistorySize <= 0 { - err = multierr.Append(err, configutils.ErrInvalid{Name: "BlockHistory.BlockHistorySize", Value: *e.BlockHistory.BlockHistorySize, + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "BlockHistory.BlockHistorySize", Value: *e.BlockHistory.BlockHistorySize, Msg: "must be greater than or equal to 1 with BlockHistory Mode"}) } @@ -644,7 +642,7 @@ func (ks KeySpecificConfig) ValidateConfig() (err error) { for _, k := range ks { addr := k.Key.String() if _, ok := addrs[addr]; ok { - err = multierr.Append(err, configutils.NewErrDuplicate("Key", addr)) + err = multierr.Append(err, commonconfig.NewErrDuplicate("Key", addr)) } else { addrs[addr] = struct{}{} } @@ -670,7 +668,7 @@ func (e *KeySpecificGasEstimator) setFrom(f *KeySpecificGasEstimator) { type HeadTracker struct { HistoryDepth *uint32 MaxBufferSize *uint32 - SamplingInterval *models.Duration + SamplingInterval *commonconfig.Duration } func (t *HeadTracker) setFrom(f *HeadTracker) { @@ -687,10 +685,10 @@ func (t *HeadTracker) setFrom(f *HeadTracker) { type NodePool struct { PollFailureThreshold *uint32 - PollInterval *models.Duration + PollInterval *commonconfig.Duration SelectionMode *string SyncThreshold *uint32 - LeaseDuration *models.Duration + LeaseDuration *commonconfig.Duration } func (p *NodePool) setFrom(f *NodePool) { @@ -713,11 +711,11 @@ func (p *NodePool) setFrom(f *NodePool) { type OCR struct { ContractConfirmations *uint16 - ContractTransmitterTransmitTimeout *models.Duration - DatabaseTimeout *models.Duration - DeltaCOverride *models.Duration - DeltaCJitterOverride *models.Duration - ObservationGracePeriod *models.Duration + ContractTransmitterTransmitTimeout *commonconfig.Duration + DatabaseTimeout *commonconfig.Duration + DeltaCOverride *commonconfig.Duration + DeltaCJitterOverride *commonconfig.Duration + ObservationGracePeriod *commonconfig.Duration } func (o *OCR) setFrom(f *OCR) { @@ -743,17 +741,17 @@ func (o *OCR) setFrom(f *OCR) { type Node struct { Name *string - WSURL *models.URL - HTTPURL *models.URL + WSURL *commonconfig.URL + HTTPURL *commonconfig.URL SendOnly *bool Order *int32 } func (n *Node) ValidateConfig() (err error) { if n.Name == nil { - err = multierr.Append(err, configutils.ErrMissing{Name: "Name", Msg: "required for all nodes"}) + err = multierr.Append(err, commonconfig.ErrMissing{Name: "Name", Msg: "required for all nodes"}) } else if *n.Name == "" { - err = multierr.Append(err, configutils.ErrEmpty{Name: "Name", Msg: "required for all nodes"}) + err = multierr.Append(err, commonconfig.ErrEmpty{Name: "Name", Msg: "required for all nodes"}) } var sendOnly bool @@ -762,34 +760,34 @@ func (n *Node) ValidateConfig() (err error) { } if n.WSURL == nil { if !sendOnly { - err = multierr.Append(err, configutils.ErrMissing{Name: "WSURL", Msg: "required for primary nodes"}) + err = multierr.Append(err, commonconfig.ErrMissing{Name: "WSURL", Msg: "required for primary nodes"}) } } else if n.WSURL.IsZero() { if !sendOnly { - err = multierr.Append(err, configutils.ErrEmpty{Name: "WSURL", Msg: "required for primary nodes"}) + err = multierr.Append(err, commonconfig.ErrEmpty{Name: "WSURL", Msg: "required for primary nodes"}) } } else { switch n.WSURL.Scheme { case "ws", "wss": default: - err = multierr.Append(err, configutils.ErrInvalid{Name: "WSURL", Value: n.WSURL.Scheme, Msg: "must be ws or wss"}) + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "WSURL", Value: n.WSURL.Scheme, Msg: "must be ws or wss"}) } } if n.HTTPURL == nil { - err = multierr.Append(err, configutils.ErrMissing{Name: "HTTPURL", Msg: "required for all nodes"}) + err = multierr.Append(err, commonconfig.ErrMissing{Name: "HTTPURL", Msg: "required for all nodes"}) } else if n.HTTPURL.IsZero() { - err = multierr.Append(err, configutils.ErrEmpty{Name: "HTTPURL", Msg: "required for all nodes"}) + err = multierr.Append(err, commonconfig.ErrEmpty{Name: "HTTPURL", Msg: "required for all nodes"}) } else { switch n.HTTPURL.Scheme { case "http", "https": default: - err = multierr.Append(err, configutils.ErrInvalid{Name: "HTTPURL", Value: n.HTTPURL.Scheme, Msg: "must be http or https"}) + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "HTTPURL", Value: n.HTTPURL.Scheme, Msg: "must be http or https"}) } } if n.Order != nil && (*n.Order < 1 || *n.Order > 100) { - err = multierr.Append(err, configutils.ErrInvalid{Name: "Order", Value: *n.Order, Msg: "must be between 1 and 100"}) + err = multierr.Append(err, commonconfig.ErrInvalid{Name: "Order", Value: *n.Order, Msg: "must be between 1 and 100"}) } else if n.Order == nil { z := int32(100) n.Order = &z @@ -816,6 +814,6 @@ func (n *Node) SetFrom(f *Node) { } } -func ChainIDInt64(cid relay.ChainID) (int64, error) { +func ChainIDInt64(cid string) (int64, error) { return strconv.ParseInt(cid, 10, 64) } diff --git a/core/chains/evm/config/toml/defaults.go b/core/chains/evm/config/toml/defaults.go index d362e9ac3dc..5e9a10de003 100644 --- a/core/chains/evm/config/toml/defaults.go +++ b/core/chains/evm/config/toml/defaults.go @@ -8,9 +8,9 @@ import ( "slices" "strings" + cconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/common/config" - "github.com/smartcontractkit/chainlink/v2/core/utils" - configutils "github.com/smartcontractkit/chainlink/v2/core/utils/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) var ( @@ -21,7 +21,7 @@ var ( defaultNames = map[string]string{} // DefaultIDs is the set of chain ids which have defaults. - DefaultIDs []*utils.Big + DefaultIDs []*big.Big ) func init() { @@ -36,11 +36,11 @@ func init() { log.Fatalf("failed to read %q: %v", path, err) } var config = struct { - ChainID *utils.Big + ChainID *big.Big Chain }{} - if err := configutils.DecodeTOML(bytes.NewReader(b), &config); err != nil { + if err := cconfig.DecodeTOML(bytes.NewReader(b), &config); err != nil { log.Fatalf("failed to decode %q: %v", path, err) } if fe.Name() == "fallback.toml" { @@ -61,13 +61,13 @@ func init() { defaults[id] = config.Chain defaultNames[id] = strings.ReplaceAll(strings.TrimSuffix(fe.Name(), ".toml"), "_", " ") } - slices.SortFunc(DefaultIDs, func(a, b *utils.Big) int { + slices.SortFunc(DefaultIDs, func(a, b *big.Big) int { return a.Cmp(b) }) } // DefaultsNamed returns the default Chain values, optionally for the given chainID, as well as a name if the chainID is known. -func DefaultsNamed(chainID *utils.Big) (c Chain, name string) { +func DefaultsNamed(chainID *big.Big) (c Chain, name string) { c.SetFrom(&fallback) if chainID == nil { return @@ -82,7 +82,7 @@ func DefaultsNamed(chainID *utils.Big) (c Chain, name string) { // Defaults returns a Chain based on the defaults for chainID and fields from with, applied in order so later Chains // override earlier ones. -func Defaults(chainID *utils.Big, with ...*Chain) Chain { +func Defaults(chainID *big.Big, with ...*Chain) Chain { c, _ := DefaultsNamed(chainID) for _, w := range with { c.SetFrom(w) @@ -90,7 +90,7 @@ func Defaults(chainID *utils.Big, with ...*Chain) Chain { return c } -func ChainTypeForID(chainID *utils.Big) (config.ChainType, bool) { +func ChainTypeForID(chainID *big.Big) (config.ChainType, bool) { s := chainID.String() if d, ok := defaults[s]; ok { if d.ChainType == nil { diff --git a/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml b/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml index 56ed84c7f38..e087b86fe3e 100644 --- a/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml +++ b/core/chains/evm/config/toml/defaults/Scroll_Mainnet.toml @@ -1,5 +1,6 @@ ChainID = '534352' FinalityDepth = 1 +ChainType = 'scroll' LogPollInterval = '3s' MinIncomingConfirmations = 1 # Scroll only emits blocks when a new tx is received, so this method of liveness detection is not useful diff --git a/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml b/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml index af17c4d485e..9db7a8ebed5 100644 --- a/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml +++ b/core/chains/evm/config/toml/defaults/Scroll_Sepolia.toml @@ -1,5 +1,6 @@ ChainID = '534351' FinalityDepth = 1 +ChainType = 'scroll' LogPollInterval = '3s' MinIncomingConfirmations = 1 # Scroll only emits blocks when a new tx is received, so this method of liveness detection is not useful diff --git a/core/chains/evm/forwarders/forwarder.go b/core/chains/evm/forwarders/forwarder.go index 0221c39e0a6..a0f6334a2c7 100644 --- a/core/chains/evm/forwarders/forwarder.go +++ b/core/chains/evm/forwarders/forwarder.go @@ -5,14 +5,14 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // Forwarder is the struct for Forwarder Addresses type Forwarder struct { ID int64 Address common.Address - EVMChainID utils.Big + EVMChainID big.Big CreatedAt time.Time UpdatedAt time.Time } diff --git a/core/chains/evm/forwarders/forwarder_manager.go b/core/chains/evm/forwarders/forwarder_manager.go index eaf0c32afe3..cabedf79aee 100644 --- a/core/chains/evm/forwarders/forwarder_manager.go +++ b/core/chains/evm/forwarders/forwarder_manager.go @@ -14,15 +14,16 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmlogpoller "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_receiver" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/offchain_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var forwardABI = evmtypes.MustGetABI(authorized_forwarder.AuthorizedForwarderABI).Methods["forward"] @@ -79,7 +80,7 @@ func (f *FwdMgr) Start(ctx context.Context) error { f.logger.Debug("Initializing EVM forwarder manager") chainId := f.evmClient.ConfiguredChainID() - fwdrs, err := f.ORM.FindForwardersByChain(utils.Big(*chainId)) + fwdrs, err := f.ORM.FindForwardersByChain(big.Big(*chainId)) if err != nil { return errors.Wrapf(err, "Failed to retrieve forwarders for chain %d", chainId) } @@ -112,7 +113,7 @@ func FilterName(addr common.Address) string { func (f *FwdMgr) ForwarderFor(addr common.Address) (forwarder common.Address, err error) { // Gets forwarders for current chain. - fwdrs, err := f.ORM.FindForwardersByChain(utils.Big(*f.evmClient.ConfiguredChainID())) + fwdrs, err := f.ORM.FindForwardersByChain(big.Big(*f.evmClient.ConfiguredChainID())) if err != nil { return common.Address{}, err } @@ -235,7 +236,7 @@ func (f *FwdMgr) runLoop() { defer f.wg.Done() tick := time.After(0) - for ; ; tick = time.After(utils.WithJitter(time.Duration(time.Minute))) { + for ; ; tick = time.After(utils.WithJitter(time.Minute)) { select { case <-tick: if err := f.logpoller.Ready(); err != nil { diff --git a/core/chains/evm/forwarders/forwarder_manager_test.go b/core/chains/evm/forwarders/forwarder_manager_test.go index 1da638e743d..5ef150aa5c3 100644 --- a/core/chains/evm/forwarders/forwarder_manager_test.go +++ b/core/chains/evm/forwarders/forwarder_manager_test.go @@ -12,10 +12,13 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_receiver" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" @@ -24,7 +27,6 @@ import ( "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/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var GetAuthorisedSendersABI = evmtypes.MustGetABI(authorized_receiver.AuthorizedReceiverABI).Methods["getAuthorizedSenders"] @@ -62,9 +64,9 @@ func TestFwdMgr_MaybeForwardTransaction(t *testing.T) { fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM(), evmcfg.Database()) fwdMgr.ORM = forwarders.NewORM(db, logger.Test(t), cfg.Database()) - fwd, err := fwdMgr.ORM.CreateForwarder(forwarderAddr, utils.Big(*testutils.FixtureChainID)) + fwd, err := fwdMgr.ORM.CreateForwarder(forwarderAddr, ubig.Big(*testutils.FixtureChainID)) require.NoError(t, err) - lst, err := fwdMgr.ORM.FindForwardersByChain(utils.Big(*testutils.FixtureChainID)) + lst, err := fwdMgr.ORM.FindForwardersByChain(ubig.Big(*testutils.FixtureChainID)) require.NoError(t, err) require.Equal(t, len(lst), 1) require.Equal(t, lst[0].Address, forwarderAddr) @@ -115,9 +117,9 @@ func TestFwdMgr_AccountUnauthorizedToForward_SkipsForwarding(t *testing.T) { fwdMgr := forwarders.NewFwdMgr(db, evmClient, lp, lggr, evmcfg.EVM(), evmcfg.Database()) fwdMgr.ORM = forwarders.NewORM(db, logger.Test(t), cfg.Database()) - _, err = fwdMgr.ORM.CreateForwarder(forwarderAddr, utils.Big(*testutils.FixtureChainID)) + _, err = fwdMgr.ORM.CreateForwarder(forwarderAddr, ubig.Big(*testutils.FixtureChainID)) require.NoError(t, err) - lst, err := fwdMgr.ORM.FindForwardersByChain(utils.Big(*testutils.FixtureChainID)) + lst, err := fwdMgr.ORM.FindForwardersByChain(ubig.Big(*testutils.FixtureChainID)) require.NoError(t, err) require.Equal(t, len(lst), 1) require.Equal(t, lst[0].Address, forwarderAddr) diff --git a/core/chains/evm/forwarders/mocks/orm.go b/core/chains/evm/forwarders/mocks/orm.go index e8ab62ce7de..691fbce8e9c 100644 --- a/core/chains/evm/forwarders/mocks/orm.go +++ b/core/chains/evm/forwarders/mocks/orm.go @@ -1,15 +1,16 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks import ( common "github.com/ethereum/go-ethereum/common" + big "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + forwarders "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + mock "github.com/stretchr/testify/mock" pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - - utils "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ORM is an autogenerated mock type for the ORM type @@ -18,21 +19,25 @@ type ORM struct { } // CreateForwarder provides a mock function with given fields: addr, evmChainId -func (_m *ORM) CreateForwarder(addr common.Address, evmChainId utils.Big) (forwarders.Forwarder, error) { +func (_m *ORM) CreateForwarder(addr common.Address, evmChainId big.Big) (forwarders.Forwarder, error) { ret := _m.Called(addr, evmChainId) + if len(ret) == 0 { + panic("no return value specified for CreateForwarder") + } + var r0 forwarders.Forwarder var r1 error - if rf, ok := ret.Get(0).(func(common.Address, utils.Big) (forwarders.Forwarder, error)); ok { + if rf, ok := ret.Get(0).(func(common.Address, big.Big) (forwarders.Forwarder, error)); ok { return rf(addr, evmChainId) } - if rf, ok := ret.Get(0).(func(common.Address, utils.Big) forwarders.Forwarder); ok { + if rf, ok := ret.Get(0).(func(common.Address, big.Big) forwarders.Forwarder); ok { r0 = rf(addr, evmChainId) } else { r0 = ret.Get(0).(forwarders.Forwarder) } - if rf, ok := ret.Get(1).(func(common.Address, utils.Big) error); ok { + if rf, ok := ret.Get(1).(func(common.Address, big.Big) error); ok { r1 = rf(addr, evmChainId) } else { r1 = ret.Error(1) @@ -45,6 +50,10 @@ func (_m *ORM) CreateForwarder(addr common.Address, evmChainId utils.Big) (forwa func (_m *ORM) DeleteForwarder(id int64, cleanup func(pg.Queryer, int64, common.Address) error) error { ret := _m.Called(id, cleanup) + if len(ret) == 0 { + panic("no return value specified for DeleteForwarder") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, func(pg.Queryer, int64, common.Address) error) error); ok { r0 = rf(id, cleanup) @@ -59,6 +68,10 @@ func (_m *ORM) DeleteForwarder(id int64, cleanup func(pg.Queryer, int64, common. func (_m *ORM) FindForwarders(offset int, limit int) ([]forwarders.Forwarder, int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for FindForwarders") + } + var r0 []forwarders.Forwarder var r1 int var r2 error @@ -89,15 +102,19 @@ func (_m *ORM) FindForwarders(offset int, limit int) ([]forwarders.Forwarder, in } // FindForwardersByChain provides a mock function with given fields: evmChainId -func (_m *ORM) FindForwardersByChain(evmChainId utils.Big) ([]forwarders.Forwarder, error) { +func (_m *ORM) FindForwardersByChain(evmChainId big.Big) ([]forwarders.Forwarder, error) { ret := _m.Called(evmChainId) + if len(ret) == 0 { + panic("no return value specified for FindForwardersByChain") + } + var r0 []forwarders.Forwarder var r1 error - if rf, ok := ret.Get(0).(func(utils.Big) ([]forwarders.Forwarder, error)); ok { + if rf, ok := ret.Get(0).(func(big.Big) ([]forwarders.Forwarder, error)); ok { return rf(evmChainId) } - if rf, ok := ret.Get(0).(func(utils.Big) []forwarders.Forwarder); ok { + if rf, ok := ret.Get(0).(func(big.Big) []forwarders.Forwarder); ok { r0 = rf(evmChainId) } else { if ret.Get(0) != nil { @@ -105,7 +122,7 @@ func (_m *ORM) FindForwardersByChain(evmChainId utils.Big) ([]forwarders.Forward } } - if rf, ok := ret.Get(1).(func(utils.Big) error); ok { + if rf, ok := ret.Get(1).(func(big.Big) error); ok { r1 = rf(evmChainId) } else { r1 = ret.Error(1) @@ -115,15 +132,19 @@ func (_m *ORM) FindForwardersByChain(evmChainId utils.Big) ([]forwarders.Forward } // FindForwardersInListByChain provides a mock function with given fields: evmChainId, addrs -func (_m *ORM) FindForwardersInListByChain(evmChainId utils.Big, addrs []common.Address) ([]forwarders.Forwarder, error) { +func (_m *ORM) FindForwardersInListByChain(evmChainId big.Big, addrs []common.Address) ([]forwarders.Forwarder, error) { ret := _m.Called(evmChainId, addrs) + if len(ret) == 0 { + panic("no return value specified for FindForwardersInListByChain") + } + var r0 []forwarders.Forwarder var r1 error - if rf, ok := ret.Get(0).(func(utils.Big, []common.Address) ([]forwarders.Forwarder, error)); ok { + if rf, ok := ret.Get(0).(func(big.Big, []common.Address) ([]forwarders.Forwarder, error)); ok { return rf(evmChainId, addrs) } - if rf, ok := ret.Get(0).(func(utils.Big, []common.Address) []forwarders.Forwarder); ok { + if rf, ok := ret.Get(0).(func(big.Big, []common.Address) []forwarders.Forwarder); ok { r0 = rf(evmChainId, addrs) } else { if ret.Get(0) != nil { @@ -131,7 +152,7 @@ func (_m *ORM) FindForwardersInListByChain(evmChainId utils.Big, addrs []common. } } - if rf, ok := ret.Get(1).(func(utils.Big, []common.Address) error); ok { + if rf, ok := ret.Get(1).(func(big.Big, []common.Address) error); ok { r1 = rf(evmChainId, addrs) } else { r1 = ret.Error(1) diff --git a/core/chains/evm/forwarders/orm.go b/core/chains/evm/forwarders/orm.go index 104e2574252..2a455360190 100644 --- a/core/chains/evm/forwarders/orm.go +++ b/core/chains/evm/forwarders/orm.go @@ -8,18 +8,18 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore type ORM interface { - CreateForwarder(addr common.Address, evmChainId utils.Big) (fwd Forwarder, err error) + CreateForwarder(addr common.Address, evmChainId big.Big) (fwd Forwarder, err error) FindForwarders(offset, limit int) ([]Forwarder, int, error) - FindForwardersByChain(evmChainId utils.Big) ([]Forwarder, error) + FindForwardersByChain(evmChainId big.Big) ([]Forwarder, error) DeleteForwarder(id int64, cleanup func(tx pg.Queryer, evmChainId int64, addr common.Address) error) error - FindForwardersInListByChain(evmChainId utils.Big, addrs []common.Address) ([]Forwarder, error) + FindForwardersInListByChain(evmChainId big.Big, addrs []common.Address) ([]Forwarder, error) } type orm struct { @@ -33,7 +33,7 @@ func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *orm { } // CreateForwarder creates the Forwarder address associated with the current EVM chain id. -func (o *orm) CreateForwarder(addr common.Address, evmChainId utils.Big) (fwd Forwarder, err error) { +func (o *orm) CreateForwarder(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.q.Get(&fwd, sql, addr, evmChainId) return fwd, err @@ -93,13 +93,13 @@ func (o *orm) FindForwarders(offset, limit int) (fwds []Forwarder, count int, er } // FindForwardersByChain returns all forwarder addresses for a chain. -func (o *orm) FindForwardersByChain(evmChainId utils.Big) (fwds []Forwarder, err error) { +func (o *orm) FindForwardersByChain(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.q.Select(&fwds, sql, evmChainId) return } -func (o *orm) FindForwardersInListByChain(evmChainId utils.Big, addrs []common.Address) ([]Forwarder, error) { +func (o *orm) FindForwardersInListByChain(evmChainId big.Big, addrs []common.Address) ([]Forwarder, error) { var fwdrs []Forwarder arg := map[string]interface{}{ diff --git a/core/chains/evm/forwarders/orm_test.go b/core/chains/evm/forwarders/orm_test.go index ba9664c196a..e95ac3778c6 100644 --- a/core/chains/evm/forwarders/orm_test.go +++ b/core/chains/evm/forwarders/orm_test.go @@ -10,10 +10,10 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/jmoiron/sqlx" ) @@ -42,7 +42,7 @@ func Test_DeleteForwarder(t *testing.T) { addr := testutils.NewAddress() chainID := testutils.FixtureChainID - fwd, err := orm.CreateForwarder(addr, *utils.NewBig(chainID)) + fwd, err := orm.CreateForwarder(addr, *big.New(chainID)) require.NoError(t, err) assert.Equal(t, addr, fwd.Address) diff --git a/core/chains/evm/gas/arbitrum_estimator.go b/core/chains/evm/gas/arbitrum_estimator.go index ee020f67002..ca819ba04b3 100644 --- a/core/chains/evm/gas/arbitrum_estimator.go +++ b/core/chains/evm/gas/arbitrum_estimator.go @@ -15,11 +15,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" 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/utils" ) type ArbConfig interface { diff --git a/core/chains/evm/gas/arbitrum_estimator_test.go b/core/chains/evm/gas/arbitrum_estimator_test.go index 53f81617988..9d56e2c10ad 100644 --- a/core/chains/evm/gas/arbitrum_estimator_test.go +++ b/core/chains/evm/gas/arbitrum_estimator_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "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" @@ -66,8 +67,7 @@ func TestArbitrumEstimator(t *testing.T) { }).Return(zeros.Bytes(), nil) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) // Expected price for a standard l2_suggested_estimator would be 42, but we add a fixed gasPriceBufferPercentage. @@ -92,8 +92,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, assets.NewWeiI(40)) require.Error(t, err) assert.EqualError(t, err, "estimated gas price: 42 wei is greater than the maximum gas price configured: 40 wei") @@ -118,8 +117,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, assets.NewWeiI(110)) assert.EqualError(t, err, "estimated gas price: 120 wei is greater than the maximum gas price configured: 110 wei") assert.Nil(t, gasPrice) @@ -148,8 +146,7 @@ func TestArbitrumEstimator(t *testing.T) { assert.Equal(t, big.NewInt(-1), blockNumber) }).Return(zeros.Bytes(), nil) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "failed to estimate gas; gas price not set") @@ -181,8 +178,7 @@ func TestArbitrumEstimator(t *testing.T) { }).Return(b.Bytes(), nil) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) require.NotNil(t, gasPrice) @@ -216,8 +212,7 @@ func TestArbitrumEstimator(t *testing.T) { }).Return(b.Bytes(), nil) o := gas.NewArbitrumEstimator(logger.Test(t), &arbConfig{v: maxGasLimit}, rpcClient, ethClient) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + 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 64dc331f657..b94083a1ae7 100644 --- a/core/chains/evm/gas/block_history_estimator.go +++ b/core/chains/evm/gas/block_history_estimator.go @@ -17,6 +17,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/common/config" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" @@ -24,8 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) // MaxStartTime is the maximum amount of time we are allowed to spend @@ -109,7 +109,7 @@ type ( blocks []evmtypes.Block blocksMu sync.RWMutex size int64 - mb *utils.Mailbox[*evmtypes.Head] + mb *mailbox.Mailbox[*evmtypes.Head] wg *sync.WaitGroup ctx context.Context ctxCancel context.CancelFunc @@ -139,7 +139,7 @@ func NewBlockHistoryEstimator(lggr logger.Logger, ethClient evmclient.Client, cf blocks: make([]evmtypes.Block, 0), // Must have enough blocks for both estimator and connectivity checker size: int64(mathutil.Max(bhCfg.BlockHistorySize(), bhCfg.CheckInclusionBlocks())), - mb: utils.NewSingleMailbox[*evmtypes.Head](), + mb: mailbox.NewSingle[*evmtypes.Head](), wg: new(sync.WaitGroup), ctx: ctx, ctxCancel: cancel, @@ -198,7 +198,7 @@ func (b *BlockHistoryEstimator) getBlocks() []evmtypes.Block { // The provided context can be used to terminate Start sequence. func (b *BlockHistoryEstimator) Start(ctx context.Context) error { return b.StartOnce("BlockHistoryEstimator", func() error { - logger.Trace(b.logger, "Starting") + b.logger.Trace("Starting") if b.bhConfig.CheckInclusionBlocks() > 0 { b.logger.Infof("Inclusion checking enabled, bumping will be prevented on transactions that have been priced above the %d percentile for %d blocks", b.bhConfig.CheckInclusionPercentile(), b.bhConfig.CheckInclusionBlocks()) @@ -228,7 +228,7 @@ func (b *BlockHistoryEstimator) Start(ctx context.Context) error { b.wg.Add(1) go b.runLoop() - logger.Trace(b.logger, "Started") + b.logger.Trace("Started") return nil }) } @@ -291,7 +291,7 @@ func (b *BlockHistoryEstimator) BumpLegacyGas(_ context.Context, originalGasPric if b.bhConfig.CheckInclusionBlocks() > 0 { if err = b.checkConnectivity(attempts); err != nil { if errors.Is(err, commonfee.ErrConnectivity) { - logger.Criticalw(b.logger, BumpingHaltedLabel, "err", err) + b.logger.Criticalw(BumpingHaltedLabel, "err", err) b.SvcErrBuffer.Append(err) promBlockHistoryEstimatorConnectivityFailureCount.WithLabelValues(b.chainID.String(), "legacy").Inc() } @@ -467,7 +467,7 @@ func (b *BlockHistoryEstimator) BumpDynamicFee(_ context.Context, originalFee Dy if b.bhConfig.CheckInclusionBlocks() > 0 { if err = b.checkConnectivity(attempts); err != nil { if errors.Is(err, commonfee.ErrConnectivity) { - logger.Criticalw(b.logger, BumpingHaltedLabel, "err", err) + b.logger.Criticalw(BumpingHaltedLabel, "err", err) b.SvcErrBuffer.Append(err) promBlockHistoryEstimatorConnectivityFailureCount.WithLabelValues(b.chainID.String(), "eip1559").Inc() } @@ -508,7 +508,7 @@ func (b *BlockHistoryEstimator) FetchBlocksAndRecalculate(ctx context.Context, h func (b *BlockHistoryEstimator) Recalculate(head *evmtypes.Head) { percentile := int(b.bhConfig.TransactionPercentile()) - lggr := logger.With(b.logger, "head", head) + lggr := b.logger.With("head", head) blockHistory := b.getBlocks() if len(blockHistory) == 0 { @@ -630,9 +630,9 @@ func (b *BlockHistoryEstimator) FetchBlocks(ctx context.Context, head *evmtypes. reqs = append(reqs, req) } - lggr := logger.With(b.logger, "head", head) + lggr := b.logger.With("head", head) - logger.Tracew(lggr, fmt.Sprintf("Fetching %v blocks (%v in local history)", len(reqs), len(blocks)), "n", len(reqs), "inHistory", len(blocks), "blockNum", head.Number) + lggr.Tracew(fmt.Sprintf("Fetching %v blocks (%v in local history)", len(reqs), len(blocks)), "n", len(reqs), "inHistory", len(blocks), "blockNum", head.Number) if err := b.batchFetch(ctx, reqs); err != nil { return err } @@ -713,7 +713,7 @@ func (b *BlockHistoryEstimator) batchFetch(ctx context.Context, reqs []rpc.Batch j = len(reqs) } - logger.Tracew(b.logger, fmt.Sprintf("Batch fetching blocks %v thru %v", HexToInt64(reqs[i].Args[0]), HexToInt64(reqs[j-1].Args[0]))) + b.logger.Tracew(fmt.Sprintf("Batch fetching blocks %v thru %v", HexToInt64(reqs[i].Args[0]), HexToInt64(reqs[j-1].Args[0]))) err := b.ethClient.BatchCallContext(ctx, reqs[i:j]) if errors.Is(err, context.DeadlineExceeded) { @@ -858,42 +858,46 @@ func (b *BlockHistoryEstimator) EffectiveGasPrice(block evmtypes.Block, tx evmty switch tx.Type { case 0x0, 0x1: return tx.GasPrice - case 0x2: - if block.BaseFeePerGas == nil || tx.MaxPriorityFeePerGas == nil || tx.MaxFeePerGas == nil { - b.logger.Warnw("Got transaction type 0x2 but one of the required EIP1559 fields was missing, falling back to gasPrice", "block", block, "tx", tx) - return tx.GasPrice - } - if tx.GasPrice != nil { - // Always use the gas price if provided - return tx.GasPrice - } - if tx.MaxFeePerGas.Cmp(block.BaseFeePerGas) < 0 { - b.logger.AssumptionViolationw("MaxFeePerGas >= BaseFeePerGas", "block", block, "tx", tx) - return nil - } - if tx.MaxFeePerGas.Cmp(tx.MaxPriorityFeePerGas) < 0 { - b.logger.AssumptionViolationw("MaxFeePerGas >= MaxPriorityFeePerGas", "block", block, "tx", tx) - return nil - } - - // From: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md - priorityFeePerGas := tx.MaxPriorityFeePerGas - maxFeeMinusBaseFee := tx.MaxFeePerGas.Sub(block.BaseFeePerGas) - if maxFeeMinusBaseFee.Cmp(priorityFeePerGas) < 0 { - priorityFeePerGas = maxFeeMinusBaseFee - } - - effectiveGasPrice := priorityFeePerGas.Add(block.BaseFeePerGas) - return effectiveGasPrice + case 0x2, 0x3: + return b.getEffectiveGasPrice(block, tx) default: b.logger.Warnw(fmt.Sprintf("Ignoring unknown transaction type %v", tx.Type), "block", block, "tx", tx) return nil } } +func (b *BlockHistoryEstimator) getEffectiveGasPrice(block evmtypes.Block, tx evmtypes.Transaction) *assets.Wei { + if block.BaseFeePerGas == nil || tx.MaxPriorityFeePerGas == nil || tx.MaxFeePerGas == nil { + b.logger.Warnw("Got transaction type 0x2 but one of the required EIP1559 fields was missing, falling back to gasPrice", "block", block, "tx", tx) + return tx.GasPrice + } + if tx.GasPrice != nil { + // Always use the gas price if provided + return tx.GasPrice + } + if tx.MaxFeePerGas.Cmp(block.BaseFeePerGas) < 0 { + b.logger.AssumptionViolationw("MaxFeePerGas >= BaseFeePerGas", "block", block, "tx", tx) + return nil + } + if tx.MaxFeePerGas.Cmp(tx.MaxPriorityFeePerGas) < 0 { + b.logger.AssumptionViolationw("MaxFeePerGas >= MaxPriorityFeePerGas", "block", block, "tx", tx) + return nil + } + + // From: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md + priorityFeePerGas := tx.MaxPriorityFeePerGas + maxFeeMinusBaseFee := tx.MaxFeePerGas.Sub(block.BaseFeePerGas) + if maxFeeMinusBaseFee.Cmp(priorityFeePerGas) < 0 { + priorityFeePerGas = maxFeeMinusBaseFee + } + + effectiveGasPrice := priorityFeePerGas.Add(block.BaseFeePerGas) + return effectiveGasPrice +} + func (b *BlockHistoryEstimator) EffectiveTipCap(block evmtypes.Block, tx evmtypes.Transaction) *assets.Wei { switch tx.Type { - case 0x2: + case 0x2, 0x3: return tx.MaxPriorityFeePerGas case 0x0, 0x1: if tx.GasPrice == nil { diff --git a/core/chains/evm/gas/block_history_estimator_test.go b/core/chains/evm/gas/block_history_estimator_test.go index d3edf212b6a..dfb4adf11ef 100644 --- a/core/chains/evm/gas/block_history_estimator_test.go +++ b/core/chains/evm/gas/block_history_estimator_test.go @@ -25,10 +25,11 @@ import ( evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" 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" "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/utils" ) func NewEvmHash() common.Hash { @@ -429,7 +430,7 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { elems[1].Result = &b42 }) - head := evmtypes.NewHead(big.NewInt(44), b44.Hash, b43.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) + head := evmtypes.NewHead(big.NewInt(44), b44.Hash, b43.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) err = bhe.FetchBlocks(testutils.Context(t), &head) require.NoError(t, err) @@ -493,8 +494,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { elems[1].Result = &b2 }) - head2 := evmtypes.NewHead(big.NewInt(2), b2.Hash, b1.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) - head3 := evmtypes.NewHead(big.NewInt(3), b3.Hash, b2.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) + head2 := evmtypes.NewHead(big.NewInt(2), b2.Hash, b1.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) + head3 := evmtypes.NewHead(big.NewInt(3), b3.Hash, b2.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) head3.Parent = &head2 err := bhe.FetchBlocks(testutils.Context(t), &head3) require.NoError(t, err) @@ -546,8 +547,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { gas.SetRollingBlockHistory(bhe, blocks) // RE-ORG, head2 and head3 have different hash than saved b2 and b3 - head2 := evmtypes.NewHead(big.NewInt(2), utils.NewHash(), b1.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) - head3 := evmtypes.NewHead(big.NewInt(3), utils.NewHash(), head2.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) + head2 := evmtypes.NewHead(big.NewInt(2), utils.NewHash(), b1.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) + head3 := evmtypes.NewHead(big.NewInt(3), utils.NewHash(), head2.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) head3.Parent = &head2 ethClient.On("BatchCallContext", mock.Anything, mock.MatchedBy(func(b []rpc.BatchElem) bool { @@ -617,8 +618,8 @@ func TestBlockHistoryEstimator_FetchBlocks(t *testing.T) { gas.SetRollingBlockHistory(bhe, blocks) // head2 and head3 have identical hash to saved blocks - head2 := evmtypes.NewHead(big.NewInt(2), b2.Hash, b1.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) - head3 := evmtypes.NewHead(big.NewInt(3), b3.Hash, head2.Hash, uint64(time.Now().Unix()), utils.NewBig(&cltest.FixtureChainID)) + head2 := evmtypes.NewHead(big.NewInt(2), b2.Hash, b1.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) + head3 := evmtypes.NewHead(big.NewInt(3), b3.Hash, head2.Hash, uint64(time.Now().Unix()), ubig.New(&cltest.FixtureChainID)) head3.Parent = &head2 err := bhe.FetchBlocks(testutils.Context(t), &head3) @@ -1395,7 +1396,7 @@ func TestBlockHistoryEstimator_EffectiveTipCap(t *testing.T) { res := bhe.EffectiveTipCap(eipblock, tx) assert.Equal(t, "42 wei", res.String()) }) - t.Run("tx type 2 should calculate gas price", func(t *testing.T) { + t.Run("tx type 2 & type 3 should calculate gas price", func(t *testing.T) { // 0x2 transaction (should use MaxPriorityFeePerGas) tx := evmtypes.Transaction{Type: 0x2, MaxPriorityFeePerGas: assets.NewWeiI(200), MaxFeePerGas: assets.NewWeiI(250), GasLimit: 42, Hash: utils.NewHash()} res := bhe.EffectiveTipCap(eipblock, tx) @@ -1404,6 +1405,15 @@ func TestBlockHistoryEstimator_EffectiveTipCap(t *testing.T) { tx = evmtypes.Transaction{Type: 0x2, GasPrice: assets.NewWeiI(400), MaxPriorityFeePerGas: assets.NewWeiI(200), MaxFeePerGas: assets.NewWeiI(350), GasLimit: 42, Hash: utils.NewHash()} res = bhe.EffectiveTipCap(eipblock, tx) assert.Equal(t, "200 wei", res.String()) + + // 0x3 transaction (should use MaxPriorityFeePerGas) + tx = evmtypes.Transaction{Type: 0x3, MaxPriorityFeePerGas: assets.NewWeiI(100), MaxFeePerGas: assets.NewWeiI(250), GasLimit: 42, Hash: utils.NewHash()} + res = bhe.EffectiveTipCap(eipblock, tx) + assert.Equal(t, "100 wei", res.String()) + // 0x3 transaction (should use MaxPriorityFeePerGas, ignoring gas price) + tx = evmtypes.Transaction{Type: 0x3, GasPrice: assets.NewWeiI(400), MaxPriorityFeePerGas: assets.NewWeiI(100), MaxFeePerGas: assets.NewWeiI(350), GasLimit: 42, Hash: utils.NewHash()} + res = bhe.EffectiveTipCap(eipblock, tx) + assert.Equal(t, "100 wei", res.String()) }) t.Run("missing field returns nil", func(t *testing.T) { tx := evmtypes.Transaction{Type: 0x2, GasPrice: assets.NewWeiI(132), MaxFeePerGas: assets.NewWeiI(200), GasLimit: 42, Hash: utils.NewHash()} @@ -1411,7 +1421,7 @@ func TestBlockHistoryEstimator_EffectiveTipCap(t *testing.T) { assert.Nil(t, res) }) t.Run("unknown type returns nil", func(t *testing.T) { - tx := evmtypes.Transaction{Type: 0x3, GasPrice: assets.NewWeiI(55555), MaxPriorityFeePerGas: assets.NewWeiI(200), MaxFeePerGas: assets.NewWeiI(250), GasLimit: 42, Hash: utils.NewHash()} + tx := evmtypes.Transaction{Type: 0x4, GasPrice: assets.NewWeiI(55555), MaxPriorityFeePerGas: assets.NewWeiI(200), MaxFeePerGas: assets.NewWeiI(250), GasLimit: 42, Hash: utils.NewHash()} res := bhe.EffectiveTipCap(eipblock, tx) assert.Nil(t, res) }) @@ -1465,6 +1475,26 @@ func TestBlockHistoryEstimator_EffectiveGasPrice(t *testing.T) { res = bhe.EffectiveGasPrice(eipblock, tx) assert.Equal(t, "32 wei", res.String()) }) + + t.Run("tx type 3 should calculate gas price", func(t *testing.T) { + // 0x3 transaction (should calculate to 250) + tx := evmtypes.Transaction{Type: 0x3, MaxPriorityFeePerGas: assets.NewWeiI(100), MaxFeePerGas: assets.NewWeiI(110), GasLimit: 42, Hash: utils.NewHash()} + res := bhe.EffectiveGasPrice(eipblock, tx) + assert.Equal(t, "110 wei", res.String()) + // 0x3 transaction (should calculate to 300) + tx = evmtypes.Transaction{Type: 0x3, MaxPriorityFeePerGas: assets.NewWeiI(200), MaxFeePerGas: assets.NewWeiI(350), GasLimit: 42, Hash: utils.NewHash()} + res = bhe.EffectiveGasPrice(eipblock, tx) + assert.Equal(t, "300 wei", res.String()) + // 0x3 transaction (should calculate to 300, ignoring gas price) + tx = evmtypes.Transaction{Type: 0x3, MaxPriorityFeePerGas: assets.NewWeiI(200), MaxFeePerGas: assets.NewWeiI(350), GasLimit: 42, Hash: utils.NewHash()} + res = bhe.EffectiveGasPrice(eipblock, tx) + assert.Equal(t, "300 wei", res.String()) + // 0x3 transaction (should fall back to gas price since MaxFeePerGas is missing) + tx = evmtypes.Transaction{Type: 0x3, GasPrice: assets.NewWeiI(5), MaxPriorityFeePerGas: assets.NewWeiI(200), GasLimit: 42, Hash: utils.NewHash()} + res = bhe.EffectiveGasPrice(eipblock, tx) + assert.Equal(t, "5 wei", res.String()) + }) + t.Run("tx type 2 has block missing base fee (should never happen but must handle gracefully)", func(t *testing.T) { // 0x2 transaction (should calculate to 250) tx := evmtypes.Transaction{Type: 0x2, GasPrice: assets.NewWeiI(55555), MaxPriorityFeePerGas: assets.NewWeiI(200), MaxFeePerGas: assets.NewWeiI(250), GasLimit: 42, Hash: utils.NewHash()} @@ -1472,7 +1502,7 @@ func TestBlockHistoryEstimator_EffectiveGasPrice(t *testing.T) { assert.Equal(t, "55.555 kwei", res.String()) }) t.Run("unknown type returns nil", func(t *testing.T) { - tx := evmtypes.Transaction{Type: 0x3, GasPrice: assets.NewWeiI(55555), MaxPriorityFeePerGas: assets.NewWeiI(200), MaxFeePerGas: assets.NewWeiI(250), GasLimit: 42, Hash: utils.NewHash()} + tx := evmtypes.Transaction{Type: 0x4, GasPrice: assets.NewWeiI(55555), MaxPriorityFeePerGas: assets.NewWeiI(200), MaxFeePerGas: assets.NewWeiI(250), GasLimit: 42, Hash: utils.NewHash()} res := bhe.EffectiveGasPrice(block, tx) assert.Nil(t, res) }) diff --git a/core/chains/evm/gas/mocks/config.go b/core/chains/evm/gas/mocks/config.go index c09005b5e3d..4a7b6f4d7eb 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type Config struct { func (_m *Config) ChainType() config.ChainType { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainType") + } + var r0 config.ChainType if rf, ok := ret.Get(0).(func() config.ChainType); ok { r0 = rf() @@ -31,6 +35,10 @@ func (_m *Config) ChainType() config.ChainType { func (_m *Config) FinalityDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -45,6 +53,10 @@ func (_m *Config) FinalityDepth() uint32 { func (_m *Config) FinalityTagEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityTagEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() diff --git a/core/chains/evm/gas/mocks/eth_client.go b/core/chains/evm/gas/mocks/eth_client.go index 2b0aaff0257..bb0784f8515 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type ETHClient struct { func (_m *ETHClient) 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 { diff --git a/core/chains/evm/gas/mocks/evm_estimator.go b/core/chains/evm/gas/mocks/evm_estimator.go index f2cb51f8560..29705b2a5d9 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -25,6 +25,10 @@ type EvmEstimator struct { func (_m *EvmEstimator) BumpDynamicFee(ctx context.Context, original gas.DynamicFee, gasLimit uint32, maxGasPriceWei *assets.Wei, attempts []gas.EvmPriorAttempt) (gas.DynamicFee, uint32, error) { ret := _m.Called(ctx, original, gasLimit, maxGasPriceWei, attempts) + if len(ret) == 0 { + panic("no return value specified for BumpDynamicFee") + } + var r0 gas.DynamicFee var r1 uint32 var r2 error @@ -56,6 +60,10 @@ func (_m *EvmEstimator) BumpDynamicFee(ctx context.Context, original gas.Dynamic func (_m *EvmEstimator) BumpLegacyGas(ctx context.Context, originalGasPrice *assets.Wei, gasLimit uint32, maxGasPriceWei *assets.Wei, attempts []gas.EvmPriorAttempt) (*assets.Wei, uint32, error) { ret := _m.Called(ctx, originalGasPrice, gasLimit, maxGasPriceWei, attempts) + if len(ret) == 0 { + panic("no return value specified for BumpLegacyGas") + } + var r0 *assets.Wei var r1 uint32 var r2 error @@ -89,6 +97,10 @@ func (_m *EvmEstimator) BumpLegacyGas(ctx context.Context, originalGasPrice *ass func (_m *EvmEstimator) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -103,6 +115,10 @@ func (_m *EvmEstimator) Close() error { func (_m *EvmEstimator) GetDynamicFee(ctx context.Context, gasLimit uint32, maxGasPriceWei *assets.Wei) (gas.DynamicFee, uint32, error) { ret := _m.Called(ctx, gasLimit, maxGasPriceWei) + if len(ret) == 0 { + panic("no return value specified for GetDynamicFee") + } + var r0 gas.DynamicFee var r1 uint32 var r2 error @@ -141,6 +157,10 @@ func (_m *EvmEstimator) GetLegacyGas(ctx context.Context, calldata []byte, gasLi _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetLegacyGas") + } + var r0 *assets.Wei var r1 uint32 var r2 error @@ -174,6 +194,10 @@ func (_m *EvmEstimator) GetLegacyGas(ctx context.Context, calldata []byte, gasLi func (_m *EvmEstimator) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -190,6 +214,10 @@ func (_m *EvmEstimator) HealthReport() map[string]error { func (_m *EvmEstimator) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -209,6 +237,10 @@ func (_m *EvmEstimator) OnNewLongestChain(ctx context.Context, head *evmtypes.He func (_m *EvmEstimator) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -223,6 +255,10 @@ func (_m *EvmEstimator) Ready() error { func (_m *EvmEstimator) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/chains/evm/gas/mocks/evm_fee_estimator.go b/core/chains/evm/gas/mocks/evm_fee_estimator.go index b9b16367796..66acbdbf7ff 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -29,6 +29,10 @@ type EvmFeeEstimator struct { func (_m *EvmFeeEstimator) BumpFee(ctx context.Context, originalFee gas.EvmFee, feeLimit uint32, maxFeePrice *assets.Wei, attempts []gas.EvmPriorAttempt) (gas.EvmFee, uint32, error) { ret := _m.Called(ctx, originalFee, feeLimit, maxFeePrice, attempts) + if len(ret) == 0 { + panic("no return value specified for BumpFee") + } + var r0 gas.EvmFee var r1 uint32 var r2 error @@ -60,6 +64,10 @@ func (_m *EvmFeeEstimator) BumpFee(ctx context.Context, originalFee gas.EvmFee, func (_m *EvmFeeEstimator) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -81,6 +89,10 @@ func (_m *EvmFeeEstimator) GetFee(ctx context.Context, calldata []byte, feeLimit _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetFee") + } + var r0 gas.EvmFee var r1 uint32 var r2 error @@ -119,6 +131,10 @@ func (_m *EvmFeeEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, ca _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetMaxCost") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, assets.Eth, []byte, uint32, *assets.Wei, ...types.Opt) (*big.Int, error)); ok { @@ -145,6 +161,10 @@ func (_m *EvmFeeEstimator) GetMaxCost(ctx context.Context, amount assets.Eth, ca func (_m *EvmFeeEstimator) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -161,6 +181,10 @@ func (_m *EvmFeeEstimator) HealthReport() map[string]error { func (_m *EvmFeeEstimator) 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() @@ -177,6 +201,10 @@ func (_m *EvmFeeEstimator) L1Oracle() rollups.L1Oracle { func (_m *EvmFeeEstimator) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -196,6 +224,10 @@ func (_m *EvmFeeEstimator) OnNewLongestChain(ctx context.Context, head *evmtypes func (_m *EvmFeeEstimator) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -210,6 +242,10 @@ func (_m *EvmFeeEstimator) Ready() error { func (_m *EvmFeeEstimator) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/chains/evm/gas/mocks/rpc_client.go b/core/chains/evm/gas/mocks/rpc_client.go index 6f6ac8d6b79..d1262665f66 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ func (_m *RPCClient) CallContext(ctx context.Context, result interface{}, 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...) diff --git a/core/chains/evm/gas/models.go b/core/chains/evm/gas/models.go index c7476d58ba4..8d977df0991 100644 --- a/core/chains/evm/gas/models.go +++ b/core/chains/evm/gas/models.go @@ -71,19 +71,31 @@ func NewEstimator(lggr logger.Logger, ethClient evmclient.Client, cfg Config, ge if rollups.IsRollupWithL1Support(cfg.ChainType()) { l1Oracle = rollups.NewL1GasPriceOracle(lggr, ethClient, cfg.ChainType()) } + var newEstimator func(logger.Logger) EvmEstimator switch s { case "Arbitrum": - return NewWrappedEvmEstimator(NewArbitrumEstimator(lggr, geCfg, ethClient, ethClient), df, l1Oracle) + newEstimator = func(l logger.Logger) EvmEstimator { + return NewArbitrumEstimator(lggr, geCfg, ethClient, ethClient) + } case "BlockHistory": - return NewWrappedEvmEstimator(NewBlockHistoryEstimator(lggr, ethClient, cfg, geCfg, bh, *ethClient.ConfiguredChainID()), df, l1Oracle) + newEstimator = func(l logger.Logger) EvmEstimator { + return NewBlockHistoryEstimator(lggr, ethClient, cfg, geCfg, bh, *ethClient.ConfiguredChainID()) + } case "FixedPrice": - return NewWrappedEvmEstimator(NewFixedPriceEstimator(geCfg, bh, lggr), df, l1Oracle) + newEstimator = func(l logger.Logger) EvmEstimator { + return NewFixedPriceEstimator(geCfg, bh, lggr) + } case "L2Suggested", "SuggestedPrice": - return NewWrappedEvmEstimator(NewSuggestedPriceEstimator(lggr, ethClient), df, l1Oracle) + newEstimator = func(l logger.Logger) EvmEstimator { + return NewSuggestedPriceEstimator(lggr, ethClient) + } default: lggr.Warnf("GasEstimator: unrecognised mode '%s', falling back to FixedPriceEstimator", s) - return NewWrappedEvmEstimator(NewFixedPriceEstimator(geCfg, bh, lggr), df, l1Oracle) + newEstimator = func(l logger.Logger) EvmEstimator { + return NewFixedPriceEstimator(geCfg, bh, lggr) + } } + return NewWrappedEvmEstimator(lggr, newEstimator, df, l1Oracle) } // DynamicFee encompasses both FeeCap and TipCap for EIP1559 transactions @@ -150,6 +162,7 @@ func (fee EvmFee) ValidDynamic() bool { // 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 { services.StateMachine + lggr logger.Logger EvmEstimator EIP1559Enabled bool l1Oracle rollups.L1Oracle @@ -157,16 +170,18 @@ type WrappedEvmEstimator struct { var _ EvmFeeEstimator = (*WrappedEvmEstimator)(nil) -func NewWrappedEvmEstimator(e EvmEstimator, eip1559Enabled bool, l1Oracle rollups.L1Oracle) EvmFeeEstimator { +func NewWrappedEvmEstimator(lggr logger.Logger, newEstimator func(logger.Logger) EvmEstimator, eip1559Enabled bool, l1Oracle rollups.L1Oracle) EvmFeeEstimator { + lggr = logger.Named(lggr, "WrappedEvmEstimator") return &WrappedEvmEstimator{ - EvmEstimator: e, + lggr: lggr, + EvmEstimator: newEstimator(lggr), EIP1559Enabled: eip1559Enabled, l1Oracle: l1Oracle, } } func (e *WrappedEvmEstimator) Name() string { - return fmt.Sprintf("WrappedEvmEstimator(%s)", e.EvmEstimator.Name()) + return e.lggr.Name() } func (e *WrappedEvmEstimator) Start(ctx context.Context) error { diff --git a/core/chains/evm/gas/models_test.go b/core/chains/evm/gas/models_test.go index a2dce58ee3f..95a7a471eba 100644 --- a/core/chains/evm/gas/models_test.go +++ b/core/chains/evm/gas/models_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "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" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" @@ -27,39 +28,41 @@ func TestWrappedEvmEstimator(t *testing.T) { FeeCap: assets.NewWeiI(20), TipCap: assets.NewWeiI(1), } - - e := mocks.NewEvmEstimator(t) - e.On("GetDynamicFee", mock.Anything, mock.Anything, mock.Anything). + est := mocks.NewEvmEstimator(t) + est.On("GetDynamicFee", mock.Anything, mock.Anything, mock.Anything). Return(dynamicFee, gasLimit, nil).Twice() - e.On("GetLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + est.On("GetLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(legacyFee, gasLimit, nil).Twice() - e.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). + est.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(dynamicFee, gasLimit, nil).Once() - e.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). + est.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(legacyFee, gasLimit, nil).Once() + getRootEst := func(logger.Logger) gas.EvmEstimator { return est } - mockEvmEstimatorName := "MockEstimator" - mockEstimatorName := "WrappedEvmEstimator(MockEstimator)" + mockEstimatorName := "WrappedEvmEstimator" + mockEvmEstimatorName := "WrappedEvmEstimator.MockEstimator" // L1Oracle returns the correct L1Oracle interface t.Run("L1Oracle", func(t *testing.T) { + lggr := logger.Test(t) // expect nil - estimator := gas.NewWrappedEvmEstimator(e, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, false, nil) l1Oracle := estimator.L1Oracle() assert.Nil(t, l1Oracle) // expect l1Oracle oracle := rollupMocks.NewL1Oracle(t) - estimator = gas.NewWrappedEvmEstimator(e, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, false, oracle) l1Oracle = estimator.L1Oracle() assert.Equal(t, oracle, l1Oracle) }) // GetFee returns gas estimation based on configuration value t.Run("GetFee", func(t *testing.T) { + lggr := logger.Test(t) // expect legacy fee data dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(e, dynamicFees, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) fee, max, err := estimator.GetFee(ctx, nil, 0, nil) require.NoError(t, err) assert.Equal(t, gasLimit, max) @@ -69,7 +72,7 @@ func TestWrappedEvmEstimator(t *testing.T) { // expect dynamic fee data dynamicFees = true - estimator = gas.NewWrappedEvmEstimator(e, dynamicFees, nil) + estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) fee, max, err = estimator.GetFee(ctx, nil, 0, nil) require.NoError(t, err) assert.Equal(t, gasLimit, max) @@ -80,8 +83,9 @@ func TestWrappedEvmEstimator(t *testing.T) { // BumpFee returns bumped fee type based on original fee calculation t.Run("BumpFee", func(t *testing.T) { + lggr := logger.Test(t) dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(e, dynamicFees, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) // expect legacy fee data fee, max, err := estimator.BumpFee(ctx, gas.EvmFee{Legacy: assets.NewWeiI(0)}, 0, nil, nil) @@ -114,11 +118,12 @@ func TestWrappedEvmEstimator(t *testing.T) { }) t.Run("GetMaxCost", func(t *testing.T) { + lggr := logger.Test(t) val := assets.NewEthValue(1) // expect legacy fee data dynamicFees := false - estimator := gas.NewWrappedEvmEstimator(e, dynamicFees, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) total, err := estimator.GetMaxCost(ctx, val, nil, gasLimit, nil) require.NoError(t, err) fee := new(big.Int).Mul(legacyFee.ToInt(), big.NewInt(int64(gasLimit))) @@ -126,7 +131,7 @@ func TestWrappedEvmEstimator(t *testing.T) { // expect dynamic fee data dynamicFees = true - estimator = gas.NewWrappedEvmEstimator(e, dynamicFees, nil) + estimator = gas.NewWrappedEvmEstimator(lggr, getRootEst, dynamicFees, nil) 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))) @@ -134,33 +139,38 @@ func TestWrappedEvmEstimator(t *testing.T) { }) t.Run("Name", func(t *testing.T) { - evmEstimator := mocks.NewEvmEstimator(t) - oracle := rollupMocks.NewL1Oracle(t) + lggr := logger.Test(t) + oracle := rollupMocks.NewL1Oracle(t) + evmEstimator := mocks.NewEvmEstimator(t) evmEstimator.On("Name").Return(mockEvmEstimatorName, nil).Once() - estimator := gas.NewWrappedEvmEstimator(evmEstimator, false, oracle) - name := estimator.Name() - require.Equal(t, mockEstimatorName, name) + estimator := gas.NewWrappedEvmEstimator(lggr, func(logger.Logger) gas.EvmEstimator { + return evmEstimator + }, false, oracle) + + require.Equal(t, mockEstimatorName, estimator.Name()) + require.Equal(t, mockEvmEstimatorName, evmEstimator.Name()) }) t.Run("Start and stop calls both EVM estimator and L1Oracle", func(t *testing.T) { - evmEstimator := mocks.NewEvmEstimator(t) + lggr := logger.Test(t) oracle := rollupMocks.NewL1Oracle(t) + evmEstimator := mocks.NewEvmEstimator(t) - evmEstimator.On("Name").Return(mockEvmEstimatorName, nil).Times(4) evmEstimator.On("Start", mock.Anything).Return(nil).Twice() evmEstimator.On("Close").Return(nil).Twice() oracle.On("Start", mock.Anything).Return(nil).Once() oracle.On("Close").Return(nil).Once() + getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(evmEstimator, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil) err := estimator.Start(ctx) require.NoError(t, err) err = estimator.Close() require.NoError(t, err) - estimator = gas.NewWrappedEvmEstimator(evmEstimator, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle) err = estimator.Start(ctx) require.NoError(t, err) err = estimator.Close() @@ -168,22 +178,25 @@ func TestWrappedEvmEstimator(t *testing.T) { }) t.Run("Read calls both EVM estimator and L1Oracle", func(t *testing.T) { + lggr := logger.Test(t) evmEstimator := mocks.NewEvmEstimator(t) oracle := rollupMocks.NewL1Oracle(t) evmEstimator.On("Ready").Return(nil).Twice() oracle.On("Ready").Return(nil).Once() + getEst := func(logger.Logger) gas.EvmEstimator { return evmEstimator } - estimator := gas.NewWrappedEvmEstimator(evmEstimator, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil) err := estimator.Ready() require.NoError(t, err) - estimator = gas.NewWrappedEvmEstimator(evmEstimator, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle) err = estimator.Ready() require.NoError(t, err) }) t.Run("HealthReport merges report from EVM estimator and L1Oracle", func(t *testing.T) { + lggr := logger.Test(t) evmEstimator := mocks.NewEvmEstimator(t) oracle := rollupMocks.NewL1Oracle(t) @@ -192,17 +205,17 @@ func TestWrappedEvmEstimator(t *testing.T) { oracleKey := "oracle" oracleError := errors.New("oracle error") - evmEstimator.On("Name").Return(mockEvmEstimatorName, nil).Twice() 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(evmEstimator, false, nil) + estimator := gas.NewWrappedEvmEstimator(lggr, getEst, false, nil) report := estimator.HealthReport() require.True(t, errors.Is(report[evmEstimatorKey], evmEstimatorError)) require.Nil(t, report[oracleKey]) require.NotNil(t, report[mockEstimatorName]) - estimator = gas.NewWrappedEvmEstimator(evmEstimator, false, oracle) + estimator = gas.NewWrappedEvmEstimator(lggr, getEst, false, oracle) report = estimator.HealthReport() require.True(t, errors.Is(report[evmEstimatorKey], evmEstimatorError)) require.True(t, errors.Is(report[oracleKey], oracleError)) diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go index 6a384fa9c54..a006ea89923 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle.go @@ -14,11 +14,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "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" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name ethClient --output ./mocks/ --case=underscore --structname ETHClient @@ -31,7 +31,7 @@ type l1GasPriceOracle struct { services.StateMachine client ethClient pollPeriod time.Duration - logger logger.Logger + logger logger.SugaredLogger address string callArgs string @@ -65,11 +65,18 @@ const ( // `function l1BaseFee() external view returns (uint256);` KromaGasOracle_l1BaseFee = "519b4bd3" + // GasOracleAddress is the address of the precompiled contract that exists on scroll chain. + // This is the case for Scroll. + ScrollGasOracleAddress = "0x5300000000000000000000000000000000000002" + // GasOracle_l1BaseFee is the a hex encoded call to: + // `function l1BaseFee() external view returns (uint256);` + ScrollGasOracle_l1BaseFee = "519b4bd3" + // Interval at which to poll for L1BaseFee. A good starting point is the L1 block time. PollPeriod = 12 * time.Second ) -var supportedChainTypes = []config.ChainType{config.ChainArbitrum, config.ChainOptimismBedrock, config.ChainKroma} +var supportedChainTypes = []config.ChainType{config.ChainArbitrum, config.ChainOptimismBedrock, config.ChainKroma, config.ChainScroll} func IsRollupWithL1Support(chainType config.ChainType) bool { return slices.Contains(supportedChainTypes, chainType) @@ -87,6 +94,9 @@ func NewL1GasPriceOracle(lggr logger.Logger, ethClient ethClient, chainType conf case config.ChainKroma: address = KromaGasOracleAddress callArgs = KromaGasOracle_l1BaseFee + case config.ChainScroll: + address = ScrollGasOracleAddress + callArgs = ScrollGasOracle_l1BaseFee default: panic(fmt.Sprintf("Received unspported chaintype %s", chainType)) } @@ -94,7 +104,7 @@ func NewL1GasPriceOracle(lggr logger.Logger, ethClient ethClient, chainType conf return &l1GasPriceOracle{ client: ethClient, pollPeriod: PollPeriod, - logger: logger.Named(lggr, fmt.Sprintf("L1GasPriceOracle(%s)", chainType)), + logger: logger.Sugared(logger.Named(lggr, fmt.Sprintf("L1GasPriceOracle(%s)", chainType))), address: address, callArgs: callArgs, chInitialised: make(chan struct{}), @@ -159,7 +169,7 @@ func (o *l1GasPriceOracle) refresh() (t *time.Timer) { } if len(b) != 32 { // returns uint256; - logger.Criticalf(o.logger, "return data length (%d) different than expected (%d)", len(b), 32) + o.logger.Criticalf("return data length (%d) different than expected (%d)", len(b), 32) return } price := new(big.Int).SetBytes(b) diff --git a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go index 2defedd6b47..188376bf832 100644 --- a/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go +++ b/core/chains/evm/gas/rollups/l1_gas_price_oracle_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/common/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -50,8 +51,7 @@ func TestL1GasPriceOracle(t *testing.T) { }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainArbitrum) - require.NoError(t, oracle.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) + servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(testutils.Context(t)) require.NoError(t, err) @@ -72,8 +72,7 @@ func TestL1GasPriceOracle(t *testing.T) { }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainKroma) - require.NoError(t, oracle.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) + servicetest.RunHealthy(t, oracle) gasPrice, err := oracle.GasPrice(testutils.Context(t)) require.NoError(t, err) @@ -94,6 +93,27 @@ func TestL1GasPriceOracle(t *testing.T) { }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainOptimismBedrock) + servicetest.RunHealthy(t, oracle) + + gasPrice, err := oracle.GasPrice(testutils.Context(t)) + require.NoError(t, err) + + assert.Equal(t, assets.NewWei(l1BaseFee), gasPrice) + }) + + t.Run("Calling GasPrice on started Scroll L1Oracle returns Scroll l1GasPrice", func(t *testing.T) { + l1BaseFee := big.NewInt(200) + + ethClient := mocks.NewETHClient(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) + assert.Equal(t, ScrollGasOracleAddress, callMsg.To.String()) + assert.Equal(t, ScrollGasOracle_l1BaseFee, fmt.Sprintf("%x", callMsg.Data)) + assert.Nil(t, blockNumber) + }).Return(common.BigToHash(l1BaseFee).Bytes(), nil) + + oracle := NewL1GasPriceOracle(logger.Test(t), ethClient, config.ChainScroll) require.NoError(t, oracle.Start(testutils.Context(t))) t.Cleanup(func() { assert.NoError(t, oracle.Close()) }) diff --git a/core/chains/evm/gas/rollups/mocks/eth_client.go b/core/chains/evm/gas/rollups/mocks/eth_client.go index 2b0aaff0257..bb0784f8515 100644 --- a/core/chains/evm/gas/rollups/mocks/eth_client.go +++ b/core/chains/evm/gas/rollups/mocks/eth_client.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type ETHClient struct { func (_m *ETHClient) 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 { diff --git a/core/chains/evm/gas/rollups/mocks/l1_oracle.go b/core/chains/evm/gas/rollups/mocks/l1_oracle.go index f6f8cc736af..9e52a3ec38e 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type L1Oracle struct { func (_m *L1Oracle) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -33,6 +37,10 @@ func (_m *L1Oracle) Close() error { func (_m *L1Oracle) GasPrice(ctx context.Context) (*assets.Wei, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GasPrice") + } + var r0 *assets.Wei var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*assets.Wei, error)); ok { @@ -59,6 +67,10 @@ func (_m *L1Oracle) GasPrice(ctx context.Context) (*assets.Wei, error) { func (_m *L1Oracle) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -75,6 +87,10 @@ func (_m *L1Oracle) HealthReport() map[string]error { func (_m *L1Oracle) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -89,6 +105,10 @@ func (_m *L1Oracle) Name() string { func (_m *L1Oracle) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -103,6 +123,10 @@ func (_m *L1Oracle) Ready() error { func (_m *L1Oracle) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/chains/evm/gas/suggested_price_estimator.go b/core/chains/evm/gas/suggested_price_estimator.go index 2e0d32bfc94..3b02b7f4362 100644 --- a/core/chains/evm/gas/suggested_price_estimator.go +++ b/core/chains/evm/gas/suggested_price_estimator.go @@ -11,12 +11,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" 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" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( diff --git a/core/chains/evm/gas/suggested_price_estimator_test.go b/core/chains/evm/gas/suggested_price_estimator_test.go index 304e5359107..8e45f5b759a 100644 --- a/core/chains/evm/gas/suggested_price_estimator_test.go +++ b/core/chains/evm/gas/suggested_price_estimator_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "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" @@ -40,8 +41,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { }) o := gas.NewSuggestedPriceEstimator(logger.Test(t), client) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) require.NoError(t, err) assert.Equal(t, assets.NewWeiI(42), gasPrice) @@ -57,8 +57,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { (*big.Int)(res).SetInt64(42) }) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, assets.NewWeiI(40)) require.Error(t, err) assert.EqualError(t, err, "estimated gas price: 42 wei is greater than the maximum gas price configured: 40 wei") @@ -75,8 +74,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { (*big.Int)(res).SetInt64(120) }) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) gasPrice, chainSpecificGasLimit, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, assets.NewWeiI(110)) assert.EqualError(t, err, "estimated gas price: 120 wei is greater than the maximum gas price configured: 110 wei") assert.Nil(t, gasPrice) @@ -96,8 +94,7 @@ func TestSuggestedPriceEstimator(t *testing.T) { client.On("CallContext", mock.Anything, mock.Anything, "eth_gasPrice").Return(errors.New("kaboom")) - require.NoError(t, o.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, o.Close()) }) + servicetest.RunHealthy(t, o) _, _, err := o.GetLegacyGas(testutils.Context(t), calldata, gasLimit, maxGasPrice) assert.EqualError(t, err, "failed to estimate gas; gas price not set") diff --git a/core/chains/evm/headtracker/head_broadcaster_test.go b/core/chains/evm/headtracker/head_broadcaster_test.go index 6fb151bfe6c..dcbb9bd0396 100644 --- a/core/chains/evm/headtracker/head_broadcaster_test.go +++ b/core/chains/evm/headtracker/head_broadcaster_test.go @@ -10,21 +10,23 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" commonhtrk "github.com/smartcontractkit/chainlink/v2/common/headtracker" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "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/services" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func waitHeadBroadcasterToStart(t *testing.T, hb types.HeadBroadcaster) { @@ -44,7 +46,7 @@ func TestHeadBroadcaster_Subscribe(t *testing.T) { g := gomega.NewWithT(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].HeadTracker.SamplingInterval = &models.Duration{} + c.EVM[0].HeadTracker.SamplingInterval = &commonconfig.Duration{} }) evmCfg := evmtest.NewChainScopedConfig(t, cfg) db := pgtest.NewSqlxDB(t) @@ -68,21 +70,21 @@ func TestHeadBroadcaster_Subscribe(t *testing.T) { checker1 := &cltest.MockHeadTrackable{} checker2 := &cltest.MockHeadTrackable{} - hb := headtracker.NewHeadBroadcaster(logger) orm := headtracker.NewORM(db, logger, cfg.Database(), *ethClient.ConfiguredChainID()) hs := headtracker.NewHeadSaver(logger, orm, evmCfg.EVM(), evmCfg.EVM().HeadTracker()) - mailMon := utils.NewMailboxMonitor(t.Name()) + mailMon := mailboxtest.NewMonitor(t) + servicetest.Run(t, mailMon) + hb := headtracker.NewHeadBroadcaster(logger) + servicetest.Run(t, hb) ht := headtracker.NewHeadTracker(logger, ethClient, evmCfg.EVM(), evmCfg.EVM().HeadTracker(), hb, hs, mailMon) - var ms services.MultiStart - require.NoError(t, ms.Start(testutils.Context(t), mailMon, hb, ht)) - t.Cleanup(func() { require.NoError(t, services.CloseAll(mailMon, hb, ht)) }) + servicetest.Run(t, ht) latest1, unsubscribe1 := hb.Subscribe(checker1) // "latest head" is nil here because we didn't receive any yet assert.Equal(t, (*evmtypes.Head)(nil), latest1) headers := <-chchHeaders - h := evmtypes.Head{Number: 1, Hash: utils.NewHash(), ParentHash: utils.NewHash(), EVMChainID: utils.NewBig(&cltest.FixtureChainID)} + h := evmtypes.Head{Number: 1, Hash: utils.NewHash(), ParentHash: utils.NewHash(), EVMChainID: big.New(&cltest.FixtureChainID)} headers <- &h g.Eventually(checker1.OnNewLongestChainCount).Should(gomega.Equal(int32(1))) @@ -93,7 +95,7 @@ func TestHeadBroadcaster_Subscribe(t *testing.T) { unsubscribe1() - headers <- &evmtypes.Head{Number: 2, Hash: utils.NewHash(), ParentHash: h.Hash, EVMChainID: utils.NewBig(&cltest.FixtureChainID)} + headers <- &evmtypes.Head{Number: 2, Hash: utils.NewHash(), ParentHash: h.Hash, EVMChainID: big.New(&cltest.FixtureChainID)} g.Eventually(checker2.OnNewLongestChainCount).Should(gomega.Equal(int32(1))) } diff --git a/core/chains/evm/headtracker/head_listener_test.go b/core/chains/evm/headtracker/head_listener_test.go index 8bb761bdfaa..3ba9c0863da 100644 --- a/core/chains/evm/headtracker/head_listener_test.go +++ b/core/chains/evm/headtracker/head_listener_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" @@ -21,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func Test_HeadListener_HappyPath(t *testing.T) { @@ -39,7 +39,7 @@ func Test_HeadListener_HappyPath(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { // no need to test head timeouts here - c.EVM[0].NoNewHeadsThreshold = &models.Duration{} + c.EVM[0].NoNewHeadsThreshold = &commonconfig.Duration{} }) evmcfg := evmtest.NewChainScopedConfig(t, cfg) chStop := make(chan struct{}) @@ -100,7 +100,7 @@ func Test_HeadListener_NotReceivingHeads(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].NoNewHeadsThreshold = models.MustNewDuration(time.Second) + c.EVM[0].NoNewHeadsThreshold = commonconfig.MustNewDuration(time.Second) }) evmcfg := evmtest.NewChainScopedConfig(t, cfg) chStop := make(chan struct{}) diff --git a/core/chains/evm/headtracker/head_tracker.go b/core/chains/evm/headtracker/head_tracker.go index b86a6b5fe22..3cddfb71d09 100644 --- a/core/chains/evm/headtracker/head_tracker.go +++ b/core/chains/evm/headtracker/head_tracker.go @@ -9,12 +9,13 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/common/headtracker" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type headTracker = headtracker.HeadTracker[*evmtypes.Head, ethereum.Subscription, *big.Int, common.Hash] @@ -28,7 +29,7 @@ func NewHeadTracker( htConfig HeadTrackerConfig, headBroadcaster httypes.HeadBroadcaster, headSaver httypes.HeadSaver, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, ) httypes.HeadTracker { return headtracker.NewHeadTracker[*evmtypes.Head, ethereum.Subscription, *big.Int, common.Hash]( lggr, diff --git a/core/chains/evm/headtracker/head_tracker_test.go b/core/chains/evm/headtracker/head_tracker_test.go index 4d3cebd24e2..22e931d6d0f 100644 --- a/core/chains/evm/headtracker/head_tracker_test.go +++ b/core/chains/evm/headtracker/head_tracker_test.go @@ -20,22 +20,25 @@ import ( "github.com/jmoiron/sqlx" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" 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" "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/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func firstHead(t *testing.T, db *sqlx.DB) (h evmtypes.Head) { @@ -257,7 +260,7 @@ func TestHeadTracker_CallsHeadTrackableCallbacks(t *testing.T) { assert.Equal(t, int32(0), checker.OnNewLongestChainCount()) headers := <-chchHeaders - headers.TrySend(&evmtypes.Head{Number: 1, Hash: utils.NewHash(), EVMChainID: utils.NewBig(&cltest.FixtureChainID)}) + headers.TrySend(&evmtypes.Head{Number: 1, Hash: utils.NewHash(), EVMChainID: ubig.New(&cltest.FixtureChainID)}) g.Eventually(checker.OnNewLongestChainCount).Should(gomega.Equal(int32(1))) ht.Stop(t) @@ -423,7 +426,7 @@ func TestHeadTracker_SwitchesToLongestChainWithHeadSamplingEnabled(t *testing.T) c.EVM[0].FinalityDepth = ptr[uint32](50) // Need to set the buffer to something large since we inject a lot of heads at once and otherwise they will be dropped c.EVM[0].HeadTracker.MaxBufferSize = ptr[uint32](100) - c.EVM[0].HeadTracker.SamplingInterval = models.MustNewDuration(2500 * time.Millisecond) + c.EVM[0].HeadTracker.SamplingInterval = commonconfig.MustNewDuration(2500 * time.Millisecond) }) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -551,7 +554,7 @@ func TestHeadTracker_SwitchesToLongestChainWithHeadSamplingDisabled(t *testing.T c.EVM[0].FinalityDepth = ptr[uint32](50) // Need to set the buffer to something large since we inject a lot of heads at once and otherwise they will be dropped c.EVM[0].HeadTracker.MaxBufferSize = ptr[uint32](100) - c.EVM[0].HeadTracker.SamplingInterval = models.MustNewDuration(0) + c.EVM[0].HeadTracker.SamplingInterval = commonconfig.MustNewDuration(0) }) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) @@ -718,7 +721,7 @@ func TestHeadTracker_Backfill(t *testing.T) { ParentHash: gethCommon.BigToHash(big.NewInt(0)), Time: now, } - head0 := evmtypes.NewHead(gethHead0.Number, utils.NewHash(), gethHead0.ParentHash, gethHead0.Time, utils.NewBig(&cltest.FixtureChainID)) + head0 := evmtypes.NewHead(gethHead0.Number, utils.NewHash(), gethHead0.ParentHash, gethHead0.Time, ubig.New(&cltest.FixtureChainID)) h1 := *cltest.Head(1) h1.ParentHash = head0.Hash @@ -728,7 +731,7 @@ func TestHeadTracker_Backfill(t *testing.T) { ParentHash: utils.NewHash(), Time: now, } - head8 := evmtypes.NewHead(gethHead8.Number, utils.NewHash(), gethHead8.ParentHash, gethHead8.Time, utils.NewBig(&cltest.FixtureChainID)) + head8 := evmtypes.NewHead(gethHead8.Number, utils.NewHash(), gethHead8.ParentHash, gethHead8.Time, ubig.New(&cltest.FixtureChainID)) h9 := *cltest.Head(9) h9.ParentHash = head8.Hash @@ -738,7 +741,7 @@ func TestHeadTracker_Backfill(t *testing.T) { ParentHash: h9.Hash, Time: now, } - head10 := evmtypes.NewHead(gethHead10.Number, utils.NewHash(), gethHead10.ParentHash, gethHead10.Time, utils.NewBig(&cltest.FixtureChainID)) + head10 := evmtypes.NewHead(gethHead10.Number, utils.NewHash(), gethHead10.ParentHash, gethHead10.Time, ubig.New(&cltest.FixtureChainID)) h11 := *cltest.Head(11) h11.ParentHash = head10.Hash @@ -992,7 +995,7 @@ func createHeadTracker(t *testing.T, ethClient evmclient.Client, config headtrac lggr := logger.Test(t) hb := headtracker.NewHeadBroadcaster(lggr) hs := headtracker.NewHeadSaver(lggr, orm, config, htConfig) - mailMon := utils.NewMailboxMonitor(t.Name()) + mailMon := mailboxtest.NewMonitor(t) return &headTrackerUniverse{ mu: new(sync.Mutex), headTracker: headtracker.NewHeadTracker(lggr, ethClient, config, htConfig, hb, hs, mailMon), @@ -1007,7 +1010,7 @@ func createHeadTrackerWithNeverSleeper(t *testing.T, ethClient evmclient.Client, lggr := logger.Test(t) hb := headtracker.NewHeadBroadcaster(lggr) hs := headtracker.NewHeadSaver(lggr, orm, evmcfg.EVM(), evmcfg.EVM().HeadTracker()) - mailMon := utils.NewMailboxMonitor(t.Name()) + mailMon := mailboxtest.NewMonitor(t) ht := headtracker.NewHeadTracker(lggr, ethClient, evmcfg.EVM(), evmcfg.EVM().HeadTracker(), hb, hs, mailMon) _, err := hs.Load(testutils.Context(t)) require.NoError(t, err) @@ -1025,7 +1028,7 @@ func createHeadTrackerWithChecker(t *testing.T, ethClient evmclient.Client, conf hb := headtracker.NewHeadBroadcaster(lggr) hs := headtracker.NewHeadSaver(lggr, orm, config, htConfig) hb.Subscribe(checker) - mailMon := utils.NewMailboxMonitor(t.Name()) + mailMon := mailboxtest.NewMonitor(t) ht := headtracker.NewHeadTracker(lggr, ethClient, config, htConfig, hb, hs, mailMon) return &headTrackerUniverse{ mu: new(sync.Mutex), @@ -1042,7 +1045,7 @@ type headTrackerUniverse struct { headTracker httypes.HeadTracker headBroadcaster httypes.HeadBroadcaster headSaver httypes.HeadSaver - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } func (u *headTrackerUniverse) Backfill(ctx context.Context, head *evmtypes.Head, depth uint) error { diff --git a/core/chains/evm/headtracker/heads_test.go b/core/chains/evm/headtracker/heads_test.go index 7da6b1cc9ba..9fa5ed4e548 100644 --- a/core/chains/evm/headtracker/heads_test.go +++ b/core/chains/evm/headtracker/heads_test.go @@ -10,8 +10,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" 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" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestHeads_LatestHead(t *testing.T) { @@ -77,11 +78,11 @@ func TestHeads_AddHeads(t *testing.T) { var parentHash common.Hash for i := 0; i < 5; i++ { hash := utils.NewHash() - h := evmtypes.NewHead(big.NewInt(int64(i)), hash, parentHash, uint64(time.Now().Unix()), utils.NewBigI(0)) + h := evmtypes.NewHead(big.NewInt(int64(i)), hash, parentHash, uint64(time.Now().Unix()), ubig.NewI(0)) testHeads = append(testHeads, &h) if i == 2 { // uncled block - h := evmtypes.NewHead(big.NewInt(int64(i)), uncleHash, parentHash, uint64(time.Now().Unix()), utils.NewBigI(0)) + h := evmtypes.NewHead(big.NewInt(int64(i)), uncleHash, parentHash, uint64(time.Now().Unix()), ubig.NewI(0)) testHeads = append(testHeads, &h) } parentHash = hash diff --git a/core/chains/evm/headtracker/mocks/config.go b/core/chains/evm/headtracker/mocks/config.go index b505cfc445d..74376a71362 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type Config struct { func (_m *Config) BlockEmissionIdleWarningThreshold() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BlockEmissionIdleWarningThreshold") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -31,6 +35,10 @@ func (_m *Config) BlockEmissionIdleWarningThreshold() time.Duration { func (_m *Config) FinalityDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() diff --git a/core/chains/evm/headtracker/orm.go b/core/chains/evm/headtracker/orm.go index 88d569b9a21..859f6764b63 100644 --- a/core/chains/evm/headtracker/orm.go +++ b/core/chains/evm/headtracker/orm.go @@ -12,8 +12,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ORM interface { @@ -32,11 +32,11 @@ type ORM interface { type orm struct { q pg.Q - chainID utils.Big + chainID ubig.Big } func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, chainID big.Int) ORM { - return &orm{pg.NewQ(db, logger.Named(lggr, "HeadTrackerORM"), cfg), utils.Big(chainID)} + return &orm{pg.NewQ(db, logger.Named(lggr, "HeadTrackerORM"), cfg), ubig.Big(chainID)} } func (orm *orm) IdempotentInsertHead(ctx context.Context, head *evmtypes.Head) error { diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index f4528396093..8321dd30bfe 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -14,14 +14,16 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" 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" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name Broadcaster --output ./mocks/ --case=underscore --structname Broadcaster --filename broadcaster.go @@ -102,11 +104,11 @@ type ( registrations *registrations logPool *logPool - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor // Use the same channel for subs/unsubs so ordering is preserved // (unsubscribe must happen after subscribe) - changeSubscriberStatus *utils.Mailbox[changeSubscriberStatus] - newHeads *utils.Mailbox[*evmtypes.Head] + changeSubscriberStatus *mailbox.Mailbox[changeSubscriberStatus] + newHeads *mailbox.Mailbox[*evmtypes.Head] utils.DependentAwaiter @@ -165,7 +167,7 @@ const ( var _ Broadcaster = (*broadcaster)(nil) // NewBroadcaster creates a new instance of the broadcaster -func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *utils.MailboxMonitor) *broadcaster { +func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *mailbox.Monitor) *broadcaster { chStop := make(chan struct{}) lggr = logger.Named(lggr, "LogBroadcaster") chainId := ethClient.ConfiguredChainID() @@ -178,8 +180,8 @@ func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr log registrations: newRegistrations(lggr, *chainId), logPool: newLogPool(lggr), mailMon: mailMon, - changeSubscriberStatus: utils.NewHighCapacityMailbox[changeSubscriberStatus](), - newHeads: utils.NewSingleMailbox[*evmtypes.Head](), + changeSubscriberStatus: mailbox.NewHighCapacity[changeSubscriberStatus](), + newHeads: mailbox.NewSingle[*evmtypes.Head](), DependentAwaiter: utils.NewDependentAwaiter(), chStop: chStop, highestSavedHead: highestSavedHead, @@ -393,7 +395,7 @@ func (b *broadcaster) reinitialize() (backfillStart *int64, abort bool) { ctx, cancel := b.chStop.NewCtx() defer cancel() - utils.RetryWithBackoff(ctx, func() bool { + evmutils.RetryWithBackoff(ctx, func() bool { var err error backfillStart, err = b.orm.Reinitialize(pg.WithParentCtx(ctx)) if err != nil { @@ -562,7 +564,7 @@ func (b *broadcaster) onNewHeads() { b.lastSeenHeadNumber.Store(latestHead.Number) - keptLogsDepth := uint32(b.config.FinalityDepth()) + keptLogsDepth := b.config.FinalityDepth() if b.registrations.highestNumConfirmations > keptLogsDepth { keptLogsDepth = b.registrations.highestNumConfirmations } diff --git a/core/chains/evm/log/eth_subscriber.go b/core/chains/evm/log/eth_subscriber.go index 96a7a8248a6..ff20a6e74e8 100644 --- a/core/chains/evm/log/eth_subscriber.go +++ b/core/chains/evm/log/eth_subscriber.go @@ -14,8 +14,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ( @@ -131,7 +131,7 @@ func (sub *ethSubscriber) backfillLogs(fromBlockOverride null.Int64, addresses [ return true } - sub.logger.Infow(fmt.Sprintf("LogBroadcaster: Fetched a batch of %v logs from %v to %v%s", len(batchLogs), from, to, elapsedMessage), "len", len(batchLogs), "fromBlock", from, "toBlock", to, "remaining", int64(latestHeight)-to) + sub.logger.Infow(fmt.Sprintf("LogBroadcaster: Fetched a batch of %v logs from %v to %v%s", len(batchLogs), from, to, elapsedMessage), "len", len(batchLogs), "fromBlock", from, "toBlock", to, "remaining", latestHeight-to) select { case <-sub.chStop: diff --git a/core/chains/evm/log/helpers_internal_test.go b/core/chains/evm/log/helpers_internal_test.go index 38f40bd329e..4d4318cdf9d 100644 --- a/core/chains/evm/log/helpers_internal_test.go +++ b/core/chains/evm/log/helpers_internal_test.go @@ -4,13 +4,14 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // NewTestBroadcaster creates a broadcaster with Pause/Resume enabled. -func NewTestBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *utils.MailboxMonitor) *broadcaster { +func NewTestBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *mailbox.Monitor) *broadcaster { b := NewBroadcaster(orm, ethClient, config, lggr, highestSavedHead, mailMon) b.testPause, b.testResume = make(chan struct{}), make(chan struct{}) return b diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index ac7eb863e62..35db8f7f7bf 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -21,12 +21,16 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" 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/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" @@ -39,9 +43,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" - evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type broadcasterHelper struct { @@ -89,7 +90,7 @@ func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, }) config := evmtest.NewChainScopedConfig(t, globalConfig) lggr := logger.Test(t) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) db := pgtest.NewSqlxDB(t) orm := log.NewORM(db, lggr, config.Database(), cltest.FixtureChainID) @@ -104,7 +105,12 @@ func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, LogBroadcaster: &log.NullBroadcaster{}, MailMon: mailMon, }) - legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) + + m := make(map[string]legacyevm.Chain) + for _, r := range cc.Slice() { + 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) return &broadcasterHelper{ @@ -240,7 +246,7 @@ func (rec *received) logsOnBlocks() []logOnBlock { type simpleLogListener struct { name string - lggr logger.Logger + lggr logger.SugaredLogger cfg pg.QConfig received *received t *testing.T @@ -265,7 +271,7 @@ func (helper *broadcasterHelper) newLogListenerWithJob(name string) *simpleLogLi var rec received return &simpleLogListener{ db: db, - lggr: logger.Test(t), + lggr: logger.Sugared(logger.Test(t)), cfg: helper.config.Database(), name: name, received: &rec, @@ -281,7 +287,7 @@ func (listener *simpleLogListener) SkipMarkingConsumed(skip bool) { func (listener *simpleLogListener) HandleLog(lb log.Broadcast) { listener.received.Lock() defer listener.received.Unlock() - logger.Tracef(listener.lggr, "Listener %v HandleLog for block %v %v received at %v %v", listener.name, lb.RawLog().BlockNumber, lb.RawLog().BlockHash, lb.LatestBlockNumber(), lb.LatestBlockHash()) + 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()) listener.received.logs = append(listener.received.logs, lb.RawLog()) listener.received.broadcasts = append(listener.received.broadcasts, lb) diff --git a/core/chains/evm/log/integration_test.go b/core/chains/evm/log/integration_test.go index edc04a4ada4..02a30c6d93f 100644 --- a/core/chains/evm/log/integration_test.go +++ b/core/chains/evm/log/integration_test.go @@ -17,18 +17,20 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" 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/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "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/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestBroadcaster_AwaitsInitialSubscribersOnStartup(t *testing.T) { @@ -1324,7 +1326,7 @@ func TestBroadcaster_AppendLogChannel(t *testing.T) { ch3 := make(chan types.Log) ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.RunHealthy(t, mailboxtest.NewMonitor(t)) lb := log.NewBroadcaster(nil, ethClient, nil, logger.Test(t), nil, mailMon) chCombined := lb.ExportedAppendLogChannel(ch1, ch2) chCombined = lb.ExportedAppendLogChannel(chCombined, ch3) diff --git a/core/chains/evm/log/mocks/abigen_contract.go b/core/chains/evm/log/mocks/abigen_contract.go index dcc95a1acdb..fde8949e4fe 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type AbigenContract struct { func (_m *AbigenContract) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -36,6 +40,10 @@ func (_m *AbigenContract) Address() common.Address { func (_m *AbigenContract) ParseLog(_a0 types.Log) (generated.AbigenLog, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { diff --git a/core/chains/evm/log/mocks/broadcast.go b/core/chains/evm/log/mocks/broadcast.go index a58ce9f30e4..6d9a83716d5 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type Broadcast struct { func (_m *Broadcast) DecodedLog() interface{} { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DecodedLog") + } + var r0 interface{} if rf, ok := ret.Get(0).(func() interface{}); ok { r0 = rf() @@ -37,6 +41,10 @@ func (_m *Broadcast) DecodedLog() interface{} { func (_m *Broadcast) EVMChainID() big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVMChainID") + } + var r0 big.Int if rf, ok := ret.Get(0).(func() big.Int); ok { r0 = rf() @@ -51,6 +59,10 @@ func (_m *Broadcast) EVMChainID() big.Int { func (_m *Broadcast) JobID() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for JobID") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() @@ -65,6 +77,10 @@ func (_m *Broadcast) JobID() int32 { func (_m *Broadcast) LatestBlockHash() common.Hash { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LatestBlockHash") + } + var r0 common.Hash if rf, ok := ret.Get(0).(func() common.Hash); ok { r0 = rf() @@ -81,6 +97,10 @@ func (_m *Broadcast) LatestBlockHash() common.Hash { func (_m *Broadcast) LatestBlockNumber() uint64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LatestBlockNumber") + } + var r0 uint64 if rf, ok := ret.Get(0).(func() uint64); ok { r0 = rf() @@ -95,6 +115,10 @@ func (_m *Broadcast) LatestBlockNumber() uint64 { func (_m *Broadcast) RawLog() types.Log { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RawLog") + } + var r0 types.Log if rf, ok := ret.Get(0).(func() types.Log); ok { r0 = rf() @@ -109,6 +133,10 @@ func (_m *Broadcast) RawLog() types.Log { func (_m *Broadcast) ReceiptsRoot() common.Hash { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ReceiptsRoot") + } + var r0 common.Hash if rf, ok := ret.Get(0).(func() common.Hash); ok { r0 = rf() @@ -125,6 +153,10 @@ func (_m *Broadcast) ReceiptsRoot() common.Hash { func (_m *Broadcast) StateRoot() common.Hash { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StateRoot") + } + var r0 common.Hash if rf, ok := ret.Get(0).(func() common.Hash); ok { r0 = rf() @@ -141,6 +173,10 @@ func (_m *Broadcast) StateRoot() common.Hash { func (_m *Broadcast) String() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -155,6 +191,10 @@ func (_m *Broadcast) String() string { func (_m *Broadcast) TransactionsRoot() common.Hash { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TransactionsRoot") + } + var r0 common.Hash if rf, ok := ret.Get(0).(func() common.Hash); ok { r0 = rf() diff --git a/core/chains/evm/log/mocks/broadcaster.go b/core/chains/evm/log/mocks/broadcaster.go index 84f143b39e4..031bdaaa7d9 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ func (_m *Broadcaster) AddDependents(n int) { func (_m *Broadcaster) AwaitDependents() <-chan struct{} { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AwaitDependents") + } + var r0 <-chan struct{} if rf, ok := ret.Get(0).(func() <-chan struct{}); ok { r0 = rf() @@ -43,6 +47,10 @@ func (_m *Broadcaster) AwaitDependents() <-chan struct{} { func (_m *Broadcaster) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -62,6 +70,10 @@ func (_m *Broadcaster) DependentReady() { func (_m *Broadcaster) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -78,6 +90,10 @@ func (_m *Broadcaster) HealthReport() map[string]error { func (_m *Broadcaster) IsConnected() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsConnected") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -99,6 +115,10 @@ func (_m *Broadcaster) MarkConsumed(lb log.Broadcast, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for MarkConsumed") + } + var r0 error if rf, ok := ret.Get(0).(func(log.Broadcast, ...pg.QOpt) error); ok { r0 = rf(lb, qopts...) @@ -120,6 +140,10 @@ func (_m *Broadcaster) MarkManyConsumed(lbs []log.Broadcast, qopts ...pg.QOpt) e _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for MarkManyConsumed") + } + var r0 error if rf, ok := ret.Get(0).(func([]log.Broadcast, ...pg.QOpt) error); ok { r0 = rf(lbs, qopts...) @@ -134,6 +158,10 @@ func (_m *Broadcaster) MarkManyConsumed(lbs []log.Broadcast, qopts ...pg.QOpt) e func (_m *Broadcaster) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -153,6 +181,10 @@ func (_m *Broadcaster) OnNewLongestChain(ctx context.Context, head *types.Head) func (_m *Broadcaster) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -167,6 +199,10 @@ func (_m *Broadcaster) Ready() error { func (_m *Broadcaster) Register(listener log.Listener, opts log.ListenerOpts) func() { ret := _m.Called(listener, opts) + if len(ret) == 0 { + panic("no return value specified for Register") + } + var r0 func() if rf, ok := ret.Get(0).(func(log.Listener, log.ListenerOpts) func()); ok { r0 = rf(listener, opts) @@ -188,6 +224,10 @@ func (_m *Broadcaster) ReplayFromBlock(number int64, forceBroadcast bool) { func (_m *Broadcaster) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -209,6 +249,10 @@ func (_m *Broadcaster) WasAlreadyConsumed(lb log.Broadcast, qopts ...pg.QOpt) (b _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for WasAlreadyConsumed") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(log.Broadcast, ...pg.QOpt) (bool, error)); ok { diff --git a/core/chains/evm/log/orm.go b/core/chains/evm/log/orm.go index a2bcab6e785..51ed9f2f132 100644 --- a/core/chains/evm/log/orm.go +++ b/core/chains/evm/log/orm.go @@ -12,8 +12,10 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ORM is the interface for log broadcasts. @@ -48,13 +50,13 @@ type ORM interface { type orm struct { q pg.Q - evmChainID utils.Big + evmChainID ubig.Big } var _ ORM = (*orm)(nil) func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, evmChainID big.Int) *orm { - return &orm{pg.NewQ(db, lggr, cfg), *utils.NewBig(&evmChainID)} + return &orm{pg.NewQ(db, lggr, cfg), *ubig.New(&evmChainID)} } func (o *orm) WasBroadcastConsumed(blockHash common.Hash, logIndex uint, jobID int32, qopts ...pg.QOpt) (consumed bool, err error) { @@ -128,7 +130,7 @@ func (o *orm) MarkBroadcastsConsumed(blockHashes []common.Hash, blockNumbers []u BlockNumber uint64 `db:"blockNumber"` LogIndex uint `db:"logIndex"` JobID int32 `db:"jobID"` - ChainID utils.Big `db:"chainID"` + ChainID ubig.Big `db:"chainID"` } inputs := make([]input, len(blockHashes)) query := ` diff --git a/core/chains/evm/log/registrations.go b/core/chains/evm/log/registrations.go index 73f197a6ab6..346a6776e86 100644 --- a/core/chains/evm/log/registrations.go +++ b/core/chains/evm/log/registrations.go @@ -46,7 +46,7 @@ type ( // handlersByConfs maps numConfirmations => *handler handlersByConfs map[uint32]*handler - logger logger.Logger + logger logger.SugaredLogger evmChainID big.Int // highest 'NumConfirmations' per all listeners, used to decide about deleting older logs if it's higher than EvmFinalityDepth @@ -57,7 +57,7 @@ type ( handler struct { lookupSubs map[common.Address]map[common.Hash]subscribers // contractAddress => logTopic => *subscriber => topicValueFilters evmChainID big.Int - logger logger.Logger + logger logger.SugaredLogger } // The Listener responds to log events through HandleLog. @@ -76,7 +76,7 @@ func newRegistrations(lggr logger.Logger, evmChainID big.Int) *registrations { jobIDAddrs: make(map[int32]map[common.Address]struct{}), handlersByConfs: make(map[uint32]*handler), evmChainID: evmChainID, - logger: logger.Named(lggr, "Registrations"), + logger: logger.Sugared(logger.Named(lggr, "Registrations")), } } @@ -85,7 +85,7 @@ func (r *registrations) addSubscriber(sub *subscriber) (needsResubscribe bool) { r.logger.Panicw(err.Error(), "err", err, "addr", sub.opts.Contract.Hex(), "jobID", sub.listener.JobID()) } - logger.Tracef(r.logger, "Added subscription %p with job ID %v", sub, sub.listener.JobID()) + r.logger.Tracef("Added subscription %p with job ID %v", sub, sub.listener.JobID()) handler, exists := r.handlersByConfs[sub.opts.MinIncomingConfirmations] if !exists { @@ -142,7 +142,7 @@ func (r *registrations) removeSubscriber(sub *subscriber) (needsResubscribe bool if err := r.checkRemoveSubscriber(sub); err != nil { r.logger.Panicw(err.Error(), "err", err, "addr", sub.opts.Contract.Hex(), "jobID", sub.listener.JobID()) } - logger.Tracef(r.logger, "Removed subscription %p with job ID %v", sub, sub.listener.JobID()) + r.logger.Tracef("Removed subscription %p with job ID %v", sub, sub.listener.JobID()) handlers, exists := r.handlersByConfs[sub.opts.MinIncomingConfirmations] if !exists { @@ -263,7 +263,7 @@ func filtersContainValues(topicValues []common.Hash, filters [][]Topic) bool { return true } -func newHandler(lggr logger.Logger, evmChainID big.Int) *handler { +func newHandler(lggr logger.SugaredLogger, evmChainID big.Int) *handler { return &handler{ lookupSubs: make(map[common.Address]map[common.Hash]subscribers), evmChainID: evmChainID, @@ -284,7 +284,7 @@ func (r *handler) addSubscriber(sub *subscriber, handlersWithGreaterConfs []*han for topic, topicValueFilters := range sub.opts.LogsWithTopics { if _, exists := r.lookupSubs[addr][topic]; !exists { - logger.Tracef(r.logger, "No existing sub for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + r.logger.Tracef("No existing sub for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) r.lookupSubs[addr][topic] = make(subscribers) func() { @@ -295,11 +295,11 @@ func (r *handler) addSubscriber(sub *subscriber, handlersWithGreaterConfs []*han // again since even the worst case lookback is already covered for _, existingHandler := range handlersWithGreaterConfs { if _, exists := existingHandler.lookupSubs[addr][topic]; exists { - logger.Tracef(r.logger, "Sub already exists for addr %s and topic %s at greater than this MinIncomingConfirmations of %v. Resubscribe is not required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + r.logger.Tracef("Sub already exists for addr %s and topic %s at greater than this MinIncomingConfirmations of %v. Resubscribe is not required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) return } } - logger.Tracef(r.logger, "No sub exists for addr %s and topic %s at this or greater MinIncomingConfirmations of %v. Resubscribe is required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + r.logger.Tracef("No sub exists for addr %s and topic %s at this or greater MinIncomingConfirmations of %v. Resubscribe is required", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) needsResubscribe = true } }() @@ -332,7 +332,7 @@ func (r *handler) removeSubscriber(sub *subscriber, allHandlers map[uint32]*hand // cleanup and resubscribe if necessary if len(topicMap) == 0 { - logger.Tracef(r.logger, "No subs left for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) + r.logger.Tracef("No subs left for addr %s and topic %s at this MinIncomingConfirmations of %v", addr.Hex(), topic.Hex(), sub.opts.MinIncomingConfirmations) func() { if !needsResubscribe { @@ -344,12 +344,12 @@ func (r *handler) removeSubscriber(sub *subscriber, allHandlers map[uint32]*hand continue } if _, exists := otherHandler.lookupSubs[addr][topic]; exists { - logger.Tracef(r.logger, "Sub still exists for addr %s and topic %s. Resubscribe will not be performed", addr.Hex(), topic.Hex()) + r.logger.Tracef("Sub still exists for addr %s and topic %s. Resubscribe will not be performed", addr.Hex(), topic.Hex()) return } } - logger.Tracef(r.logger, "No sub exists for addr %s and topic %s. Resubscribe will be performed", addr.Hex(), topic.Hex()) + r.logger.Tracef("No sub exists for addr %s and topic %s. Resubscribe will be performed", addr.Hex(), topic.Hex()) needsResubscribe = true } }() diff --git a/core/chains/evm/log/registrations_test.go b/core/chains/evm/log/registrations_test.go index 0682564fe72..2be01dca2bf 100644 --- a/core/chains/evm/log/registrations_test.go +++ b/core/chains/evm/log/registrations_test.go @@ -8,8 +8,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ Listener = testListener{} diff --git a/core/chains/evm/logpoller/log_poller.go b/core/chains/evm/logpoller/log_poller.go index de1999da260..7006c1762ef 100644 --- a/core/chains/evm/logpoller/log_poller.go +++ b/core/chains/evm/logpoller/log_poller.go @@ -22,12 +22,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) //go:generate mockery --quiet --name LogPoller --output ./mocks/ --case=underscore --structname LogPoller --filename log_poller.go @@ -97,7 +98,7 @@ type logPoller struct { services.StateMachine ec Client orm ORM - lggr logger.Logger + lggr logger.SugaredLogger pollPeriod time.Duration // poll period set by block production rate useFinalityTag bool // indicates whether logPoller should use chain's finality or pick a fixed depth for finality finalityDepth int64 // finality depth is taken to mean that block (head - finality) is finalized. If `useFinalityTag` is set to true, this value is ignored, because finalityDepth is fetched from chain @@ -137,7 +138,7 @@ func NewLogPoller(orm ORM, ec Client, lggr logger.Logger, pollPeriod time.Durati cancel: cancel, ec: ec, orm: orm, - lggr: logger.Named(lggr, "LogPoller"), + lggr: logger.Sugared(logger.Named(lggr, "LogPoller")), replayStart: make(chan int64), replayComplete: make(chan error), pollPeriod: pollPeriod, @@ -216,6 +217,7 @@ func (filter *Filter) Contains(other *Filter) bool { // Generally speaking this is harmless. We enforce that EventSigs and Addresses are non-empty, // which means that anonymous events are not supported and log.Topics >= 1 always (log.Topics[0] is the event signature). // The filter may be unregistered later by Filter.Name +// Warnings/debug information is keyed by filter name. func (lp *logPoller) RegisterFilter(filter Filter, qopts ...pg.QOpt) error { if len(filter.Addresses) == 0 { return errors.Errorf("at least one address must be specified") @@ -241,33 +243,35 @@ func (lp *logPoller) RegisterFilter(filter Filter, qopts ...pg.QOpt) error { if existingFilter, ok := lp.filters[filter.Name]; ok { if existingFilter.Contains(&filter) { // Nothing new in this Filter + lp.lggr.Warnw("Filter already present, no-op", "name", filter.Name, "filter", filter) return nil } - lp.lggr.Warnw("Updating existing filter with more events or addresses", "filter", filter) - } else { - lp.lggr.Debugw("Creating new filter", "filter", filter) + lp.lggr.Warnw("Updating existing filter with more events or addresses", "name", filter.Name, "filter", filter) } if err := lp.orm.InsertFilter(filter, qopts...); err != nil { - return errors.Wrap(err, "RegisterFilter failed to save filter to db") + return errors.Wrap(err, "error inserting filter") } lp.filters[filter.Name] = filter lp.filterDirty = true return nil } +// UnregisterFilter will remove the filter with the given name. +// If the name does not exist, it will log an error but not return an error. +// Warnings/debug information is keyed by filter name. func (lp *logPoller) UnregisterFilter(name string, qopts ...pg.QOpt) error { lp.filterMu.Lock() defer lp.filterMu.Unlock() _, ok := lp.filters[name] if !ok { - lp.lggr.Errorf("Filter %s not found", name) + lp.lggr.Warnw("Filter not found", "name", name) return nil } if err := lp.orm.DeleteFilter(name, qopts...); err != nil { - return errors.Wrapf(err, "Failed to delete filter %s", name) + return errors.Wrap(err, "error deleting filter") } delete(lp.filters, name) lp.filterDirty = true @@ -608,7 +612,7 @@ func convertLogs(logs []types.Log, blocks []LogPollerBlock, lggr logger.Logger, blockTimestamp = blocks[i].BlockTimestamp } lgs = append(lgs, Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: int64(l.Index), BlockHash: l.BlockHash, // We assume block numbers fit in int64 @@ -662,7 +666,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { } } if batchSize == 1 { - logger.Criticalw(lp.lggr, "Too many log results in a single block, failed to retrieve logs! Node may be running in a degraded state.", "err", err, "from", from, "to", to, "LogBackfillBatchSize", lp.backfillBatchSize) + lp.lggr.Criticalw("Too many log results in a single block, failed to retrieve logs! Node may be running in a degraded state.", "err", err, "from", from, "to", to, "LogBackfillBatchSize", lp.backfillBatchSize) return err } batchSize /= 2 @@ -679,7 +683,7 @@ func (lp *logPoller) backfill(ctx context.Context, start, end int64) error { } lp.lggr.Debugw("Backfill found logs", "from", from, "to", to, "logs", len(gethLogs), "blocks", blocks) - err = lp.orm.InsertLogs(convertLogs(gethLogs, blocks, lp.lggr, lp.ec.ConfiguredChainID()), pg.WithParentCtx(ctx)) + err = lp.orm.InsertLogsWithBlock(convertLogs(gethLogs, blocks, lp.lggr, lp.ec.ConfiguredChainID()), blocks[len(blocks)-1], pg.WithParentCtx(ctx)) if err != nil { lp.lggr.Warnw("Unable to insert logs, retrying", "err", err, "from", from, "to", to) return err @@ -917,7 +921,7 @@ func (lp *logPoller) findBlockAfterLCA(ctx context.Context, current *evmtypes.He return nil, err } } - logger.Criticalw(lp.lggr, "Reorg greater than finality depth detected", "finalityTag", lp.useFinalityTag, "current", current.Number, "latestFinalized", latestFinalizedBlockNumber) + lp.lggr.Criticalw("Reorg greater than finality depth detected", "finalityTag", lp.useFinalityTag, "current", current.Number, "latestFinalized", latestFinalizedBlockNumber) rerr := errors.New("Reorg greater than finality depth") lp.SvcErrBuffer.Append(rerr) return nil, rerr @@ -1056,7 +1060,7 @@ func (lp *logPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts qopts = append(qopts, pg.WithParentCtx(ctx)) minRequestedBlock := int64(mathutil.Min(numbers[0], numbers[1:]...)) maxRequestedBlock := int64(mathutil.Max(numbers[0], numbers[1:]...)) - lpBlocks, err := lp.orm.GetBlocksRange(int64(minRequestedBlock), int64(maxRequestedBlock), qopts...) + lpBlocks, err := lp.orm.GetBlocksRange(minRequestedBlock, maxRequestedBlock, qopts...) if err != nil { lp.lggr.Warnw("Error while retrieving blocks from log pollers blocks table. Falling back to RPC...", "requestedBlocks", numbers, "err", err) } else { diff --git a/core/chains/evm/logpoller/log_poller_internal_test.go b/core/chains/evm/logpoller/log_poller_internal_test.go index e3ba8b655e8..863ab0fddea 100644 --- a/core/chains/evm/logpoller/log_poller_internal_test.go +++ b/core/chains/evm/logpoller/log_poller_internal_test.go @@ -22,14 +22,15 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -56,7 +57,7 @@ func TestLogPoller_RegisterFilter(t *testing.T) { a1 := common.HexToAddress("0x2ab9a2dc53736b361b72d900cdf9f78f9406fbbb") a2 := common.HexToAddress("0x2ab9a2dc53736b361b72d900cdf9f78f9406fbbc") - lggr, observedLogs := logger.TestObserved(t, zapcore.ErrorLevel) + lggr, observedLogs := logger.TestObserved(t, zapcore.WarnLevel) chainID := testutils.NewRandomEVMChainID() db := pgtest.NewSqlxDB(t) @@ -351,8 +352,7 @@ func TestLogPoller_Replay(t *testing.T) { ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Maybe() // in case task gets delayed by >= 100ms t.Cleanup(lp.reset) - require.NoError(t, lp.Start(ctx)) - t.Cleanup(func() { assert.NoError(t, lp.Close()) }) + servicetest.Run(t, lp) select { case <-ctx.Done(): @@ -389,8 +389,7 @@ func TestLogPoller_Replay(t *testing.T) { ec.On("FilterLogs", mock.Anything, mock.Anything).Return([]types.Log{log1}, nil).Maybe() // in case task gets delayed by >= 100ms t.Cleanup(lp.reset) - require.NoError(t, lp.Start(ctx)) - t.Cleanup(func() { assert.NoError(t, lp.Close()) }) + servicetest.Run(t, lp) select { case <-ctx.Done(): @@ -402,8 +401,7 @@ func TestLogPoller_Replay(t *testing.T) { // ReplayAsync should return as soon as replayStart is received t.Run("ReplayAsync success", func(t *testing.T) { t.Cleanup(lp.reset) - require.NoError(t, lp.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, lp.Close()) }) + servicetest.Run(t, lp) lp.ReplayAsync(1) @@ -412,8 +410,7 @@ func TestLogPoller_Replay(t *testing.T) { t.Run("ReplayAsync error", func(t *testing.T) { t.Cleanup(lp.reset) - require.NoError(t, lp.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, lp.Close()) }) + servicetest.Run(t, lp) anyErr := errors.New("async error") observedLogs.TakeAll() diff --git a/core/chains/evm/logpoller/log_poller_test.go b/core/chains/evm/logpoller/log_poller_test.go index 82447bdb5f4..2508e676e6c 100644 --- a/core/chains/evm/logpoller/log_poller_test.go +++ b/core/chains/evm/logpoller/log_poller_test.go @@ -20,24 +20,25 @@ import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/gen" "github.com/leanovate/gopter/prop" - "github.com/lib/pq" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-common/pkg/logger" + commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" 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" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "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/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func logRuntime(t testing.TB, start time.Time) { @@ -62,7 +63,7 @@ func populateDatabase(t testing.TB, o *logpoller.DbORM, chainID *big.Int) (commo blockTimestamp := startDate.Add(time.Duration(j*1000) * time.Hour) logs = append(logs, logpoller.Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: 1, BlockHash: common.HexToHash(fmt.Sprintf("0x%d", i+(1000*j))), BlockNumber: blockNumber, @@ -70,14 +71,14 @@ func populateDatabase(t testing.TB, o *logpoller.DbORM, chainID *big.Int) (commo EventSig: event1, Topics: [][]byte{event1[:], logpoller.EvmWord(uint64(i + 1000*j)).Bytes()}, Address: addr, - TxHash: utils.RandomAddress().Hash(), + TxHash: utils.RandomHash(), Data: logpoller.EvmWord(uint64(i + 1000*j)).Bytes(), CreatedAt: blockTimestamp, }) } require.NoError(t, o.InsertLogs(logs)) - require.NoError(t, o.InsertBlock(utils.RandomAddress().Hash(), int64((j+1)*1000-1), startDate.Add(time.Duration(j*1000)*time.Hour), 0)) + require.NoError(t, o.InsertBlock(utils.RandomHash(), int64((j+1)*1000-1), startDate.Add(time.Duration(j*1000)*time.Hour), 0)) } return event1, address1, address2 @@ -965,8 +966,8 @@ func TestLogPoller_PollAndSaveLogs(t *testing.T) { lgs, err = th.ORM.SelectLogsByBlockRange(11, 17) require.NoError(t, err) assert.Equal(t, 7, len(lgs)) - th.assertHaveCanonical(t, 15, 16) - th.assertDontHave(t, 11, 14) // Do not expect to save backfilled blocks. + th.assertHaveCanonical(t, 14, 16) // Should have last finalized block plus unfinalized blocks + th.assertDontHave(t, 11, 13) // Should not have older finalized blocks // Verify that a custom block timestamp will get written to db correctly also b, err = th.Client.BlockByNumber(testutils.Context(t), nil) @@ -1057,8 +1058,8 @@ func TestLogPoller_PollAndSaveLogsDeepReorg(t *testing.T) { require.NoError(t, err) assert.Equal(t, hexutil.MustDecode(`0x0000000000000000000000000000000000000000000000000000000000000002`), lgs[0].Data) th.assertHaveCanonical(t, 1, 1) - th.assertDontHave(t, 2, 5) // These blocks are backfilled - th.assertHaveCanonical(t, 6, 10) + th.assertDontHave(t, 2, 3) // These blocks are backfilled + th.assertHaveCanonical(t, 5, 10) }) } } @@ -1293,7 +1294,7 @@ func TestLogPoller_DBErrorHandling(t *testing.T) { require.ErrorContains(t, err, "Invalid replay block number") // Force a db error while loading the filters (tx aborted, already rolled back) - require.Error(t, utils.JustError(db.Exec(`invalid query`))) + require.Error(t, commonutils.JustError(db.Exec(`invalid query`))) go func() { err = lp.Replay(ctx, 2) assert.ErrorContains(t, err, "current transaction is aborted") @@ -1322,61 +1323,6 @@ func TestLogPoller_DBErrorHandling(t *testing.T) { assert.Contains(t, logMsgs, "Backup log poller ran before filters loaded, skipping") } -func TestNotifyAfterInsert(t *testing.T) { - t.Parallel() - - // Use a non-transactional db for this test because notify events - // are not delivered until the transaction is committed. - var dbURL string - _, sqlxDB := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - dbURL = s.Database.URL.URL().String() - }) - - lggr, _ := logger.TestObserved(t, zapcore.WarnLevel) - chainID := big.NewInt(1337) - o := logpoller.NewORM(chainID, sqlxDB, lggr, pgtest.NewQConfig(true)) - - listener := pq.NewListener(dbURL, time.Second, time.Second, nil) - err := listener.Listen(pg.ChannelInsertOnEVMLogs) - require.NoError(t, err) - - log := logpoller.Log{ - EvmChainId: utils.NewBig(chainID), - LogIndex: 10, - BlockHash: testutils.Random32Byte(), - BlockNumber: 100, - BlockTimestamp: time.Now(), - Topics: pq.ByteaArray{ - testutils.NewAddress().Bytes(), - testutils.NewAddress().Bytes(), - }, - EventSig: testutils.Random32Byte(), - Address: testutils.NewAddress(), - TxHash: testutils.Random32Byte(), - Data: []byte("test_data"), - CreatedAt: time.Now(), - } - - err = o.InsertLogs([]logpoller.Log{log}) - require.NoError(t, err) - - testutils.AssertEventually(t, func() bool { - select { - case event := <-listener.Notify: - expectedPayload := fmt.Sprintf( - "%s:%s,%s", - hexutil.Encode(log.Address.Bytes())[2:], // strip the leading 0x - hexutil.Encode(log.Topics[0])[2:], - hexutil.Encode(log.Topics[1])[2:], - ) - require.Equal(t, event.Extra, expectedPayload) - return true - default: - return false - } - }) -} - type getLogErrData struct { From string To string diff --git a/core/chains/evm/logpoller/mocks/log_poller.go b/core/chains/evm/logpoller/mocks/log_poller.go index fe4ccc965cc..65d808b98d5 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -25,6 +25,10 @@ type LogPoller struct { func (_m *LogPoller) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -46,6 +50,10 @@ func (_m *LogPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetBlocksRange") + } + var r0 []logpoller.LogPollerBlock var r1 error if rf, ok := ret.Get(0).(func(context.Context, []uint64, ...pg.QOpt) ([]logpoller.LogPollerBlock, error)); ok { @@ -72,6 +80,10 @@ func (_m *LogPoller) GetBlocksRange(ctx context.Context, numbers []uint64, qopts func (_m *LogPoller) HasFilter(name string) bool { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for HasFilter") + } + var r0 bool if rf, ok := ret.Get(0).(func(string) bool); ok { r0 = rf(name) @@ -86,6 +98,10 @@ func (_m *LogPoller) HasFilter(name string) bool { func (_m *LogPoller) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -109,6 +125,10 @@ func (_m *LogPoller) IndexedLogs(eventSig common.Hash, address common.Address, t _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogs") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -142,6 +162,10 @@ func (_m *LogPoller) IndexedLogsByBlockRange(start int64, end int64, eventSig co _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsByBlockRange") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(int64, int64, common.Hash, common.Address, int, []common.Hash, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -175,6 +199,10 @@ func (_m *LogPoller) IndexedLogsByTxHash(eventSig common.Hash, address common.Ad _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsByTxHash") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, common.Hash, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -208,6 +236,10 @@ func (_m *LogPoller) IndexedLogsCreatedAfter(eventSig common.Hash, address commo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsCreatedAfter") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, []common.Hash, time.Time, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -241,6 +273,10 @@ func (_m *LogPoller) IndexedLogsTopicGreaterThan(eventSig common.Hash, address c _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsTopicGreaterThan") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -274,6 +310,10 @@ func (_m *LogPoller) IndexedLogsTopicRange(eventSig common.Hash, address common. _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsTopicRange") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -307,6 +347,10 @@ func (_m *LogPoller) IndexedLogsWithSigsExcluding(address common.Address, eventS _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IndexedLogsWithSigsExcluding") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Address, common.Hash, common.Hash, int, int64, int64, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -339,6 +383,10 @@ func (_m *LogPoller) LatestBlock(qopts ...pg.QOpt) (logpoller.LogPollerBlock, er _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LatestBlock") + } + var r0 logpoller.LogPollerBlock var r1 error if rf, ok := ret.Get(0).(func(...pg.QOpt) (logpoller.LogPollerBlock, error)); ok { @@ -370,6 +418,10 @@ func (_m *LogPoller) LatestBlockByEventSigsAddrsWithConfs(fromBlock int64, event _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LatestBlockByEventSigsAddrsWithConfs") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, logpoller.Confirmations, ...pg.QOpt) (int64, error)); ok { @@ -401,6 +453,10 @@ func (_m *LogPoller) LatestLogByEventSigWithConfs(eventSig common.Hash, address _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LatestLogByEventSigWithConfs") + } + var r0 *logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, logpoller.Confirmations, ...pg.QOpt) (*logpoller.Log, error)); ok { @@ -434,6 +490,10 @@ func (_m *LogPoller) LatestLogEventSigsAddrsWithConfs(fromBlock int64, eventSigs _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LatestLogEventSigsAddrsWithConfs") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(int64, []common.Hash, []common.Address, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -467,6 +527,10 @@ func (_m *LogPoller) Logs(start int64, end int64, eventSig common.Hash, address _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Logs") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(int64, int64, common.Hash, common.Address, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -500,6 +564,10 @@ func (_m *LogPoller) LogsCreatedAfter(eventSig common.Hash, address common.Addre _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LogsCreatedAfter") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, time.Time, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -533,6 +601,10 @@ func (_m *LogPoller) LogsDataWordBetween(eventSig common.Hash, address common.Ad _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LogsDataWordBetween") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -566,6 +638,10 @@ func (_m *LogPoller) LogsDataWordGreaterThan(eventSig common.Hash, address commo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LogsDataWordGreaterThan") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -599,6 +675,10 @@ func (_m *LogPoller) LogsDataWordRange(eventSig common.Hash, address common.Addr _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LogsDataWordRange") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(common.Hash, common.Address, int, common.Hash, common.Hash, logpoller.Confirmations, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -632,6 +712,10 @@ func (_m *LogPoller) LogsWithSigs(start int64, end int64, eventSigs []common.Has _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for LogsWithSigs") + } + var r0 []logpoller.Log var r1 error if rf, ok := ret.Get(0).(func(int64, int64, []common.Hash, common.Address, ...pg.QOpt) ([]logpoller.Log, error)); ok { @@ -658,6 +742,10 @@ func (_m *LogPoller) LogsWithSigs(start int64, end int64, eventSigs []common.Has func (_m *LogPoller) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -672,6 +760,10 @@ func (_m *LogPoller) Name() string { func (_m *LogPoller) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -693,6 +785,10 @@ func (_m *LogPoller) RegisterFilter(filter logpoller.Filter, qopts ...pg.QOpt) e _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RegisterFilter") + } + var r0 error if rf, ok := ret.Get(0).(func(logpoller.Filter, ...pg.QOpt) error); ok { r0 = rf(filter, qopts...) @@ -707,6 +803,10 @@ func (_m *LogPoller) RegisterFilter(filter logpoller.Filter, qopts ...pg.QOpt) e func (_m *LogPoller) Replay(ctx context.Context, fromBlock int64) error { ret := _m.Called(ctx, fromBlock) + if len(ret) == 0 { + panic("no return value specified for Replay") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, fromBlock) @@ -726,6 +826,10 @@ func (_m *LogPoller) ReplayAsync(fromBlock int64) { func (_m *LogPoller) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -747,6 +851,10 @@ func (_m *LogPoller) UnregisterFilter(name string, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UnregisterFilter") + } + var r0 error if rf, ok := ret.Get(0).(func(string, ...pg.QOpt) error); ok { r0 = rf(name, qopts...) diff --git a/core/chains/evm/logpoller/models.go b/core/chains/evm/logpoller/models.go index 87ddd079a5b..c5d6f5eab1c 100644 --- a/core/chains/evm/logpoller/models.go +++ b/core/chains/evm/logpoller/models.go @@ -7,13 +7,13 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/lib/pq" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // LogPollerBlock represents an unfinalized block // used for reorg detection when polling. type LogPollerBlock struct { - EvmChainId *utils.Big + EvmChainId *big.Big BlockHash common.Hash // Note geth uses int64 internally https://github.com/ethereum/go-ethereum/blob/f66f1a16b3c480d3a43ac7e8a09ab3e362e96ae4/eth/filters/api.go#L340 BlockNumber int64 @@ -24,7 +24,7 @@ type LogPollerBlock struct { // Log represents an EVM log. type Log struct { - EvmChainId *utils.Big + EvmChainId *big.Big LogIndex int64 BlockHash common.Hash BlockNumber int64 diff --git a/core/chains/evm/logpoller/observability_test.go b/core/chains/evm/logpoller/observability_test.go index 76575f46ca4..eb81273af2c 100644 --- a/core/chains/evm/logpoller/observability_test.go +++ b/core/chains/evm/logpoller/observability_test.go @@ -16,10 +16,11 @@ import ( "github.com/prometheus/client_golang/prometheus/testutil" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "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/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestMultipleMetricsArePublished(t *testing.T) { @@ -126,7 +127,7 @@ func generateRandomLogs(chainId, count int) []Log { logs := make([]Log, count) for i := range logs { logs[i] = Log{ - EvmChainId: utils.NewBigI(int64(chainId)), + EvmChainId: ubig.NewI(int64(chainId)), LogIndex: int64(i + 1), BlockHash: utils.RandomBytes32(), BlockNumber: int64(i + 1), diff --git a/core/chains/evm/logpoller/orm.go b/core/chains/evm/logpoller/orm.go index c24d423b253..663c56d10ed 100644 --- a/core/chains/evm/logpoller/orm.go +++ b/core/chains/evm/logpoller/orm.go @@ -12,8 +12,8 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ORM represents the persistent data access layer used by the log poller. At this moment, it's a bit leaky abstraction, because @@ -119,7 +119,7 @@ func (o *DbORM) InsertFilter(filter Filter, qopts ...pg.QOpt) (err error) { // DeleteFilter removes all events,address pairs associated with the Filter func (o *DbORM) DeleteFilter(name string, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - return q.ExecQ(`DELETE FROM evm.log_poller_filters WHERE name = $1 AND evm_chain_id = $2`, name, utils.NewBig(o.chainID)) + return q.ExecQ(`DELETE FROM evm.log_poller_filters WHERE name = $1 AND evm_chain_id = $2`, name, ubig.New(o.chainID)) } // LoadFiltersForChain returns all filters for this chain @@ -131,7 +131,7 @@ func (o *DbORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { ARRAY_AGG(DISTINCT event)::BYTEA[] AS event_sigs, MAX(retention) AS retention FROM evm.log_poller_filters WHERE evm_chain_id = $1 - GROUP BY name`, utils.NewBig(o.chainID)) + GROUP BY name`, ubig.New(o.chainID)) filters := make(map[string]Filter) for _, filter := range rows { filters[filter.Name] = filter @@ -143,7 +143,7 @@ func (o *DbORM) LoadFilters(qopts ...pg.QOpt) (map[string]Filter, error) { func (o *DbORM) SelectBlockByHash(hash common.Hash, qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock - if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_hash = $1 AND evm_chain_id = $2`, hash, utils.NewBig(o.chainID)); err != nil { + if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_hash = $1 AND evm_chain_id = $2`, hash, ubig.New(o.chainID)); err != nil { return nil, err } return &b, nil @@ -152,7 +152,7 @@ func (o *DbORM) SelectBlockByHash(hash common.Hash, qopts ...pg.QOpt) (*LogPolle func (o *DbORM) SelectBlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock - if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_number = $1 AND evm_chain_id = $2`, n, utils.NewBig(o.chainID)); err != nil { + if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE block_number = $1 AND evm_chain_id = $2`, n, ubig.New(o.chainID)); err != nil { return nil, err } return &b, nil @@ -161,7 +161,7 @@ func (o *DbORM) SelectBlockByNumber(n int64, qopts ...pg.QOpt) (*LogPollerBlock, func (o *DbORM) SelectLatestBlock(qopts ...pg.QOpt) (*LogPollerBlock, error) { q := o.q.WithOpts(qopts...) var b LogPollerBlock - if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1`, utils.NewBig(o.chainID)); err != nil { + if err := q.Get(&b, `SELECT * FROM evm.log_poller_blocks WHERE evm_chain_id = $1 ORDER BY block_number DESC LIMIT 1`, ubig.New(o.chainID)); err != nil { return nil, err } return &b, nil @@ -191,7 +191,7 @@ func (o *DbORM) SelectLatestLogByEventSigWithConfs(eventSig common.Hash, address // DeleteBlocksBefore delete all blocks before and including end. func (o *DbORM) DeleteBlocksBefore(end int64, qopts ...pg.QOpt) error { q := o.q.WithOpts(qopts...) - _, err := q.Exec(`DELETE FROM evm.log_poller_blocks WHERE block_number <= $1 AND evm_chain_id = $2`, end, utils.NewBig(o.chainID)) + _, err := q.Exec(`DELETE FROM evm.log_poller_blocks WHERE block_number <= $1 AND evm_chain_id = $2`, end, ubig.New(o.chainID)) return err } @@ -241,7 +241,7 @@ func (o *DbORM) DeleteExpiredLogs(qopts ...pg.QOpt) error { ) DELETE FROM evm.logs l USING r WHERE l.evm_chain_id = $1 AND l.address=r.address AND l.event_sig=r.event AND l.created_at <= STATEMENT_TIMESTAMP() - (r.retention / 10^9 * interval '1 second')`, // retention is in nanoseconds (time.Duration aka BIGINT) - utils.NewBig(o.chainID)) + ubig.New(o.chainID)) } // InsertLogs is idempotent to support replays. diff --git a/core/chains/evm/logpoller/orm_test.go b/core/chains/evm/logpoller/orm_test.go index 2a6ebb2c04e..0af62ebd547 100644 --- a/core/chains/evm/logpoller/orm_test.go +++ b/core/chains/evm/logpoller/orm_test.go @@ -18,11 +18,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "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" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type block struct { @@ -37,7 +38,7 @@ func GenLog(chainID *big.Int, logIndex int64, blockNum int64, blockHash string, func GenLogWithTimestamp(chainID *big.Int, logIndex int64, blockNum int64, blockHash string, topic1 []byte, address common.Address, blockTimestamp time.Time) logpoller.Log { return logpoller.Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: logIndex, BlockHash: common.HexToHash(blockHash), BlockNumber: blockNum, @@ -52,7 +53,7 @@ func GenLogWithTimestamp(chainID *big.Int, logIndex int64, blockNum int64, block func GenLogWithData(chainID *big.Int, address common.Address, eventSig common.Hash, logIndex int64, blockNum int64, data []byte) logpoller.Log { return logpoller.Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: logIndex, BlockHash: utils.RandomBytes32(), BlockNumber: blockNum, @@ -219,7 +220,7 @@ func TestORM(t *testing.T) { topic2 := common.HexToHash("0x1600") require.NoError(t, o1.InsertLogs([]logpoller.Log{ { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 1, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(10), @@ -230,7 +231,7 @@ func TestORM(t *testing.T) { Data: []byte("hello"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 2, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(11), @@ -241,7 +242,7 @@ func TestORM(t *testing.T) { Data: []byte("hello"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 3, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(12), @@ -252,7 +253,7 @@ func TestORM(t *testing.T) { Data: []byte("hello"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 4, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(13), @@ -263,7 +264,7 @@ func TestORM(t *testing.T) { Data: []byte("hello"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 5, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(14), @@ -274,7 +275,7 @@ func TestORM(t *testing.T) { Data: []byte("hello2"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 6, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(15), @@ -285,7 +286,7 @@ func TestORM(t *testing.T) { Data: []byte("hello2"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 7, BlockHash: common.HexToHash("0x1237"), BlockNumber: int64(16), @@ -296,7 +297,7 @@ func TestORM(t *testing.T) { Data: []byte("hello short retention"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 8, BlockHash: common.HexToHash("0x1238"), BlockNumber: int64(17), @@ -451,7 +452,7 @@ func insertLogsTopicValueRange(t *testing.T, chainID *big.Int, o *logpoller.DbOR var lgs []logpoller.Log for i := start; i <= stop; i++ { lgs = append(lgs, logpoller.Log{ - EvmChainId: utils.NewBig(chainID), + EvmChainId: ubig.New(chainID), LogIndex: int64(i), BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(blockNumber), @@ -536,7 +537,7 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { require.NoError(t, o1.InsertBlock(common.HexToHash("0x1"), 1, time.Now(), 0)) logs := []logpoller.Log{ { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(0), BlockHash: common.HexToHash("0x1"), BlockNumber: int64(1), @@ -547,7 +548,7 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { Data: logpoller.EvmWord(1).Bytes(), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(1), BlockHash: common.HexToHash("0x1"), BlockNumber: int64(1), @@ -559,7 +560,7 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { }, // Different txHash { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(2), BlockHash: common.HexToHash("0x1"), BlockNumber: int64(1), @@ -571,7 +572,7 @@ func TestORM_SelectIndexedLogsByTxHash(t *testing.T) { }, // Different eventSig { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(3), BlockHash: common.HexToHash("0x1"), BlockNumber: int64(1), @@ -600,7 +601,7 @@ func TestORM_DataWords(t *testing.T) { require.NoError(t, o1.InsertBlock(common.HexToHash("0x1"), 1, time.Now(), 0)) require.NoError(t, o1.InsertLogs([]logpoller.Log{ { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(0), BlockHash: common.HexToHash("0x1"), BlockNumber: int64(1), @@ -612,7 +613,7 @@ func TestORM_DataWords(t *testing.T) { }, { // In block 2, unconfirmed to start - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(1), BlockHash: common.HexToHash("0x2"), BlockNumber: int64(2), @@ -667,7 +668,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { sourceAddr := common.HexToAddress("0x12345") inputLogs := []logpoller.Log{ { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 1, BlockHash: common.HexToHash("0x1234"), BlockNumber: int64(10), @@ -678,7 +679,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { Data: []byte("hello1"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 2, BlockHash: common.HexToHash("0x1235"), BlockNumber: int64(11), @@ -689,7 +690,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { Data: []byte("hello2"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 3, BlockHash: common.HexToHash("0x1236"), BlockNumber: int64(12), @@ -700,7 +701,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { Data: []byte("hello3"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 4, BlockHash: common.HexToHash("0x1237"), BlockNumber: int64(13), @@ -711,7 +712,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { Data: []byte("hello4"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 5, BlockHash: common.HexToHash("0x1238"), BlockNumber: int64(14), @@ -722,7 +723,7 @@ func TestORM_SelectLogsWithSigsByBlockRangeFilter(t *testing.T) { Data: []byte("hello5"), }, { - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: 6, BlockHash: common.HexToHash("0x1239"), BlockNumber: int64(15), @@ -827,7 +828,7 @@ func BenchmarkLogs(b *testing.B) { addr := common.HexToAddress("0x1234") for i := 0; i < 10_000; i++ { lgs = append(lgs, logpoller.Log{ - EvmChainId: utils.NewBig(th.ChainID), + EvmChainId: ubig.New(th.ChainID), LogIndex: int64(i), BlockHash: common.HexToHash("0x1"), BlockNumber: 1, @@ -866,7 +867,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Insert two logs that mimics an oracle request from 2 different addresses (matching will be on topic index 1) require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 1, BlockHash: common.HexToHash("0x1"), BlockNumber: 1, @@ -878,7 +879,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { Data: []byte("requestID-A1"), }, { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 2, BlockHash: common.HexToHash("0x1"), BlockNumber: 1, @@ -907,7 +908,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Insert a log that mimics response for requestID-A1 require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 3, BlockHash: common.HexToHash("0x2"), BlockNumber: 2, @@ -935,7 +936,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Insert 3 request from addressC (matching will be on topic index 3) require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 5, BlockHash: common.HexToHash("0x2"), BlockNumber: 3, @@ -947,7 +948,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { Data: []byte("requestID-C1"), }, { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 6, BlockHash: common.HexToHash("0x2"), BlockNumber: 3, @@ -958,7 +959,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { TxHash: common.HexToHash("0x0002"), Data: []byte("requestID-C2"), }, { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 7, BlockHash: common.HexToHash("0x2"), BlockNumber: 3, @@ -983,7 +984,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Fulfill requestID-C2 require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 8, BlockHash: common.HexToHash("0x3"), BlockNumber: 3, @@ -1006,7 +1007,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Fulfill requestID-C3 require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 9, BlockHash: common.HexToHash("0x3"), BlockNumber: 3, @@ -1041,7 +1042,7 @@ func TestSelectLogsWithSigsExcluding(t *testing.T) { //Fulfill requestID-C3 require.NoError(t, orm.InsertLogs([]logpoller.Log{ { - EvmChainId: (*utils.Big)(th.ChainID), + EvmChainId: (*ubig.Big)(th.ChainID), LogIndex: 10, BlockHash: common.HexToHash("0x2"), BlockNumber: 10, @@ -1105,7 +1106,7 @@ func TestSelectLatestBlockNumberEventSigsAddrsWithConfs(t *testing.T) { GenLog(th.ChainID, 2, 2, utils.RandomAddress().String(), event2[:], address2), GenLog(th.ChainID, 2, 3, utils.RandomAddress().String(), event2[:], address2), })) - require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 3, time.Now(), 1)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomHash(), 3, time.Now(), 1)) tests := []struct { name string @@ -1204,9 +1205,9 @@ func TestSelectLogsCreatedAfter(t *testing.T) { GenLogWithTimestamp(th.ChainID, 2, 2, utils.RandomAddress().String(), event[:], address, block2ts), GenLogWithTimestamp(th.ChainID, 1, 3, utils.RandomAddress().String(), event[:], address, block3ts), })) - require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 1, block1ts, 0)) - require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 2, block2ts, 1)) - require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 3, block3ts, 2)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomHash(), 1, block1ts, 0)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomHash(), 2, block2ts, 1)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomHash(), 3, block3ts, 2)) type expectedLog struct { block int64 @@ -1308,7 +1309,7 @@ func TestNestedLogPollerBlocksQuery(t *testing.T) { require.Len(t, logs, 0) // Persist block - require.NoError(t, th.ORM.InsertBlock(utils.RandomAddress().Hash(), 10, time.Now(), 0)) + require.NoError(t, th.ORM.InsertBlock(utils.RandomHash(), 10, time.Now(), 0)) // Check if query actually works well with provided dataset logs, err = th.ORM.SelectIndexedLogs(address, event, 1, []common.Hash{event}, logpoller.Unconfirmed) @@ -1533,7 +1534,7 @@ func Benchmark_LogsDataWordBetween(b *testing.B) { data = append(data, logpoller.EvmWord(uint64(numberOfMessagesPerReport*(i+1))).Bytes()...) dbLogs = append(dbLogs, logpoller.Log{ - EvmChainId: utils.NewBig(chainId), + EvmChainId: ubig.New(chainId), LogIndex: int64(i + 1), BlockHash: utils.RandomBytes32(), BlockNumber: int64(i + 1), @@ -1541,12 +1542,12 @@ func Benchmark_LogsDataWordBetween(b *testing.B) { EventSig: commitReportAccepted, Topics: [][]byte{}, Address: commitStoreAddress, - TxHash: utils.RandomAddress().Hash(), + TxHash: utils.RandomHash(), Data: data, CreatedAt: time.Now(), }) } - require.NoError(b, o.InsertBlock(utils.RandomAddress().Hash(), int64(numberOfReports*numberOfMessagesPerReport), time.Now(), int64(numberOfReports*numberOfMessagesPerReport))) + require.NoError(b, o.InsertBlock(utils.RandomHash(), int64(numberOfReports*numberOfMessagesPerReport), time.Now(), int64(numberOfReports*numberOfMessagesPerReport))) require.NoError(b, o.InsertLogs(dbLogs)) b.ResetTimer() diff --git a/core/chains/evm/logpoller/query.go b/core/chains/evm/logpoller/query.go index b7fbfade680..a37b15b2b2d 100644 --- a/core/chains/evm/logpoller/query.go +++ b/core/chains/evm/logpoller/query.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) type bytesProducer interface { @@ -34,7 +34,7 @@ type queryArgs struct { func newQueryArgs(chainId *big.Int) *queryArgs { return &queryArgs{ args: map[string]interface{}{ - "evm_chain_id": utils.NewBig(chainId), + "evm_chain_id": ubig.New(chainId), }, err: []error{}, } diff --git a/core/chains/evm/logpoller/query_test.go b/core/chains/evm/logpoller/query_test.go index e38aeb05819..70ace713228 100644 --- a/core/chains/evm/logpoller/query_test.go +++ b/core/chains/evm/logpoller/query_test.go @@ -8,7 +8,8 @@ import ( "github.com/lib/pq" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) func Test_QueryArgs(t *testing.T) { @@ -22,7 +23,7 @@ func Test_QueryArgs(t *testing.T) { name: "valid arguments", queryArgs: newQueryArgs(big.NewInt(20)).withAddress(utils.ZeroAddress), want: map[string]interface{}{ - "evm_chain_id": utils.NewBigI(20), + "evm_chain_id": ubig.NewI(20), "address": utils.ZeroAddress, }, }, diff --git a/core/chains/evm/mocks/balance_monitor.go b/core/chains/evm/mocks/balance_monitor.go index cdda18b7f03..f03fd8829cc 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -22,6 +22,10 @@ type BalanceMonitor struct { func (_m *BalanceMonitor) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -36,6 +40,10 @@ func (_m *BalanceMonitor) Close() error { func (_m *BalanceMonitor) GetEthBalance(_a0 common.Address) *assets.Eth { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetEthBalance") + } + var r0 *assets.Eth if rf, ok := ret.Get(0).(func(common.Address) *assets.Eth); ok { r0 = rf(_a0) @@ -52,6 +60,10 @@ func (_m *BalanceMonitor) GetEthBalance(_a0 common.Address) *assets.Eth { func (_m *BalanceMonitor) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -68,6 +80,10 @@ func (_m *BalanceMonitor) HealthReport() map[string]error { func (_m *BalanceMonitor) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -87,6 +103,10 @@ func (_m *BalanceMonitor) OnNewLongestChain(ctx context.Context, head *types.Hea func (_m *BalanceMonitor) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -101,6 +121,10 @@ func (_m *BalanceMonitor) Ready() error { func (_m *BalanceMonitor) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/chains/evm/mocks/node.go b/core/chains/evm/mocks/node.go index 69020d411f4..8f27218aec7 100644 --- a/core/chains/evm/mocks/node.go +++ b/core/chains/evm/mocks/node.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -30,6 +30,10 @@ type Node struct { func (_m *Node) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for BalanceAt") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (*big.Int, error)); ok { @@ -56,6 +60,10 @@ func (_m *Node) BalanceAt(ctx context.Context, account common.Address, blockNumb func (_m *Node) 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) @@ -70,6 +78,10 @@ func (_m *Node) BatchCallContext(ctx context.Context, b []rpc.BatchElem) error { func (_m *Node) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { ret := _m.Called(ctx, hash) + if len(ret) == 0 { + panic("no return value specified for BlockByHash") + } + var r0 *types.Block var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Block, error)); ok { @@ -96,6 +108,10 @@ func (_m *Node) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block func (_m *Node) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { ret := _m.Called(ctx, number) + if len(ret) == 0 { + panic("no return value specified for BlockByNumber") + } + var r0 *types.Block var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Block, error)); ok { @@ -122,6 +138,10 @@ func (_m *Node) BlockByNumber(ctx context.Context, number *big.Int) (*types.Bloc func (_m *Node) BlockNumber(ctx context.Context) (uint64, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for BlockNumber") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context) (uint64, error)); ok { @@ -149,6 +169,10 @@ func (_m *Node) CallContext(ctx context.Context, result interface{}, method stri _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...) @@ -163,6 +187,10 @@ func (_m *Node) CallContext(ctx context.Context, result interface{}, method stri func (_m *Node) 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 { @@ -189,6 +217,10 @@ func (_m *Node) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNum func (_m *Node) ChainID() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -205,6 +237,10 @@ func (_m *Node) ChainID() *big.Int { func (_m *Node) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -219,6 +255,10 @@ func (_m *Node) Close() error { func (_m *Node) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for CodeAt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) ([]byte, error)); ok { @@ -245,6 +285,10 @@ func (_m *Node) CodeAt(ctx context.Context, account common.Address, blockNumber func (_m *Node) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { ret := _m.Called(ctx, call) + if len(ret) == 0 { + panic("no return value specified for EstimateGas") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.CallMsg) (uint64, error)); ok { @@ -272,6 +316,10 @@ func (_m *Node) EthSubscribe(ctx context.Context, channel chan<- *evmtypes.Head, _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for EthSubscribe") + } + var r0 ethereum.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, chan<- *evmtypes.Head, ...interface{}) (ethereum.Subscription, error)); ok { @@ -298,6 +346,10 @@ func (_m *Node) EthSubscribe(ctx context.Context, channel chan<- *evmtypes.Head, func (_m *Node) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { ret := _m.Called(ctx, q) + if len(ret) == 0 { + panic("no return value specified for FilterLogs") + } + var r0 []types.Log var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery) ([]types.Log, error)); ok { @@ -324,6 +376,10 @@ func (_m *Node) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types func (_m *Node) HeaderByHash(_a0 context.Context, _a1 common.Hash) (*types.Header, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for HeaderByHash") + } + var r0 *types.Header var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Header, error)); ok { @@ -350,6 +406,10 @@ func (_m *Node) HeaderByHash(_a0 context.Context, _a1 common.Hash) (*types.Heade func (_m *Node) HeaderByNumber(_a0 context.Context, _a1 *big.Int) (*types.Header, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for HeaderByNumber") + } + var r0 *types.Header var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (*types.Header, error)); ok { @@ -376,6 +436,10 @@ func (_m *Node) HeaderByNumber(_a0 context.Context, _a1 *big.Int) (*types.Header func (_m *Node) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -390,6 +454,10 @@ func (_m *Node) Name() string { func (_m *Node) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { ret := _m.Called(ctx, account, blockNumber) + if len(ret) == 0 { + panic("no return value specified for NonceAt") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (uint64, error)); ok { @@ -414,6 +482,10 @@ func (_m *Node) NonceAt(ctx context.Context, account common.Address, blockNumber func (_m *Node) Order() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Order") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() @@ -428,6 +500,10 @@ func (_m *Node) Order() int32 { func (_m *Node) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { ret := _m.Called(ctx, account) + if len(ret) == 0 { + panic("no return value specified for PendingCodeAt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) ([]byte, error)); ok { @@ -454,6 +530,10 @@ func (_m *Node) PendingCodeAt(ctx context.Context, account common.Address) ([]by func (_m *Node) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { ret := _m.Called(ctx, account) + if len(ret) == 0 { + panic("no return value specified for PendingNonceAt") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) (uint64, error)); ok { @@ -478,6 +558,10 @@ func (_m *Node) PendingNonceAt(ctx context.Context, account common.Address) (uin func (_m *Node) SendTransaction(ctx context.Context, tx *types.Transaction) error { ret := _m.Called(ctx, tx) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction) error); ok { r0 = rf(ctx, tx) @@ -492,6 +576,10 @@ func (_m *Node) SendTransaction(ctx context.Context, tx *types.Transaction) erro func (_m *Node) Start(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -506,6 +594,10 @@ func (_m *Node) Start(ctx context.Context) error { func (_m *Node) State() client.NodeState { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for State") + } + var r0 client.NodeState if rf, ok := ret.Get(0).(func() client.NodeState); ok { r0 = rf() @@ -520,6 +612,10 @@ func (_m *Node) State() client.NodeState { func (_m *Node) StateAndLatest() (client.NodeState, int64, *big.Int) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StateAndLatest") + } + var r0 client.NodeState var r1 int64 var r2 *big.Int @@ -553,6 +649,10 @@ func (_m *Node) StateAndLatest() (client.NodeState, int64, *big.Int) { func (_m *Node) String() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -567,6 +667,10 @@ func (_m *Node) String() string { func (_m *Node) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { ret := _m.Called(ctx, q, ch) + if len(ret) == 0 { + panic("no return value specified for SubscribeFilterLogs") + } + var r0 ethereum.Subscription var r1 error if rf, ok := ret.Get(0).(func(context.Context, ethereum.FilterQuery, chan<- types.Log) (ethereum.Subscription, error)); ok { @@ -593,6 +697,10 @@ func (_m *Node) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, func (_m *Node) SubscribersCount() int32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribersCount") + } + var r0 int32 if rf, ok := ret.Get(0).(func() int32); ok { r0 = rf() @@ -607,6 +715,10 @@ func (_m *Node) SubscribersCount() int32 { func (_m *Node) SuggestGasPrice(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for SuggestGasPrice") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -633,6 +745,10 @@ func (_m *Node) SuggestGasPrice(ctx context.Context) (*big.Int, error) { func (_m *Node) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for SuggestGasTipCap") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { @@ -659,6 +775,10 @@ func (_m *Node) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { func (_m *Node) TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionByHash") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Transaction, error)); ok { @@ -685,6 +805,10 @@ func (_m *Node) TransactionByHash(ctx context.Context, txHash common.Hash) (*typ func (_m *Node) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { ret := _m.Called(ctx, txHash) + if len(ret) == 0 { + panic("no return value specified for TransactionReceipt") + } + var r0 *types.Receipt var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Hash) (*types.Receipt, error)); ok { diff --git a/core/chains/evm/mocks/send_only_node.go b/core/chains/evm/mocks/send_only_node.go index c836399a8ba..8ec3270281d 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ type SendOnlyNode struct { func (_m *SendOnlyNode) 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) @@ -38,6 +42,10 @@ func (_m *SendOnlyNode) BatchCallContext(ctx context.Context, b []rpc.BatchElem) func (_m *SendOnlyNode) ChainID() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -54,6 +62,10 @@ func (_m *SendOnlyNode) ChainID() *big.Int { func (_m *SendOnlyNode) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -68,6 +80,10 @@ func (_m *SendOnlyNode) Close() error { func (_m *SendOnlyNode) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -82,6 +98,10 @@ func (_m *SendOnlyNode) Name() string { func (_m *SendOnlyNode) SendTransaction(ctx context.Context, tx *types.Transaction) error { ret := _m.Called(ctx, tx) + if len(ret) == 0 { + panic("no return value specified for SendTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Transaction) error); ok { r0 = rf(ctx, tx) @@ -96,6 +116,10 @@ func (_m *SendOnlyNode) SendTransaction(ctx context.Context, tx *types.Transacti func (_m *SendOnlyNode) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -110,6 +134,10 @@ func (_m *SendOnlyNode) Start(_a0 context.Context) error { func (_m *SendOnlyNode) State() client.NodeState { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for State") + } + var r0 client.NodeState if rf, ok := ret.Get(0).(func() client.NodeState); ok { r0 = rf() @@ -124,6 +152,10 @@ func (_m *SendOnlyNode) State() client.NodeState { func (_m *SendOnlyNode) String() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for String") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() diff --git a/core/chains/evm/monitor/balance.go b/core/chains/evm/monitor/balance.go index c3b9a49c7af..b0f0fbc9c91 100644 --- a/core/chains/evm/monitor/balance.go +++ b/core/chains/evm/monitor/balance.go @@ -15,13 +15,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name BalanceMonitor --output ../mocks/ --case=underscore @@ -42,7 +42,7 @@ type ( ethKeyStore keystore.Eth ethBalances map[gethCommon.Address]*assets.Eth ethBalancesMtx *sync.RWMutex - sleeperTask utils.SleeperTask + sleeperTask *utils.SleeperTask } NullBalanceMonitor struct{} diff --git a/core/chains/evm/monitor/balance_helpers_test.go b/core/chains/evm/monitor/balance_helpers_test.go index 624aa69f061..ed949882295 100644 --- a/core/chains/evm/monitor/balance_helpers_test.go +++ b/core/chains/evm/monitor/balance_helpers_test.go @@ -1,7 +1,5 @@ package monitor func (bm *balanceMonitor) WorkDone() <-chan struct{} { - return bm.sleeperTask.(interface { - WorkDone() <-chan struct{} - }).WorkDone() + return bm.sleeperTask.WorkDone() } diff --git a/core/chains/evm/monitor/balance_test.go b/core/chains/evm/monitor/balance_test.go index c2c976e78da..246d5d0759f 100644 --- a/core/chains/evm/monitor/balance_test.go +++ b/core/chains/evm/monitor/balance_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/monitor" @@ -44,7 +45,6 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) - defer func() { assert.NoError(t, bm.Close()) }() k0bal := big.NewInt(42) k1bal := big.NewInt(43) @@ -54,7 +54,7 @@ func TestBalanceMonitor_Start(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Return(k0bal, nil) ethClient.On("BalanceAt", mock.Anything, k1Addr, nilBigInt).Once().Return(k1bal, nil) - assert.NoError(t, bm.Start(testutils.Context(t))) + servicetest.RunHealthy(t, bm) gomega.NewWithT(t).Eventually(func() *big.Int { return bm.GetEthBalance(k0Addr).ToInt() @@ -72,12 +72,11 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) - defer func() { assert.NoError(t, bm.Close()) }() k0bal := big.NewInt(42) ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Return(k0bal, nil) - assert.NoError(t, bm.Start(testutils.Context(t))) + servicetest.RunHealthy(t, bm) gomega.NewWithT(t).Eventually(func() *big.Int { return bm.GetEthBalance(k0Addr).ToInt() @@ -92,7 +91,6 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) - defer func() { assert.NoError(t, bm.Close()) }() ctxCancelledAwaiter := cltest.NewAwaiter() ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Run(func(args mock.Arguments) { @@ -122,13 +120,12 @@ func TestBalanceMonitor_Start(t *testing.T) { _, k0Addr := cltest.MustInsertRandomKey(t, ethKeyStore) bm := monitor.NewBalanceMonitor(ethClient, ethKeyStore, logger.Test(t)) - defer func() { assert.NoError(t, bm.Close()) }() ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt). Once(). Return(nil, errors.New("a little easter egg for the 4chan link marines error")) - assert.NoError(t, bm.Start(testutils.Context(t))) + servicetest.RunHealthy(t, bm) gomega.NewWithT(t).Consistently(func() *big.Int { return bm.GetEthBalance(k0Addr).ToInt() @@ -160,8 +157,7 @@ func TestBalanceMonitor_OnNewLongestChain_UpdatesBalance(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Return(k0bal, nil) ethClient.On("BalanceAt", mock.Anything, k1Addr, nilBigInt).Once().Return(k1bal, nil) - require.NoError(t, bm.Start(testutils.Context(t))) - defer func() { assert.NoError(t, bm.Close()) }() + servicetest.RunHealthy(t, bm) ethClient.On("BalanceAt", mock.Anything, k0Addr, nilBigInt).Once().Return(k0bal, nil) ethClient.On("BalanceAt", mock.Anything, k1Addr, nilBigInt).Once().Return(k1bal, nil) @@ -205,7 +201,7 @@ func TestBalanceMonitor_FewerRPCCallsWhenBehind(t *testing.T) { ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything). Once(). Return(big.NewInt(1), nil) - require.NoError(t, bm.Start(testutils.Context(t))) + servicetest.RunHealthy(t, bm) head := cltest.Head(0) @@ -234,8 +230,6 @@ func TestBalanceMonitor_FewerRPCCallsWhenBehind(t *testing.T) { mockUnblocker <- time.Time{} }) - bm.Close() - // Make sure the BalanceAt mock wasn't called more than once assert.LessOrEqual(t, callCount.Load(), int32(1)) } diff --git a/core/chains/evm/txmgr/attempts.go b/core/chains/evm/txmgr/attempts.go index 37626f4550e..91645bae6f6 100644 --- a/core/chains/evm/txmgr/attempts.go +++ b/core/chains/evm/txmgr/attempts.go @@ -3,6 +3,7 @@ package txmgr import ( "bytes" "context" + "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -119,9 +120,17 @@ func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(nonce evmtypes.Nonce, feeLimit u return attempt, errors.New("NewEmptyTranscation: legacy fee cannot be nil") } - tx := types.NewTransaction(uint64(nonce), fromAddress, value, uint64(feeLimit), fee.Legacy.ToInt(), payload) + tx := newLegacyTransaction( + uint64(nonce), + fromAddress, + value, + feeLimit, + fee.Legacy, + payload, + ) - hash, signedTxBytes, err := c.SignTx(fromAddress, tx) + transaction := types.NewTx(&tx) + hash, signedTxBytes, err := c.SignTx(fromAddress, transaction) if err != nil { return attempt, errors.Wrapf(err, "error using account %s to sign empty transaction", fromAddress.String()) } @@ -295,7 +304,7 @@ func newLegacyTransaction(nonce uint64, to common.Address, value *big.Int, gasLi func (c *evmTxAttemptBuilder) SignTx(address common.Address, tx *types.Transaction) (common.Hash, []byte, error) { signedTx, err := c.keystore.SignTx(address, tx, &c.chainID) if err != nil { - return common.Hash{}, nil, errors.Wrap(err, "SignTx failed") + return common.Hash{}, nil, fmt.Errorf("failed to sign tx: %w", err) } rlp := new(bytes.Buffer) if err := signedTx.EncodeRLP(rlp); err != nil { diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index 131115e6fae..c7373e2c4f6 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -6,6 +6,7 @@ import ( "testing" gethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" @@ -85,6 +86,44 @@ func TestTxm_SignTx(t *testing.T) { require.NotNil(t, rawBytes) require.Equal(t, "0xdd68f554373fdea7ec6713a6e437e7646465d553a6aa0b43233093366cc87ef0", hash.String()) }) + t.Run("can properly encoded and decode raw transaction for LegacyTx", func(t *testing.T) { + chainID := big.NewInt(1) + kst := ksmocks.NewEth(t) + kst.On("SignTx", to, tx, chainID).Return(tx, nil).Once() + cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) + + _, rawBytes, err := cks.SignTx(addr, tx) + require.NoError(t, err) + require.NotNil(t, rawBytes) + require.Equal(t, "0xe42a82015681f294b921f7763960b296b9cbad586ff066a18d749724818e83010203808080", hexutil.Encode(rawBytes)) + + var decodedTx *gethtypes.Transaction + decodedTx, err = txmgr.GetGethSignedTx(rawBytes) + require.NoError(t, err) + require.Equal(t, tx.Hash(), decodedTx.Hash()) + }) + t.Run("can properly encoded and decode raw transaction for DynamicFeeTx", func(t *testing.T) { + chainID := big.NewInt(1) + kst := ksmocks.NewEth(t) + typedTx := gethtypes.NewTx(&gethtypes.DynamicFeeTx{ + Nonce: 42, + To: &to, + Value: big.NewInt(142), + Gas: 242, + Data: []byte{1, 2, 3}, + }) + kst.On("SignTx", to, typedTx, chainID).Return(typedTx, nil).Once() + cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) + _, rawBytes, err := cks.SignTx(addr, typedTx) + require.NoError(t, err) + require.NotNil(t, rawBytes) + require.Equal(t, "0xa702e5802a808081f294b921f7763960b296b9cbad586ff066a18d749724818e83010203c0808080", hexutil.Encode(rawBytes)) + + var decodedTx *gethtypes.Transaction + decodedTx, err = txmgr.GetGethSignedTx(rawBytes) + require.NoError(t, err) + require.Equal(t, typedTx.Hash(), decodedTx.Hash()) + }) } func TestTxm_NewDynamicFeeTx(t *testing.T) { @@ -125,13 +164,13 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { {"gas tip < fee cap", assets.GWei(4), assets.GWei(5), nil, ""}, {"gas tip > fee cap", assets.GWei(6), assets.GWei(5), nil, "gas fee cap must be greater than or equal to gas tip cap (fee cap: 5 gwei, tip cap: 6 gwei)"}, {"fee cap exceeds max allowed", assets.GWei(5), assets.GWei(5), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.GWei(4)) + c.EVM[0].GasEstimator.PriceMax = assets.GWei(4) }, "specified gas fee cap of 5 gwei would exceed max configured gas price of 4 gwei"}, {"ignores global min gas price", assets.GWei(5), assets.GWei(5), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMin = (*assets.Wei)(assets.GWei(6)) + c.EVM[0].GasEstimator.PriceMin = assets.GWei(6) }, ""}, {"tip cap below min allowed", assets.GWei(5), assets.GWei(5), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.TipCapMin = (*assets.Wei)(assets.GWei(6)) + c.EVM[0].GasEstimator.TipCapMin = assets.GWei(6) }, "specified gas tip cap of 5 gwei is below min configured gas tip of 6 gwei"}, } diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index c6e05b0954b..67e9b0d8f04 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -23,7 +23,9 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" @@ -36,6 +38,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" 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" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -45,7 +49,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // NewEthBroadcaster creates a new txmgr.EthBroadcaster for use in testing. @@ -59,19 +62,19 @@ func NewTestEthBroadcaster( nonceAutoSync bool, ) *txmgr.Broadcaster { t.Helper() - ctx := testutils.Context(t) lggr := logger.Test(t) ge := config.EVM().GasEstimator() - estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) + estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { + return gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr) + }, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient) ethBroadcaster := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, txBuilder, txNonceSyncer, lggr, checkerFactory, nonceAutoSync) // Mark instance as test ethBroadcaster.XXXTestDisableUnstartedTxAutoProcessing() - require.NoError(t, ethBroadcaster.Start(ctx)) - t.Cleanup(func() { assert.NoError(t, ethBroadcaster.Close()) }) + servicetest.Run(t, ethBroadcaster) return ethBroadcaster } @@ -634,8 +637,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi eb.XXXTestDisableUnstartedTxAutoProcessing() // Start instance of broadcaster - require.NoError(t, eb.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, eb.Close()) }) + servicetest.Run(t, eb) mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID) @@ -648,7 +650,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi } // Simulate a "PruneQueue" call - assert.NoError(t, utils.JustError(db.Exec(`DELETE FROM evm.txes WHERE state = 'unstarted'`))) + assert.NoError(t, commonutils.JustError(db.Exec(`DELETE FROM evm.txes WHERE state = 'unstarted'`))) close(chBlock) }() @@ -1008,7 +1010,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg, &testCheckerFactory{}, false) ctx := testutils.Context(t) - require.NoError(t, utils.JustError(db.Exec(`SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`))) + require.NoError(t, commonutils.JustError(db.Exec(`SET CONSTRAINTS pipeline_runs_pipeline_spec_id_fkey DEFERRED`))) t.Run("if external wallet sent a transaction from the account and now the nonce is one higher than it should be and we got replacement underpriced then we assume a previous transaction of ours was the one that succeeded, and hand off to EthConfirmer", func(t *testing.T) { mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1135,10 +1137,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) { lggr := logger.Test(t) - estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) + 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) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) localNextNonce = getLocalNextNonce(t, eb, fromAddress) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() eb2 := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, txBuilder, nil, lggr, &testCheckerFactory{}, false) retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) @@ -1189,7 +1193,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { require.Equal(t, int64(localNextNonce), int64(nonce)) // On the second try, the tx has been accepted into the mempool - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce+1, nil).Once() retryable, err = eb.ProcessUnstartedTxs(ctx, fromAddress) assert.NoError(t, err) @@ -1213,10 +1217,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == uint64(localNextNonce) + return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() // Nonce is the same as localNextNonce, implying that this sent transaction has not been accepted - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) @@ -1265,7 +1269,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { localNextNonce := getLocalNextNonce(t, eb, fromAddress) etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { - return tx.Nonce() == uint64(localNextNonce) + return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("pending nonce fetch failed")).Once() @@ -1320,7 +1324,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce }), fromAddress).Return(commonclient.Unknown, errors.New(retryableErrorExample)).Once() // Nonce is one higher than localNextNonce, implying that despite the error, this sent transaction has been accepted into the mempool - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce+1), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce+1, nil).Once() // Do the thing retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) @@ -1462,7 +1466,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpMin = assets.NewWeiI(0) c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) @@ -1554,7 +1558,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { c.EVM[0].GasEstimator.BumpPercent = ptr[uint16](0) })) localNextNonce := getLocalNextNonce(t, eb, fromAddress) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(localNextNonce), nil).Once() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, evmcfg2, &testCheckerFactory{}, false) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, &cltest.FixtureChainID) underpricedError := "transaction underpriced" @@ -1760,7 +1764,9 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { ethNodeNonce := uint64(22) - estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), nil) + 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) checkerFactory := &testCheckerFactory{} ge := evmcfg.EVM().GasEstimator() @@ -1793,9 +1799,8 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), nil).Once() eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, txBuilder, txNonceSyncer, lggr, checkerFactory, true) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(ethNodeNonce), nil).Once() - require.NoError(t, eb.Start(ctx)) - defer func() { assert.NoError(t, eb.Close()) }() + ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(ethNodeNonce, nil).Once() + servicetest.Run(t, eb) testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") @@ -1828,8 +1833,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(uint64(0), errors.New("something exploded")).Once() ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(ethNodeNonce, nil) - require.NoError(t, eb.Start(ctx)) - defer func() { assert.NoError(t, eb.Close()) }() + servicetest.Run(t, eb) testutils.WaitForLogMessage(t, observed, "Fast-forward sequence") @@ -1901,7 +1905,7 @@ func Test_NextNonce(t *testing.T) { ethClient.On("PendingNonceAt", mock.Anything, addr1).Return(uint64(randNonce), nil).Once() eb := NewTestEthBroadcaster(t, txStore, ethClient, ks, evmcfg, checkerFactory, false) ctx := testutils.Context(t) - cltest.MustInsertRandomKey(t, ks, *utils.NewBig(testutils.FixtureChainID)) + cltest.MustInsertRandomKey(t, ks, *ubig.New(testutils.FixtureChainID)) nonce, err := eb.GetNextSequence(ctx, addr1) require.NoError(t, err) @@ -2030,7 +2034,7 @@ type testChecker struct { func (t *testChecker) Check( _ context.Context, - _ logger.Logger, + _ logger.SugaredLogger, _ txmgr.Tx, _ txmgr.TxAttempt, ) error { diff --git a/core/chains/evm/txmgr/client.go b/core/chains/evm/txmgr/client.go index d08274f74b6..0aa03536276 100644 --- a/core/chains/evm/txmgr/client.go +++ b/core/chains/evm/txmgr/client.go @@ -14,11 +14,12 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + commonclient "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ TxmClient = (*evmTxmClient)(nil) @@ -43,7 +44,7 @@ func (c *evmTxmClient) BatchSendTransactions( ctx context.Context, attempts []TxAttempt, batchSize int, - lggr logger.Logger, + lggr logger.SugaredLogger, ) ( codes []commonclient.SendTxReturnCode, txErrs []error, @@ -62,7 +63,7 @@ func (c *evmTxmClient) BatchSendTransactions( if len(reqs) != len(attempts) { lenErr := fmt.Errorf("Returned request data length (%d) != number of tx attempts (%d)", len(reqs), len(attempts)) err = errors.Join(err, lenErr) - logger.Criticalw(lggr, "Mismatched length", "err", err) + lggr.Criticalw("Mismatched length", "err", err) return } @@ -77,10 +78,14 @@ func (c *evmTxmClient) BatchSendTransactions( // convert to tx for logging purposes - exits early if error occurs tx, signedErr := GetGethSignedTx(attempts[i].SignedRawTx) if signedErr != nil { - processingErr[i] = fmt.Errorf("failed to process tx (index %d): %w", i, signedErr) + signedErrMsg := fmt.Sprintf("failed to process tx (index %d)", i) + lggr.Errorw(signedErrMsg, "err", signedErr) + processingErr[i] = fmt.Errorf("%s: %w", signedErrMsg, signedErr) return } - codes[i], txErrs[i] = client.ClassifySendError(reqs[i].Error, lggr, tx, attempts[i].Tx.FromAddress, c.client.IsL2()) + sendErr := reqs[i].Error + codes[i] = client.ClassifySendError(sendErr, lggr, tx, attempts[i].Tx.FromAddress, c.client.IsL2()) + txErrs[i] = sendErr }(index) } wg.Wait() @@ -88,10 +93,10 @@ func (c *evmTxmClient) BatchSendTransactions( return } -func (c *evmTxmClient) SendTransactionReturnCode(ctx context.Context, etx Tx, attempt TxAttempt, lggr logger.Logger) (commonclient.SendTxReturnCode, error) { +func (c *evmTxmClient) SendTransactionReturnCode(ctx context.Context, etx Tx, attempt TxAttempt, lggr logger.SugaredLogger) (commonclient.SendTxReturnCode, error) { signedTx, err := GetGethSignedTx(attempt.SignedRawTx) if err != nil { - logger.Criticalw(lggr, "Fatal error signing transaction", "err", err, "etx", etx) + lggr.Criticalw("Fatal error signing transaction", "err", err, "etx", etx) return commonclient.Fatal, err } return c.client.SendTransactionReturnCode(ctx, signedTx, etx.FromAddress) diff --git a/core/chains/evm/txmgr/common.go b/core/chains/evm/txmgr/common.go index 1956476f8dd..d1e851f0c21 100644 --- a/core/chains/evm/txmgr/common.go +++ b/core/chains/evm/txmgr/common.go @@ -35,12 +35,25 @@ func batchSendTransactions( reqs := make([]rpc.BatchElem, len(attempts)) ethTxIDs := make([]int64, len(attempts)) hashes := make([]string, len(attempts)) + now := time.Now() + successfulBroadcast := []int64{} for i, attempt := range attempts { ethTxIDs[i] = attempt.TxID hashes[i] = attempt.Hash.String() + // Decode the signed raw tx back into a Transaction object + signedTx, decodeErr := GetGethSignedTx(attempt.SignedRawTx) + if decodeErr != nil { + return reqs, now, successfulBroadcast, fmt.Errorf("failed to decode signed raw tx into Transaction object: %w", decodeErr) + } + // Get the canonical encoding of the Transaction object needed for the eth_sendRawTransaction request + // The signed raw tx cannot be used directly because it uses a different encoding + txBytes, marshalErr := signedTx.MarshalBinary() + if marshalErr != nil { + return reqs, now, successfulBroadcast, fmt.Errorf("failed to marshal tx into canonical encoding: %w", marshalErr) + } req := rpc.BatchElem{ Method: "eth_sendRawTransaction", - Args: []interface{}{hexutil.Encode(attempt.SignedRawTx)}, + Args: []interface{}{hexutil.Encode(txBytes)}, Result: &common.Hash{}, } reqs[i] = req @@ -48,12 +61,10 @@ func batchSendTransactions( logger.Debugw(fmt.Sprintf("Batch sending %d unconfirmed transactions.", len(attempts)), "n", len(attempts), "ethTxIDs", ethTxIDs, "hashes", hashes) - now := time.Now() if batchSize == 0 { batchSize = len(reqs) } - successfulBroadcast := []int64{} for i := 0; i < len(reqs); i += batchSize { j := i + batchSize if j > len(reqs) { diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 84c42cd00f1..9f267a8ea67 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -21,6 +21,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commonfee "github.com/smartcontractkit/chainlink/v2/common/fee" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" @@ -32,6 +33,7 @@ import ( gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "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" @@ -40,7 +42,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func newTestChainScopedConfig(t *testing.T) evmconfig.ChainScopedConfig { @@ -121,9 +122,10 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { cltest.MustInsertRandomKey(t, ethKeyStore) cltest.MustInsertRandomKey(t, ethKeyStore) estimator := gasmocks.NewEvmEstimator(t) + newEst := func(logger.Logger) gas.EvmEstimator { return estimator } lggr := logger.Test(t) ge := config.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(estimator, ge.EIP1559DynamicFees(), nil) + feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator) ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ethKeyStore, txBuilder, lggr) ctx := testutils.Context(t) @@ -1638,15 +1640,16 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing kst := ksmocks.NewEth(t) estimator := gasmocks.NewEvmEstimator(t) + newEst := func(logger.Logger) gas.EvmEstimator { return estimator } estimator.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, uint32(0), pkgerrors.Wrapf(commonfee.ErrConnectivity, "transaction...")) ge := ccfg.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(estimator, ge.EIP1559DynamicFees(), nil) + feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Create confirmer with necessary state ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), ccfg.EVM(), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr) - require.NoError(t, ec.Start(testutils.Context(t))) + servicetest.Run(t, ec) currentHead := int64(30) oldEnough := int64(15) nonce := int64(0) @@ -1684,14 +1687,15 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing estimator := gasmocks.NewEvmEstimator(t) estimator.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.DynamicFee{}, uint32(0), pkgerrors.Wrapf(commonfee.ErrConnectivity, "transaction...")) + newEst := func(logger.Logger) gas.EvmEstimator { return estimator } // Create confirmer with necessary state ge := ccfg.EVM().GasEstimator() - feeEstimator := gas.NewWrappedEvmEstimator(estimator, ge.EIP1559DynamicFees(), nil) + feeEstimator := gas.NewWrappedEvmEstimator(lggr, newEst, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), ccfg.EVM(), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr) - require.NoError(t, ec.Start(testutils.Context(t))) + servicetest.Run(t, ec) currentHead := int64(30) oldEnough := int64(15) nonce := int64(0) @@ -1720,7 +1724,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.GWei(500)) + c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) }) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) @@ -2369,7 +2373,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.GWei(500)) + c.EVM[0].GasEstimator.PriceMax = assets.GWei(500) }) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) @@ -2980,13 +2984,19 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + done := make(chan struct{}) + t.Cleanup(func() { <-done }) go func() { + defer close(done) err2 := ec.ResumePendingTaskRuns(testutils.Context(t), &head) - require.NoError(t, err2) + if !assert.NoError(t, err2) { + return + } // Retrieve Tx to check if callback completed flag was set to true updateTx, err3 := txStore.FindTxWithSequence(testutils.Context(t), fromAddress, nonce) - require.NoError(t, err3) - require.Equal(t, true, updateTx.CallbackCompleted) + if assert.NoError(t, err3) { + assert.Equal(t, true, updateTx.CallbackCompleted) + } }() select { @@ -3005,12 +3015,14 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `DELETE FROM pipeline_runs`) t.Run("processes eth_txes with receipt older than minConfirmations that reverted", func(t *testing.T) { - ch := make(chan interface{}) + type data struct { + value any + error + } + ch := make(chan data) nonce := evmtypes.Nonce(4) - var err error - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, thisErr error) error { - err = thisErr - ch <- value + ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, func(id uuid.UUID, value interface{}, err error) error { + ch <- data{value, err} return nil }) @@ -3026,22 +3038,28 @@ func TestEthConfirmer_ResumePendingRuns(t *testing.T) { pgtest.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, min_confirmations = $2, signal_callback = TRUE WHERE id = $3`, &tr.ID, minConfirmations, etx.ID) + done := make(chan struct{}) + t.Cleanup(func() { <-done }) go func() { + defer close(done) err2 := ec.ResumePendingTaskRuns(testutils.Context(t), &head) - require.NoError(t, err2) + if !assert.NoError(t, err2) { + return + } // Retrieve Tx to check if callback completed flag was set to true updateTx, err3 := txStore.FindTxWithSequence(testutils.Context(t), fromAddress, nonce) - require.NoError(t, err3) - require.Equal(t, true, updateTx.CallbackCompleted) + if assert.NoError(t, err3) { + assert.Equal(t, true, updateTx.CallbackCompleted) + } }() select { case data := <-ch: - assert.Error(t, err) + assert.Error(t, data.error) - assert.EqualError(t, err, fmt.Sprintf("transaction %s reverted on-chain", etx.TxAttempts[0].Hash.String())) + assert.EqualError(t, data.error, fmt.Sprintf("transaction %s reverted on-chain", etx.TxAttempts[0].Hash.String())) - assert.Nil(t, data) + assert.Nil(t, data.value) case <-testutils.AfterWaitTimeout(t): t.Fatal("no value received") @@ -3076,10 +3094,12 @@ 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 { lggr := logger.Test(t) ge := config.EVM().GasEstimator() - estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr), ge.EIP1559DynamicFees(), nil) + estimator := gas.NewWrappedEvmEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { + return gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr) + }, ge.EIP1559DynamicFees(), nil) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ks, txBuilder, lggr) ec.SetResumeCallback(fn) - require.NoError(t, ec.Start(testutils.Context(t))) + 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 730809e8dda..add4d915809 100644 --- a/core/chains/evm/txmgr/evm_tx_store.go +++ b/core/chains/evm/txmgr/evm_tx_store.go @@ -20,15 +20,16 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + "github.com/smartcontractkit/chainlink-common/pkg/utils/null" + "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "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/label" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/null" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -70,11 +71,16 @@ type TestEvmTxStore interface { InsertTxAttempt(attempt *TxAttempt) error LoadTxesAttempts(etxs []*Tx, qopts ...pg.QOpt) error GetFatalTransactions(ctx context.Context) (txes []*Tx, err error) + GetAllTxes(ctx context.Context) (txes []*Tx, err error) + GetAllTxAttempts(ctx context.Context) (attempts []TxAttempt, err error) + CountTxesByStateAndSubject(ctx context.Context, state txmgrtypes.TxState, subject uuid.UUID) (count int, err error) + FindTxesByFromAddressAndState(ctx context.Context, fromAddress common.Address, state string) (txes []*Tx, err error) + UpdateTxAttemptBroadcastBeforeBlockNum(ctx context.Context, id int64, blockNum uint) error } type evmTxStore struct { q pg.Q - logger logger.Logger + logger logger.SugaredLogger ctx context.Context ctxCancel context.CancelFunc } @@ -144,7 +150,7 @@ func fromDBReceiptsPlus(rs []dbReceiptPlus) []ReceiptPlus { func toOnchainReceipt(rs []*evmtypes.Receipt) []rawOnchainReceipt { receipts := make([]rawOnchainReceipt, len(rs)) for i := 0; i < len(rs); i++ { - receipts[i] = rawOnchainReceipt(*rs[i]) + receipts[i] = *rs[i] } return receipts } @@ -176,7 +182,7 @@ type DbEthTx struct { Subject uuid.NullUUID PipelineTaskRunID uuid.NullUUID MinConfirmations null.Uint32 - EVMChainID utils.Big + EVMChainID ubig.Big // TransmitChecker defines the check that should be performed before a transaction is submitted on // chain. TransmitChecker *sqlutil.JSON @@ -209,7 +215,7 @@ func (db *DbEthTx) FromTx(tx *Tx) { db.CallbackCompleted = tx.CallbackCompleted if tx.ChainID != nil { - db.EVMChainID = *utils.NewBig(tx.ChainID) + db.EVMChainID = *ubig.New(tx.ChainID) } if tx.Sequence != nil { n := tx.Sequence.Int64() @@ -339,7 +345,7 @@ func NewTxStore( q := pg.NewQ(db, namedLogger, cfg, pg.WithParentCtx(ctx)) return &evmTxStore{ q: q, - logger: namedLogger, + logger: logger.Sugared(namedLogger), ctx: ctx, ctxCancel: cancel, } @@ -1498,7 +1504,7 @@ GROUP BY e.id txHashesHex[i] = common.BytesToAddress(r.TxHashes[i]) } - logger.Criticalw(o.logger, fmt.Sprintf("eth_tx with ID %v expired without ever getting a receipt for any of our attempts. "+ + o.logger.Criticalw(fmt.Sprintf("eth_tx with ID %v expired without ever getting a receipt for any of our attempts. "+ "Current block height is %v, transaction was broadcast before block height %v. This transaction may not have not been sent and will be marked as fatally errored. "+ "This can happen if there is another instance of chainlink running that is using the same private key, or if "+ "an external wallet has been used to send a transaction from account %s with nonce %v."+ @@ -1555,8 +1561,8 @@ func (o *evmTxStore) UpdateTxFatalError(ctx context.Context, etx *Tx) error { ctx, cancel = o.mergeContexts(ctx) defer cancel() qq := o.q.WithOpts(pg.WithParentCtx(ctx)) - if etx.State != txmgr.TxInProgress { - return pkgerrors.Errorf("can only transition to fatal_error from in_progress, transaction is currently %s", etx.State) + if etx.State != txmgr.TxInProgress && etx.State != txmgr.TxUnstarted { + return pkgerrors.Errorf("can only transition to fatal_error from in_progress or unstarted, transaction is currently %s", etx.State) } if !etx.Error.Valid { return errors.New("expected error field to be set") @@ -2010,6 +2016,66 @@ func (o *evmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.Co return txes, pkgerrors.Wrap(err, "FindTxesWithAttemptsAndReceiptsByIdsAndState failed") } +// For testing only, get all txes in the DB +func (o *evmTxStore) GetAllTxes(ctx context.Context) (txes []*Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + var dbEtxs []DbEthTx + sql := "SELECT * FROM evm.txes" + err = qq.Select(&dbEtxs, sql) + txes = make([]*Tx, len(dbEtxs)) + dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) + return txes, err +} + +// For testing only, get all tx attempts in the DB +func (o *evmTxStore) GetAllTxAttempts(ctx context.Context) (attempts []TxAttempt, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + var dbAttempts []DbEthTxAttempt + sql := "SELECT * FROM evm.tx_attempts" + err = qq.Select(&dbAttempts, sql) + attempts = dbEthTxAttemptsToEthTxAttempts(dbAttempts) + return attempts, err +} + +func (o *evmTxStore) CountTxesByStateAndSubject(ctx context.Context, state txmgrtypes.TxState, subject uuid.UUID) (count int, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + sql := "SELECT COUNT(*) FROM evm.txes WHERE state = $1 AND subject = $2" + err = qq.Get(&count, sql, state, subject) + return count, err +} + +func (o *evmTxStore) FindTxesByFromAddressAndState(ctx context.Context, fromAddress common.Address, state string) (txes []*Tx, err error) { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + sql := "SELECT * FROM evm.txes WHERE from_address = $1 AND state = $2" + var dbEtxs []DbEthTx + err = qq.Select(&dbEtxs, sql, fromAddress, state) + txes = make([]*Tx, len(dbEtxs)) + dbEthTxsToEvmEthTxPtrs(dbEtxs, txes) + return txes, err +} + +func (o *evmTxStore) UpdateTxAttemptBroadcastBeforeBlockNum(ctx context.Context, id int64, blockNum uint) error { + var cancel context.CancelFunc + ctx, cancel = o.mergeContexts(ctx) + defer cancel() + qq := o.q.WithOpts(pg.WithParentCtx(ctx)) + sql := "UPDATE evm.tx_attempts SET broadcast_before_block_num = $1 WHERE eth_tx_id = $2" + _, err := qq.Exec(sql, blockNum, id) + return err +} + // Returns a context that contains the values of the provided context, // and which is canceled when either the provided contextg or TxStore parent context is canceled. func (o *evmTxStore) mergeContexts(ctx context.Context) (context.Context, context.CancelFunc) { diff --git a/core/chains/evm/txmgr/evm_tx_store_test.go b/core/chains/evm/txmgr/evm_tx_store_test.go index 0b4287b6f6c..b5da5527448 100644 --- a/core/chains/evm/txmgr/evm_tx_store_test.go +++ b/core/chains/evm/txmgr/evm_tx_store_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -14,6 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "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" @@ -22,8 +24,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "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" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -1379,7 +1379,7 @@ func TestORM_UpdateTxUnstartedToInProgress(t *testing.T) { etx := mustInsertInProgressEthTxWithAttempt(t, txStore, nonce, fromAddress) require.Len(t, etx.TxAttempts, 1) - zero := models.MustNewDuration(time.Duration(0)) + zero := commonconfig.MustNewDuration(time.Duration(0)) evmCfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Chain.Transactions.ReaperInterval = zero c.EVM[0].Chain.Transactions.ReaperThreshold = zero @@ -1811,7 +1811,7 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := newTestChainScopedConfig(t) - txStore := newTxStore(t, db, cfg.Database()) + txStore := txmgr.NewTxStore(db, logger.Test(t), cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() evmtest.NewEthClientMockWithDefaultChain(t) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) @@ -1822,7 +1822,7 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { for i := 0; i < 5; i++ { mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, txRequestWithStrategy(strategy1)) } - testutils.AssertCountPerSubject(t, db, int64(5), subject1) + AssertCountPerSubject(t, txStore, int64(5), subject1) }) t.Run("prunes if queue has exceeded capacity", func(t *testing.T) { @@ -1831,6 +1831,13 @@ func TestORM_PruneUnstartedTxQueue(t *testing.T) { for i := 0; i < 5; i++ { mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, &cltest.FixtureChainID, txRequestWithStrategy(strategy2)) } - testutils.AssertCountPerSubject(t, db, int64(3), subject2) + AssertCountPerSubject(t, txStore, int64(3), subject2) }) } + +func AssertCountPerSubject(t *testing.T, txStore txmgr.TestEvmTxStore, expected int64, subject uuid.UUID) { + t.Helper() + count, err := txStore.CountTxesByStateAndSubject(testutils.Context(t), "unstarted", subject) + require.NoError(t, err) + require.Equal(t, int(expected), count) +} diff --git a/core/chains/evm/txmgr/mocks/config.go b/core/chains/evm/txmgr/mocks/config.go index ab98d686c85..0a0ece4b90b 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type Config struct { func (_m *Config) ChainType() config.ChainType { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainType") + } + var r0 config.ChainType if rf, ok := ret.Get(0).(func() config.ChainType); ok { r0 = rf() @@ -30,6 +34,10 @@ func (_m *Config) ChainType() config.ChainType { func (_m *Config) FinalityDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -44,6 +52,10 @@ func (_m *Config) FinalityDepth() uint32 { func (_m *Config) FinalityTagEnabled() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityTagEnabled") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -58,6 +70,10 @@ func (_m *Config) FinalityTagEnabled() bool { func (_m *Config) NonceAutoSync() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for NonceAutoSync") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -72,6 +88,10 @@ func (_m *Config) NonceAutoSync() bool { func (_m *Config) RPCDefaultBatchSize() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for RPCDefaultBatchSize") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() diff --git a/core/chains/evm/txmgr/mocks/evm_tx_store.go b/core/chains/evm/txmgr/mocks/evm_tx_store.go index bf3088b2aa1..a9a7023ac1f 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -32,6 +32,10 @@ type EvmTxStore struct { func (_m *EvmTxStore) Abandon(ctx context.Context, id *big.Int, addr common.Address) error { ret := _m.Called(ctx, id, addr) + if len(ret) == 0 { + panic("no return value specified for Abandon") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int, common.Address) error); ok { r0 = rf(ctx, id, addr) @@ -46,6 +50,10 @@ func (_m *EvmTxStore) Abandon(ctx context.Context, id *big.Int, addr common.Addr func (_m *EvmTxStore) CheckTxQueueCapacity(ctx context.Context, fromAddress common.Address, maxQueuedTransactions uint64, chainID *big.Int) error { ret := _m.Called(ctx, fromAddress, maxQueuedTransactions, chainID) + if len(ret) == 0 { + panic("no return value specified for CheckTxQueueCapacity") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, uint64, *big.Int) error); ok { r0 = rf(ctx, fromAddress, maxQueuedTransactions, chainID) @@ -65,6 +73,10 @@ func (_m *EvmTxStore) Close() { func (_m *EvmTxStore) CountTransactionsByState(ctx context.Context, state types.TxState, chainID *big.Int) (uint32, error) { ret := _m.Called(ctx, state, chainID) + if len(ret) == 0 { + panic("no return value specified for CountTransactionsByState") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, types.TxState, *big.Int) (uint32, error)); ok { @@ -89,6 +101,10 @@ func (_m *EvmTxStore) CountTransactionsByState(ctx context.Context, state types. func (_m *EvmTxStore) CountUnconfirmedTransactions(ctx context.Context, fromAddress common.Address, chainID *big.Int) (uint32, error) { ret := _m.Called(ctx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for CountUnconfirmedTransactions") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (uint32, error)); ok { @@ -113,6 +129,10 @@ func (_m *EvmTxStore) CountUnconfirmedTransactions(ctx context.Context, fromAddr func (_m *EvmTxStore) CountUnstartedTransactions(ctx context.Context, fromAddress common.Address, chainID *big.Int) (uint32, error) { ret := _m.Called(ctx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for CountUnstartedTransactions") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (uint32, error)); ok { @@ -137,6 +157,10 @@ func (_m *EvmTxStore) CountUnstartedTransactions(ctx context.Context, fromAddres func (_m *EvmTxStore) CreateTransaction(ctx context.Context, txRequest types.TxRequest[common.Address, common.Hash], chainID *big.Int) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, txRequest, chainID) + if len(ret) == 0 { + panic("no return value specified for CreateTransaction") + } + 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, types.TxRequest[common.Address, common.Hash], *big.Int) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -161,6 +185,10 @@ func (_m *EvmTxStore) CreateTransaction(ctx context.Context, txRequest types.TxR func (_m *EvmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, attempt) + if len(ret) == 0 { + panic("no return value specified for DeleteInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, attempt) @@ -175,6 +203,10 @@ func (_m *EvmTxStore) DeleteInProgressAttempt(ctx context.Context, attempt types func (_m *EvmTxStore) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, chainID *big.Int) (null.Time, error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedBroadcastTime") + } + var r0 null.Time var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (null.Time, error)); ok { @@ -199,6 +231,10 @@ func (_m *EvmTxStore) FindEarliestUnconfirmedBroadcastTime(ctx context.Context, func (_m *EvmTxStore) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, chainID *big.Int) (null.Int, error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindEarliestUnconfirmedTxAttemptBlock") + } + var r0 null.Int var r1 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (null.Int, error)); ok { @@ -223,6 +259,10 @@ func (_m *EvmTxStore) FindEarliestUnconfirmedTxAttemptBlock(ctx context.Context, func (_m *EvmTxStore) FindLatestSequence(ctx context.Context, fromAddress common.Address, chainId *big.Int) (evmtypes.Nonce, error) { ret := _m.Called(ctx, fromAddress, chainId) + if len(ret) == 0 { + panic("no return value specified for FindLatestSequence") + } + var r0 evmtypes.Nonce var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (evmtypes.Nonce, error)); ok { @@ -247,6 +287,10 @@ func (_m *EvmTxStore) FindLatestSequence(ctx context.Context, fromAddress common func (_m *EvmTxStore) FindNextUnstartedTransactionFromAddress(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], fromAddress common.Address, chainID *big.Int) error { ret := _m.Called(ctx, etx, fromAddress, chainID) + if len(ret) == 0 { + panic("no return value specified for FindNextUnstartedTransactionFromAddress") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], common.Address, *big.Int) error); ok { r0 = rf(ctx, etx, fromAddress, chainID) @@ -261,6 +305,10 @@ func (_m *EvmTxStore) FindNextUnstartedTransactionFromAddress(ctx context.Contex func (_m *EvmTxStore) FindTransactionsConfirmedInBlockRange(ctx context.Context, highBlockNumber int64, lowBlockNumber int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, highBlockNumber, lowBlockNumber, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTransactionsConfirmedInBlockRange") + } + 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, int64, int64, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -287,6 +335,10 @@ func (_m *EvmTxStore) FindTransactionsConfirmedInBlockRange(ctx context.Context, func (_m *EvmTxStore) FindTxAttempt(hash common.Hash) (*types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(hash) + if len(ret) == 0 { + panic("no return value specified for FindTxAttempt") + } + 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(common.Hash) (*types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -313,6 +365,10 @@ func (_m *EvmTxStore) FindTxAttempt(hash common.Hash) (*types.TxAttempt[*big.Int func (_m *EvmTxStore) FindTxAttemptConfirmedByTxIDs(ids []int64) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptConfirmedByTxIDs") + } + 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([]int64) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -339,6 +395,10 @@ func (_m *EvmTxStore) FindTxAttemptConfirmedByTxIDs(ids []int64) ([]types.TxAtte func (_m *EvmTxStore) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsConfirmedMissingReceipt") + } + 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.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -365,6 +425,10 @@ func (_m *EvmTxStore) FindTxAttemptsConfirmedMissingReceipt(ctx context.Context, func (_m *EvmTxStore) FindTxAttemptsRequiringReceiptFetch(ctx context.Context, chainID *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsRequiringReceiptFetch") + } + 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.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -391,6 +455,10 @@ func (_m *EvmTxStore) FindTxAttemptsRequiringReceiptFetch(ctx context.Context, c func (_m *EvmTxStore) FindTxAttemptsRequiringResend(ctx context.Context, olderThan time.Time, maxInFlightTransactions uint32, chainID *big.Int, address common.Address) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, olderThan, maxInFlightTransactions, chainID, address) + if len(ret) == 0 { + panic("no return value specified for FindTxAttemptsRequiringResend") + } + 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, time.Time, uint32, *big.Int, common.Address) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -417,6 +485,10 @@ func (_m *EvmTxStore) FindTxAttemptsRequiringResend(ctx context.Context, olderTh func (_m *EvmTxStore) FindTxByHash(hash common.Hash) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(hash) + if len(ret) == 0 { + panic("no return value specified for FindTxByHash") + } + 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(common.Hash) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -443,6 +515,10 @@ func (_m *EvmTxStore) FindTxByHash(hash common.Hash) (*types.Tx[*big.Int, common func (_m *EvmTxStore) FindTxWithAttempts(etxID int64) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(etxID) + if len(ret) == 0 { + panic("no return value specified for FindTxWithAttempts") + } + 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(int64) (types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -467,6 +543,10 @@ func (_m *EvmTxStore) FindTxWithAttempts(etxID int64) (types.Tx[*big.Int, common func (_m *EvmTxStore) FindTxWithIdempotencyKey(ctx context.Context, idempotencyKey string, chainID *big.Int) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, idempotencyKey, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxWithIdempotencyKey") + } + 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, string, *big.Int) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -493,6 +573,10 @@ func (_m *EvmTxStore) FindTxWithIdempotencyKey(ctx context.Context, idempotencyK func (_m *EvmTxStore) FindTxWithSequence(ctx context.Context, fromAddress common.Address, seq evmtypes.Nonce) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, fromAddress, seq) + if len(ret) == 0 { + panic("no return value specified for FindTxWithSequence") + } + 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, evmtypes.Nonce) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -519,6 +603,10 @@ func (_m *EvmTxStore) FindTxWithSequence(ctx context.Context, fromAddress common func (_m *EvmTxStore) FindTxesByMetaFieldAndStates(ctx context.Context, metaField string, metaValue string, 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, metaField, metaValue, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesByMetaFieldAndStates") + } + 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, string, string, []types.TxState, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -545,6 +633,10 @@ func (_m *EvmTxStore) FindTxesByMetaFieldAndStates(ctx context.Context, metaFiel func (_m *EvmTxStore) FindTxesPendingCallback(ctx context.Context, blockNum int64, chainID *big.Int) ([]types.ReceiptPlus[*evmtypes.Receipt], error) { ret := _m.Called(ctx, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesPendingCallback") + } + var r0 []types.ReceiptPlus[*evmtypes.Receipt] var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) ([]types.ReceiptPlus[*evmtypes.Receipt], error)); ok { @@ -571,6 +663,10 @@ func (_m *EvmTxStore) FindTxesPendingCallback(ctx context.Context, blockNum int6 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) { ret := _m.Called(ctx, ids, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithAttemptsAndReceiptsByIdsAndState") + } + 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 { @@ -597,6 +693,10 @@ func (_m *EvmTxStore) FindTxesWithAttemptsAndReceiptsByIdsAndState(ctx context.C func (_m *EvmTxStore) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context, metaField string, blockNum int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, metaField, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByReceiptBlockNum") + } + 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, string, int64, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -623,6 +723,10 @@ func (_m *EvmTxStore) FindTxesWithMetaFieldByReceiptBlockNum(ctx context.Context func (_m *EvmTxStore) FindTxesWithMetaFieldByStates(ctx context.Context, metaField string, 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, metaField, states, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxesWithMetaFieldByStates") + } + 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, string, []types.TxState, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -649,6 +753,10 @@ func (_m *EvmTxStore) FindTxesWithMetaFieldByStates(ctx context.Context, metaFie func (_m *EvmTxStore) FindTxsRequiringGasBump(ctx context.Context, address common.Address, blockNum int64, gasBumpThreshold int64, depth int64, chainID *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, address, blockNum, gasBumpThreshold, depth, chainID) + if len(ret) == 0 { + panic("no return value specified for FindTxsRequiringGasBump") + } + 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, int64, int64, int64, *big.Int) ([]*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -675,6 +783,10 @@ func (_m *EvmTxStore) FindTxsRequiringGasBump(ctx context.Context, address commo func (_m *EvmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx context.Context, address common.Address, chainID *big.Int) ([]*types.Tx[*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 FindTxsRequiringResubmissionDueToInsufficientFunds") + } + 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.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -701,6 +813,10 @@ func (_m *EvmTxStore) FindTxsRequiringResubmissionDueToInsufficientFunds(ctx con 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 GetInProgressTxAttempts") + } + 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, common.Address, *big.Int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -727,6 +843,10 @@ func (_m *EvmTxStore) GetInProgressTxAttempts(ctx context.Context, address commo 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) + if len(ret) == 0 { + panic("no return value specified for GetNonFatalTransactions") + } + 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.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -753,6 +873,10 @@ func (_m *EvmTxStore) GetNonFatalTransactions(ctx context.Context, chainID *big. func (_m *EvmTxStore) GetTxByID(ctx context.Context, id int64) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for GetTxByID") + } + 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, int64) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -779,6 +903,10 @@ func (_m *EvmTxStore) GetTxByID(ctx context.Context, id int64) (*types.Tx[*big.I func (_m *EvmTxStore) GetTxInProgress(ctx context.Context, fromAddress common.Address) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error) { ret := _m.Called(ctx, fromAddress) + if len(ret) == 0 { + panic("no return value specified for GetTxInProgress") + } + 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) (*types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], error)); ok { @@ -805,6 +933,10 @@ func (_m *EvmTxStore) GetTxInProgress(ctx context.Context, fromAddress common.Ad func (_m *EvmTxStore) HasInProgressTransaction(ctx context.Context, account common.Address, chainID *big.Int) (bool, error) { ret := _m.Called(ctx, account, chainID) + if len(ret) == 0 { + panic("no return value specified for HasInProgressTransaction") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, *big.Int) (bool, error)); ok { @@ -829,6 +961,10 @@ func (_m *EvmTxStore) HasInProgressTransaction(ctx context.Context, account comm func (_m *EvmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID int64, chainID *big.Int) (bool, error) { ret := _m.Called(ctx, blockHeight, txID, chainID) + if len(ret) == 0 { + panic("no return value specified for IsTxFinalized") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64, int64, *big.Int) (bool, error)); ok { @@ -853,6 +989,10 @@ func (_m *EvmTxStore) IsTxFinalized(ctx context.Context, blockHeight int64, txID func (_m *EvmTxStore) LoadTxAttempts(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, etx) + if len(ret) == 0 { + panic("no return value specified for LoadTxAttempts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, etx) @@ -867,6 +1007,10 @@ func (_m *EvmTxStore) LoadTxAttempts(ctx context.Context, etx *types.Tx[*big.Int func (_m *EvmTxStore) MarkAllConfirmedMissingReceipt(ctx context.Context, chainID *big.Int) error { ret := _m.Called(ctx, chainID) + if len(ret) == 0 { + panic("no return value specified for MarkAllConfirmedMissingReceipt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int) error); ok { r0 = rf(ctx, chainID) @@ -881,6 +1025,10 @@ func (_m *EvmTxStore) MarkAllConfirmedMissingReceipt(ctx context.Context, chainI func (_m *EvmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, blockNum int64, finalityDepth uint32, chainID *big.Int) error { ret := _m.Called(ctx, blockNum, finalityDepth, chainID) + if len(ret) == 0 { + panic("no return value specified for MarkOldTxesMissingReceiptAsErrored") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, uint32, *big.Int) error); ok { r0 = rf(ctx, blockNum, finalityDepth, chainID) @@ -895,6 +1043,10 @@ func (_m *EvmTxStore) MarkOldTxesMissingReceiptAsErrored(ctx context.Context, bl func (_m *EvmTxStore) PreloadTxes(ctx context.Context, attempts []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, attempts) + if len(ret) == 0 { + panic("no return value specified for PreloadTxes") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, attempts) @@ -909,6 +1061,10 @@ func (_m *EvmTxStore) PreloadTxes(ctx context.Context, attempts []types.TxAttemp func (_m *EvmTxStore) PruneUnstartedTxQueue(ctx context.Context, queueSize uint32, subject uuid.UUID) (int64, error) { ret := _m.Called(ctx, queueSize, subject) + if len(ret) == 0 { + panic("no return value specified for PruneUnstartedTxQueue") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint32, uuid.UUID) (int64, error)); ok { @@ -933,6 +1089,10 @@ func (_m *EvmTxStore) PruneUnstartedTxQueue(ctx context.Context, queueSize uint3 func (_m *EvmTxStore) ReapTxHistory(ctx context.Context, minBlockNumberToKeep int64, timeThreshold time.Time, chainID *big.Int) error { ret := _m.Called(ctx, minBlockNumberToKeep, timeThreshold, chainID) + if len(ret) == 0 { + panic("no return value specified for ReapTxHistory") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, time.Time, *big.Int) error); ok { r0 = rf(ctx, minBlockNumberToKeep, timeThreshold, chainID) @@ -947,6 +1107,10 @@ func (_m *EvmTxStore) ReapTxHistory(ctx context.Context, minBlockNumberToKeep in func (_m *EvmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, timeout time.Duration, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveConfirmedMissingReceiptAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -961,6 +1125,10 @@ func (_m *EvmTxStore) SaveConfirmedMissingReceiptAttempt(ctx context.Context, ti func (_m *EvmTxStore) SaveFetchedReceipts(ctx context.Context, receipts []*evmtypes.Receipt, chainID *big.Int) error { ret := _m.Called(ctx, receipts, chainID) + if len(ret) == 0 { + panic("no return value specified for SaveFetchedReceipts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []*evmtypes.Receipt, *big.Int) error); ok { r0 = rf(ctx, receipts, chainID) @@ -975,6 +1143,10 @@ func (_m *EvmTxStore) SaveFetchedReceipts(ctx context.Context, receipts []*evmty func (_m *EvmTxStore) SaveInProgressAttempt(ctx context.Context, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, attempt) + if len(ret) == 0 { + panic("no return value specified for SaveInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, attempt) @@ -989,6 +1161,10 @@ func (_m *EvmTxStore) SaveInProgressAttempt(ctx context.Context, attempt *types. func (_m *EvmTxStore) SaveInsufficientFundsAttempt(ctx context.Context, timeout time.Duration, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveInsufficientFundsAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -1003,6 +1179,10 @@ func (_m *EvmTxStore) SaveInsufficientFundsAttempt(ctx context.Context, timeout func (_m *EvmTxStore) SaveReplacementInProgressAttempt(ctx context.Context, oldAttempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], replacementAttempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, oldAttempt, replacementAttempt) + if len(ret) == 0 { + panic("no return value specified for SaveReplacementInProgressAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, oldAttempt, replacementAttempt) @@ -1017,6 +1197,10 @@ func (_m *EvmTxStore) SaveReplacementInProgressAttempt(ctx context.Context, oldA func (_m *EvmTxStore) SaveSentAttempt(ctx context.Context, timeout time.Duration, attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], broadcastAt time.Time) error { ret := _m.Called(ctx, timeout, attempt, broadcastAt) + if len(ret) == 0 { + panic("no return value specified for SaveSentAttempt") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration, *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], time.Time) error); ok { r0 = rf(ctx, timeout, attempt, broadcastAt) @@ -1031,6 +1215,10 @@ func (_m *EvmTxStore) SaveSentAttempt(ctx context.Context, timeout time.Duration func (_m *EvmTxStore) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum int64, chainID *big.Int) error { ret := _m.Called(ctx, blockNum, chainID) + if len(ret) == 0 { + panic("no return value specified for SetBroadcastBeforeBlockNum") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, *big.Int) error); ok { r0 = rf(ctx, blockNum, chainID) @@ -1045,6 +1233,10 @@ func (_m *EvmTxStore) SetBroadcastBeforeBlockNum(ctx context.Context, blockNum i func (_m *EvmTxStore) Transactions(offset int, limit int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for Transactions") + } + var r0 []types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 int var r2 error @@ -1078,6 +1270,10 @@ func (_m *EvmTxStore) Transactions(offset int, limit int) ([]types.Tx[*big.Int, func (_m *EvmTxStore) TransactionsWithAttempts(offset int, limit int) ([]types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for TransactionsWithAttempts") + } + var r0 []types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 int var r2 error @@ -1111,6 +1307,10 @@ func (_m *EvmTxStore) TransactionsWithAttempts(offset int, limit int) ([]types.T func (_m *EvmTxStore) TxAttempts(offset int, limit int) ([]types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for TxAttempts") + } + var r0 []types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] var r1 int var r2 error @@ -1144,6 +1344,10 @@ func (_m *EvmTxStore) TxAttempts(offset int, limit int) ([]types.TxAttempt[*big. func (_m *EvmTxStore) UpdateBroadcastAts(ctx context.Context, now time.Time, etxIDs []int64) error { ret := _m.Called(ctx, now, etxIDs) + if len(ret) == 0 { + panic("no return value specified for UpdateBroadcastAts") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Time, []int64) error); ok { r0 = rf(ctx, now, etxIDs) @@ -1158,6 +1362,10 @@ func (_m *EvmTxStore) UpdateBroadcastAts(ctx context.Context, now time.Time, etx func (_m *EvmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], NewAttemptState types.TxAttemptState) error { ret := _m.Called(ctx, etx, attempt, NewAttemptState) + if len(ret) == 0 { + panic("no return value specified for UpdateTxAttemptInProgressToBroadcast") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttemptState) error); ok { r0 = rf(ctx, etx, attempt, NewAttemptState) @@ -1172,6 +1380,10 @@ func (_m *EvmTxStore) UpdateTxAttemptInProgressToBroadcast(ctx context.Context, func (_m *EvmTxStore) UpdateTxCallbackCompleted(ctx context.Context, pipelineTaskRunRid uuid.UUID, chainId *big.Int) error { ret := _m.Called(ctx, pipelineTaskRunRid, chainId) + if len(ret) == 0 { + panic("no return value specified for UpdateTxCallbackCompleted") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, *big.Int) error); ok { r0 = rf(ctx, pipelineTaskRunRid, chainId) @@ -1186,6 +1398,10 @@ func (_m *EvmTxStore) UpdateTxCallbackCompleted(ctx context.Context, pipelineTas func (_m *EvmTxStore) UpdateTxFatalError(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, etx) + if len(ret) == 0 { + panic("no return value specified for UpdateTxFatalError") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, etx) @@ -1200,6 +1416,10 @@ func (_m *EvmTxStore) UpdateTxFatalError(ctx context.Context, etx *types.Tx[*big func (_m *EvmTxStore) UpdateTxForRebroadcast(ctx context.Context, etx types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], etxAttempt types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, etx, etxAttempt) + if len(ret) == 0 { + panic("no return value specified for UpdateTxForRebroadcast") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, etx, etxAttempt) @@ -1214,6 +1434,10 @@ func (_m *EvmTxStore) UpdateTxForRebroadcast(ctx context.Context, etx types.Tx[* func (_m *EvmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], attempt *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error { ret := _m.Called(ctx, etx, attempt) + if len(ret) == 0 { + panic("no return value specified for UpdateTxUnstartedToInProgress") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *types.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], *types.TxAttempt[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]) error); ok { r0 = rf(ctx, etx, attempt) @@ -1228,6 +1452,10 @@ func (_m *EvmTxStore) UpdateTxUnstartedToInProgress(ctx context.Context, etx *ty func (_m *EvmTxStore) UpdateTxsUnconfirmed(ctx context.Context, ids []int64) error { ret := _m.Called(ctx, ids) + if len(ret) == 0 { + panic("no return value specified for UpdateTxsUnconfirmed") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []int64) error); ok { r0 = rf(ctx, ids) diff --git a/core/chains/evm/txmgr/reaper_test.go b/core/chains/evm/txmgr/reaper_test.go index 2da8e7a93c8..a539f0ac8cb 100644 --- a/core/chains/evm/txmgr/reaper_test.go +++ b/core/chains/evm/txmgr/reaper_test.go @@ -9,13 +9,14 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" 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" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func newReaperWithChainID(t *testing.T, db txmgrtypes.TxHistoryReaper[*big.Int], cfg txmgrtypes.ReaperChainConfig, txConfig txmgrtypes.ReaperTransactionsConfig, cid *big.Int) *txmgr.Reaper { diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index 0e86c0d4f8c..fd3d1745010 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -13,17 +13,17 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "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/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/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_EthResender_resendUnconfirmed(t *testing.T) { @@ -106,10 +106,10 @@ func Test_EthResender_alertUnconfirmed(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, logCfg).Eth() ethClient := evmtest.NewEthClientMockWithDefaultChain(t) // Set this to the smallest non-zero value possible for the attempt to be eligible for resend - delay := models.MustNewDuration(1 * time.Nanosecond) + delay := commonconfig.MustNewDuration(1 * time.Nanosecond) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0] = &toml.EVMConfig{ - Chain: toml.Defaults(utils.NewBig(big.NewInt(0)), &toml.Chain{ + Chain: toml.Defaults(ubig.New(big.NewInt(0)), &toml.Chain{ Transactions: toml.Transactions{ResendAfterThreshold: delay}, }), } @@ -144,7 +144,7 @@ func Test_EthResender_Start(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { // This can be anything as long as it isn't zero - c.EVM[0].Transactions.ResendAfterThreshold = models.MustNewDuration(42 * time.Hour) + c.EVM[0].Transactions.ResendAfterThreshold = commonconfig.MustNewDuration(42 * time.Hour) // Set batch size low to test batching c.EVM[0].RPCDefaultBatchSize = ptr[uint32](1) }) diff --git a/core/chains/evm/txmgr/tracker_test.go b/core/chains/evm/txmgr/tracker_test.go index af41aaeffa5..d3083372789 100644 --- a/core/chains/evm/txmgr/tracker_test.go +++ b/core/chains/evm/txmgr/tracker_test.go @@ -7,12 +7,12 @@ import ( "time" "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/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" @@ -33,8 +33,8 @@ func newTestEvmTrackerSetup(t *testing.T) (*txmgr.Tracker, txmgr.TestEvmTxStore, func generateEnabledAddresses(t *testing.T, keyStore keystore.Eth, chainID *big.Int) []common.Address { var enabledAddresses []common.Address - _, addr1 := cltest.MustInsertRandomKey(t, keyStore, *utils.NewBigI(chainID.Int64())) - _, addr2 := cltest.MustInsertRandomKey(t, keyStore, *utils.NewBigI(chainID.Int64())) + _, addr1 := cltest.MustInsertRandomKey(t, keyStore, *ubig.NewI(chainID.Int64())) + _, addr2 := cltest.MustInsertRandomKey(t, keyStore, *ubig.NewI(chainID.Int64())) enabledAddresses = append(enabledAddresses, addr1, addr2) return enabledAddresses } diff --git a/core/chains/evm/txmgr/transmitchecker.go b/core/chains/evm/txmgr/transmitchecker.go index 76dfcb9d51c..5a5cc3dbcd4 100644 --- a/core/chains/evm/txmgr/transmitchecker.go +++ b/core/chains/evm/txmgr/transmitchecker.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" + "github.com/smartcontractkit/chainlink-common/pkg/utils/bytes" "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" @@ -23,7 +24,6 @@ import ( v1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" v2 "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/utils" ) type ( @@ -110,7 +110,7 @@ type noChecker struct{} // Check satisfies the TransmitChecker interface. func (noChecker) Check( _ context.Context, - _ logger.Logger, + _ logger.SugaredLogger, _ Tx, _ TxAttempt, ) error { @@ -125,7 +125,7 @@ type SimulateChecker struct { // Check satisfies the TransmitChecker interface. func (s *SimulateChecker) Check( ctx context.Context, - l logger.Logger, + l logger.SugaredLogger, tx Tx, a TxAttempt, ) error { @@ -148,7 +148,7 @@ func (s *SimulateChecker) Check( err := s.Client.CallContext(ctx, &b, "eth_call", callArg, evmclient.ToBlockNumArg(nil)) if err != nil { if jErr := evmclient.ExtractRPCErrorOrNil(err); jErr != nil { - logger.Criticalw(l, "Transaction reverted during simulation", + l.Criticalw("Transaction reverted during simulation", "ethTxAttemptID", a.ID, "txHash", a.Hash, "err", err, "rpcErr", jErr.String(), "returnValue", b.String()) return errors.Errorf("transaction reverted during simulation: %s", jErr.String()) } @@ -175,7 +175,7 @@ type VRFV1Checker struct { // Check satisfies the TransmitChecker interface. func (v *VRFV1Checker) Check( ctx context.Context, - l logger.Logger, + l logger.SugaredLogger, tx Tx, _ TxAttempt, ) error { @@ -252,7 +252,7 @@ func (v *VRFV1Checker) Check( "meta", tx.Meta, "reqID", reqID) return nil - } else if utils.IsEmpty(callback.SeedAndBlockNum[:]) { + } else if bytes.IsEmpty(callback.SeedAndBlockNum[:]) { // Request already fulfilled l.Infow("Request already fulfilled", "err", err, @@ -284,7 +284,7 @@ type VRFV2Checker struct { // Check satisfies the TransmitChecker interface. func (v *VRFV2Checker) Check( ctx context.Context, - l logger.Logger, + l logger.SugaredLogger, tx Tx, _ TxAttempt, ) error { @@ -344,7 +344,7 @@ func (v *VRFV2Checker) Check( "blockNumber", h.Number, ) return nil - } else if utils.IsEmpty(callback[:]) { + } else if bytes.IsEmpty(callback[:]) { // If seedAndBlockNumber is zero then the response has been fulfilled and we should skip it. l.Infow("Request already fulfilled.", "ethTxID", tx.ID, diff --git a/core/chains/evm/txmgr/transmitchecker_test.go b/core/chains/evm/txmgr/transmitchecker_test.go index 6dd4edd91c6..d2f668da11b 100644 --- a/core/chains/evm/txmgr/transmitchecker_test.go +++ b/core/chains/evm/txmgr/transmitchecker_test.go @@ -106,7 +106,7 @@ func TestFactory(t *testing.T) { func TestTransmitCheckers(t *testing.T) { client := evmtest.NewEthClientMockWithDefaultChain(t) - log := logger.Test(t) + log := logger.Sugared(logger.Test(t)) ctx := testutils.Context(t) t.Run("no checker", func(t *testing.T) { diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 745623ed77e..6fafff1a5c1 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -21,6 +21,9 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" @@ -32,6 +35,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" 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" "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" @@ -40,7 +45,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func makeTestEvmTxm( @@ -205,7 +209,7 @@ func TestTxm_CreateTransaction(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), fmt.Sprintf("no eth key exists with address %s", rndAddr.String())) - _, otherAddress := cltest.MustInsertRandomKey(t, kst.Eth(), *utils.NewBigI(1337)) + _, otherAddress := cltest.MustInsertRandomKey(t, kst.Eth(), *ubig.NewI(1337)) _, err = txm.CreateTransaction(testutils.Context(t), txmgr.TxRequest{ FromAddress: otherAddress, @@ -300,7 +304,7 @@ func TestTxm_CreateTransaction(t *testing.T) { // Create mock forwarder, mock authorizedsenders call. form := forwarders.NewORM(db, logger.Test(t), cfg.Database()) fwdrAddr := testutils.NewAddress() - fwdr, err := form.CreateForwarder(fwdrAddr, utils.Big(cltest.FixtureChainID)) + fwdr, err := form.CreateForwarder(fwdrAddr, ubig.Big(cltest.FixtureChainID)) require.NoError(t, err) require.Equal(t, fwdr.Address, fwdrAddr) @@ -417,7 +421,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { require.Equal(t, payload, etx.EncodedPayload) }) - require.NoError(t, utils.JustError(db.Exec(`DELETE FROM evm.txes WHERE from_address = $1`, thisKey.Address))) + require.NoError(t, commonutils.JustError(db.Exec(`DELETE FROM evm.txes WHERE from_address = $1`, thisKey.Address))) t.Run("if this key has any transactions with insufficient eth errors, inserts it anyway", func(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) @@ -440,7 +444,7 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { require.Equal(t, payload, etx.EncodedPayload) }) - require.NoError(t, utils.JustError(db.Exec(`DELETE FROM evm.txes WHERE from_address = $1`, thisKey.Address))) + require.NoError(t, commonutils.JustError(db.Exec(`DELETE FROM evm.txes WHERE from_address = $1`, thisKey.Address))) t.Run("if this key has transactions but no insufficient eth errors, transmits as normal", func(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) @@ -552,8 +556,7 @@ func TestTxm_Reset(t *testing.T) { assert.EqualError(t, err, "not started") }) - require.NoError(t, txm.Start(testutils.Context(t))) - defer func() { assert.NoError(t, txm.Close()) }() + servicetest.Run(t, txm) t.Run("returns no error if started", func(t *testing.T) { err := txm.Reset(addr, false) @@ -651,14 +654,15 @@ func mustInsertUnconfirmedEthTxWithAttemptState(t *testing.T, txStore txmgr.Test etx := cltest.MustInsertUnconfirmedEthTx(t, txStore, nonce, fromAddress, opts...) attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) - tx := types.NewTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + tx := cltest.NewLegacyTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) rlp := new(bytes.Buffer) require.NoError(t, tx.EncodeRLP(rlp)) attempt.SignedRawTx = rlp.Bytes() attempt.State = txAttemptState require.NoError(t, txStore.InsertTxAttempt(&attempt)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + var err error + etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) return etx } @@ -685,7 +689,8 @@ func mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t *testing.T, txSt attempt.State = txmgrtypes.TxAttemptBroadcast require.NoError(t, txStore.InsertTxAttempt(&attempt)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + var err error + etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) return etx } @@ -702,14 +707,15 @@ func mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t *testing.T, txStore require.NoError(t, txStore.InsertTx(&etx)) attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) - tx := types.NewTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + tx := cltest.NewLegacyTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) rlp := new(bytes.Buffer) require.NoError(t, tx.EncodeRLP(rlp)) attempt.SignedRawTx = rlp.Bytes() attempt.State = txmgrtypes.TxAttemptInsufficientFunds require.NoError(t, txStore.InsertTxAttempt(&attempt)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + var err error + etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) return etx } @@ -740,13 +746,14 @@ func mustInsertInProgressEthTxWithAttempt(t *testing.T, txStore txmgr.TestEvmTxS etx.State = txmgrcommon.TxInProgress require.NoError(t, txStore.InsertTx(&etx)) attempt := cltest.NewLegacyEthTxAttempt(t, etx.ID) - tx := types.NewTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + tx := cltest.NewLegacyTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) rlp := new(bytes.Buffer) require.NoError(t, tx.EncodeRLP(rlp)) attempt.SignedRawTx = rlp.Bytes() attempt.State = txmgrtypes.TxAttemptInProgress require.NoError(t, txStore.InsertTxAttempt(&attempt)) - etx, err := txStore.FindTxWithAttempts(etx.ID) + var err error + etx, err = txStore.FindTxWithAttempts(etx.ID) require.NoError(t, err) return etx } diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index 314180a7e98..44e150b6541 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -16,12 +16,14 @@ import ( "github.com/pkg/errors" "github.com/ugorji/go/codec" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types/internal/blocks" + "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/null" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Head represents a BlockNumber, BlockHash. @@ -32,7 +34,7 @@ type Head struct { L1BlockNumber null.Int64 ParentHash common.Hash Parent *Head - EVMChainID *utils.Big + EVMChainID *ubig.Big Timestamp time.Time CreatedAt time.Time BaseFeePerGas *assets.Wei @@ -47,7 +49,7 @@ var _ commontypes.Head[common.Hash] = &Head{} var _ htrktypes.Head[common.Hash, *big.Int] = &Head{} // NewHead returns a Head instance. -func NewHead(number *big.Int, blockHash common.Hash, parentHash common.Hash, timestamp uint64, chainID *utils.Big) Head { +func NewHead(number *big.Int, blockHash common.Hash, parentHash common.Hash, timestamp uint64, chainID *ubig.Big) Head { return Head{ Number: number.Int64(), Hash: blockHash, @@ -314,7 +316,7 @@ func (h *Head) MarshalJSON() ([]byte, error) { if h.StateRoot != (common.Hash{}) { jsonHead.StateRoot = &h.StateRoot } - jsonHead.Number = (*hexutil.Big)(big.NewInt(int64(h.Number))) + jsonHead.Number = (*hexutil.Big)(big.NewInt(h.Number)) if h.ParentHash != (common.Hash{}) { jsonHead.ParentHash = &h.ParentHash } @@ -499,7 +501,7 @@ func (f *FunctionSelector) SetBytes(b []byte) { copy(f[:], b[:FunctionSelectorLe var hexRegexp = regexp.MustCompile("^[0-9a-fA-F]*$") func unmarshalFromString(s string, f *FunctionSelector) error { - if utils.HasHexPrefix(s) { + if hex.HasPrefix(s) { if !hexRegexp.Match([]byte(s)[2:]) { return fmt.Errorf("function selector %s must be 0x-hex encoded", s) } diff --git a/core/chains/evm/types/models_test.go b/core/chains/evm/types/models_test.go index 3507b6a1318..7617b45f9a0 100644 --- a/core/chains/evm/types/models_test.go +++ b/core/chains/evm/types/models_test.go @@ -12,20 +12,20 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "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/null" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestHead_NewHead(t *testing.T) { @@ -95,13 +95,12 @@ func TestEthTxAttempt_GetSignedTx(t *testing.T) { cfg := configtest.NewGeneralConfig(t, nil) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - tx := gethTypes.NewTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + tx := cltest.NewLegacyTransaction(uint64(42), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) chainID := big.NewInt(3) signedTx, err := ethKeyStore.SignTx(fromAddress, tx, chainID) require.NoError(t, err) - signedTx.Size() // Needed to write the size for equality checking rlp := new(bytes.Buffer) require.NoError(t, signedTx.EncodeRLP(rlp)) @@ -648,6 +647,265 @@ const paritySampleBlock = ` ` +const eip4844Block = ` { + "baseFeePerGas": "0x16740b3cb5", + "blobGasUsed": "0xc0000", + "difficulty": "0x0", + "excessBlobGas": "0x4b80000", + "extraData": "0xd883010d0c846765746888676f312e32302e31856c696e7578", + "gasLimit": "0x1c9c380", + "gasUsed": "0x18db0e0", + "hash": "0x3edd900025edab70dde26a52377c3d0a9474c3f540bd0131d58f508711272590", + "logsBloom": "0xc820da8f9c4ac1db241964223d4015549765668065d0c0418691262e44eda11970c271ead2b03ecffbb2ad52348c00cb0e11c083c3e26323855296236025e1d4198c892bb5cf0135cacc4f1bc138c88d8d44790497c6c201901a894b48966b2068f144bb16614271e6c05a854421290500081cea818eaae7950a8217a0d8d43a8b80018d800a43bd542d77230e5030861051152088a0d514d65177c2fa4198642eefd29e4dae806bfd4250ec63147fee38e368d00c01da1d67c1a5a24ed87331289bba074e1c2434147502a90df300a311b67056524e78a5b792930272b4607fb676060ea623d64ac1174a22b382a0648f5a35994b669131e3ea074ea128de45", + "miner": "0x6a7aa9b882d50bb7bc5da1a244719c99f12f06a3", + "mixHash": "0x27337177ae9744acb30c9d13e187c582367d75f702cc3ef2e77f9c6b10394ebf", + "nonce": "0x0000000000000000", + "number": "0x50e1d6", + "parentBeaconBlockRoot": "0xcdfe5d7bfd13221a86881bee926ec7e7e6c1eed2e460bd7772caa64bed1582ec", + "parentHash": "0x077c1d68b52f8203cb90a71759a09b11c2a6577f97ea1fd4a8686a387fbedac8", + "receiptsRoot": "0xff81f4fddbcfcc550c4358136953b56a66a95c24089501e2085d8c4588ffdb1f", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size": "0x2b41f", + "stateRoot": "0xc9541af90707127dde506b208de22cfda50ad2ef6e8b4f67212e6402d7099708", + "timestamp": "0x65cf57dc", + "totalDifficulty": "0x3c656d23029ab0", + "transactions": [ + { + "blockHash": "0x3edd900025edab70dde26a52377c3d0a9474c3f540bd0131d58f508711272590", + "blockNumber": "0x50e1d6", + "from": "0x3c352ea32dfbb757ccdf4b457e52daf6ecc21917", + "gas": "0x14820", + "gasPrice": "0x5d426cae68", + "hash": "0x8857a9064210e138a996c82a9d58b001d198b2362e8ad2ede7056a9c942011aa", + "input": "0x", + "nonce": "0xa07aa", + "to": "0xd3234d7985fdaefc68cbfa04e91ecca334b6545c", + "transactionIndex": "0x0", + "value": "0x6f05b59d3b20000", + "type": "0x0", + "chainId": "0xaa36a7", + "v": "0x1546d72", + "r": "0x2acc4f73342578b09d5152f60305f7cfe4f5d377da504e99ed3795b65b9bd5c", + "s": "0x33470e89e7508816c8c71d2135fc16a49b34ffbd86d8f6506658819afb578944" + }, + { + "blockHash": "0x3edd900025edab70dde26a52377c3d0a9474c3f540bd0131d58f508711272590", + "blockNumber": "0x50e1d6", + "from": "0x87c9b02a10ec2cb4dcb3b2e573e26169cf3cd9bf", + "gas": "0x14820", + "gasPrice": "0x5d426cae68", + "hash": "0x83170edd8c637791fc8bdf07ad687ab11456409546fea23d8db90933d18eb566", + "input": "0x", + "nonce": "0xa2e22", + "to": "0x2853502c56fb2160fcdc044d4477408b9670058e", + "transactionIndex": "0x1", + "value": "0x6f05b59d3b20000", + "type": "0x0", + "chainId": "0xaa36a7", + "v": "0x1546d72", + "r": "0xf5f12880149214ef1109c83bd9e80a6851a581aba2cf10c1c3d0e8ad473db9f5", + "s": "0x150c309b585f0b76fdb6ee4e26048fae88464e6ef2ff41a9341e84ddbbf4f7a7" + }, + { + "blockHash": "0x3edd900025edab70dde26a52377c3d0a9474c3f540bd0131d58f508711272590", + "blockNumber": "0x50e1d6", + "from": "0x0bf8d3a5bc2f3ce4ce93d0ef13c2d519d2efe7ab", + "gas": "0x32aa5", + "gasPrice": "0x17e3776320", + "hash": "0xe9a8dc19ca3ace8b06fdb120fbb1333f75a14e06229536adbdae1ca018f39d2f", + "input": "0x79df76820000000000000000000000000bf8d3a5bc2f3ce4ce93d0ef13c2d519d2efe7ab000000000000000000000000000000000000000000000000000000000002c3380000000000000000000000000000000000000000000000000000018db1eefe820000000000000000000000000000000000000000000000000000000191ea03c00000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001cbeaa1a18797feaaae677a2c47f551623362b25a4cbed88a14cf06318974302be1e3a13405cc803063bb4549a79efa547f2024d470b53d21631f42e3ce993bdd7", + "nonce": "0x3", + "to": "0x321ce961084fcf3a56de4be2f2006707a0421aa4", + "transactionIndex": "0x4a", + "value": "0x0", + "type": "0x0", + "chainId": "0xaa36a7", + "v": "0x1546d72", + "r": "0x53fa23875340ac5bd7af3e5b4791981cad94f9a86da431bdafdaf0d4fccbfab9", + "s": "0x1f3826a1d0358425f2bddacd9d87efeee07065492b7ccc499357d69437856859" + }, + { + "blockHash": "0x3edd900025edab70dde26a52377c3d0a9474c3f540bd0131d58f508711272590", + "blockNumber": "0x50e1d6", + "from": "0x1803c760451dc8da8935c7b7e47e1c60910e6986", + "gas": "0x5208", + "gasPrice": "0x17d9abf8b5", + "maxFeePerGas": "0x8bb2c97000", + "maxPriorityFeePerGas": "0x165a0bc00", + "maxFeePerBlobGas": "0xdf8475800", + "hash": "0x48a6a2294bd57cd0defc54968bf00179ef3c2d0c647d386e1840ee347d2dd0b8", + "input": "0x", + "nonce": "0x2861", + "to": "0x4f56ffc63c28b72f79b02e91f11a4707bac4043c", + "transactionIndex": "0x4b", + "value": "0x0", + "type": "0x3", + "accessList": [], + "chainId": "0xaa36a7", + "blobVersionedHashes": [ + "0x01b3722197a3bb82f25a26ab702b63e7c5ce7296ec18f7a53d5e2c28081084a3", + "0x0125c472df6afa04cbab756630f5bcf560fc929ee12c7dd4738cfd67fa7926d8", + "0x016316f61a259aa607096440fc3eeb90356e079be01975d2fb18347bd50df33c" + ], + "v": "0x0", + "r": "0xf9cfd7e18a156807a42fc05d2255a9741168363a7184b4fa40a9dc9f83dcc3d4", + "s": "0x9b12570519ef421bd31461bed09b3599db43354d3c88ff4bed17ddd964fadf6", + "yParity": "0x0" + }, + { + "blockHash": "0x3edd900025edab70dde26a52377c3d0a9474c3f540bd0131d58f508711272590", + "blockNumber": "0x50e1d6", + "from": "0x56272f6932e6ae0116d270a2e919d20d3052f206", + "gas": "0x5208", + "gasPrice": "0x17d9abf8b5", + "maxFeePerGas": "0x8bb2c97000", + "maxPriorityFeePerGas": "0x165a0bc00", + "maxFeePerBlobGas": "0xdf8475800", + "hash": "0xa97e14a2e87d322fcb97edc4b25cd976d18963cfad19bfd4b9c8066a6a2d97cf", + "input": "0x", + "nonce": "0x2836", + "to": "0x1803c760451dc8da8935c7b7e47e1c60910e6986", + "transactionIndex": "0x4c", + "value": "0x0", + "type": "0x3", + "accessList": [], + "chainId": "0xaa36a7", + "blobVersionedHashes": [ + "0x01adde6e37a3ba9e2a40052556b51960c2a4cc69c257992ae954c6d4f8d479c2", + "0x0142116f5d1b4b60672ac5b69edb7431ffddb700227d9b4dc9adafe599b38943", + "0x010ba493f0c9891f7109bd29e4914c4e79c7a35530981e746d02df66e5d57056" + ], + "v": "0x1", + "r": "0x82045878948921a0330ea7eb23b74f103f9f353704eaeab358e777bea238bfd", + "s": "0x378128f0fa8059df16cdc95f215f1e669dc81cee7c39b804e6371e486aa1e753", + "yParity": "0x1" + }, + { + "blockHash": "0x3edd900025edab70dde26a52377c3d0a9474c3f540bd0131d58f508711272590", + "blockNumber": "0x50e1d6", + "from": "0x779fa3507ad952f447c32f7d7e1f86ceddf2cc9d", + "gas": "0x1118b", + "gasPrice": "0x2e90edd000", + "maxFeePerGas": "0x2e90edd000", + "maxPriorityFeePerGas": "0x2e90edd000", + "hash": "0x6e94385ca341d5763ebb21601a86cddbc77acb879735ce1d013b22dc03fb07a2", + "input": "0x095ea7b3000000000000000000000000d3ec28ad6d777f5aa92377294b9b6522c719307900000000000000000000000000000000000000000000003635c9adc5dea00000", + "nonce": "0x57", + "to": "0xf7f928b2bf5cc7e0bd0f258165249fa3c2ef85ac", + "transactionIndex": "0x10", + "value": "0x0", + "type": "0x2", + "accessList": [], + "chainId": "0xaa36a7", + "v": "0x0", + "r": "0x4b4f0ccda6366f4897cb8eb3dee4a72bba76758159ff7030a134022c0a11def2", + "s": "0x27621a604938c68b98c52b57e2b27cb104e3838fd2864d18b6429d42ac2b2f0a", + "yParity": "0x0" + } + ], + "transactionsRoot": "0xb9773c32f06f914e3e6da66a114e3ddf84e38dff62e26621b0ffecee38d5fe6e", + "uncles": [], + "withdrawals": [ + { + "index": "0x233d1c2", + "validatorIndex": "0x384", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xec0" + }, + { + "index": "0x233d1c3", + "validatorIndex": "0x392", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xec0" + }, + { + "index": "0x233d1c4", + "validatorIndex": "0x393", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xec0" + }, + { + "index": "0x233d1c5", + "validatorIndex": "0x395", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xec0" + }, + { + "index": "0x233d1c6", + "validatorIndex": "0x396", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xec0" + }, + { + "index": "0x233d1c7", + "validatorIndex": "0x398", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xec0" + }, + { + "index": "0x233d1c8", + "validatorIndex": "0x39a", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xec0" + }, + { + "index": "0x233d1c9", + "validatorIndex": "0x39c", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xec0" + }, + { + "index": "0x233d1ca", + "validatorIndex": "0x39d", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xec0" + }, + { + "index": "0x233d1cb", + "validatorIndex": "0x39e", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xb10" + }, + { + "index": "0x233d1cc", + "validatorIndex": "0x39f", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xb10" + }, + { + "index": "0x233d1cd", + "validatorIndex": "0x3a3", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xb10" + }, + { + "index": "0x233d1ce", + "validatorIndex": "0x3a4", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xb10" + }, + { + "index": "0x233d1cf", + "validatorIndex": "0x3a5", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xb10" + }, + { + "index": "0x233d1d0", + "validatorIndex": "0x3ad", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xb10" + }, + { + "index": "0x233d1d1", + "validatorIndex": "0x3ae", + "address": "0xe276bc378a527a8792b353cdca5b5e53263dfb9e", + "amount": "0xb10" + } + ], + "withdrawalsRoot": "0x26a577aa6ab5e73684b15665f8510c7da8f29a66ed17bf73c1c11f4c3af9c955" +}` + func TestBlock_UnmarshalJSON(t *testing.T) { t.Run("unmarshals parity block", func(t *testing.T) { b := new(evmtypes.Block) @@ -680,6 +938,17 @@ func TestBlock_UnmarshalJSON(t *testing.T) { assert.Equal(t, errors.Cause(err), evmtypes.ErrMissingBlock) assert.True(t, errors.Is(err, evmtypes.ErrMissingBlock)) }) + t.Run("unmarshals EIP-4844 block", func(t *testing.T) { + b := new(evmtypes.Block) + err := b.UnmarshalJSON([]byte(eip4844Block)) + assert.NoError(t, err) + assert.Equal(t, int64(5300694), b.Number) + assert.Equal(t, "0x3edd900025edab70dde26a52377c3d0a9474c3f540bd0131d58f508711272590", b.Hash.Hex()) + assert.Equal(t, "0x077c1d68b52f8203cb90a71759a09b11c2a6577f97ea1fd4a8686a387fbedac8", b.ParentHash.Hex()) + assert.Equal(t, assets.NewWeiI(96436174005), b.BaseFeePerGas) + assert.Equal(t, int64(1708087260), b.Timestamp.Unix()) + assert.Len(t, b.Transactions, 6) + }) } func TestTransaction_UnmarshalJSON(t *testing.T) { @@ -721,14 +990,58 @@ func TestTransaction_UnmarshalJSON(t *testing.T) { ), }, want: &evmtypes.Transaction{ - GasPrice: assets.NewWei(utils.HexToBig("978a846d2")), + GasPrice: assets.NewWei(mustHexToBig(t, "978a846d2")), GasLimit: mustHextoUint32(t, "0xdbba0"), - MaxFeePerGas: assets.NewWei(utils.HexToBig("d0892241d")), - MaxPriorityFeePerGas: assets.NewWei(utils.HexToBig("3b9aca01")), + MaxFeePerGas: assets.NewWei(mustHexToBig(t, "d0892241d")), + MaxPriorityFeePerGas: assets.NewWei(mustHexToBig(t, "3b9aca01")), Type: 0x2, Hash: common.HexToHash("0x754f49f0a2ca7680806d261dd36ee95ac88a81da59fef0b5d8d691478f075d46"), }, }, + { + name: "sample EIP4844 txn", + args: args{ + []byte( + ` + { + "blockHash": "0x3edd900025edab70dde26a52377c3d0a9474c3f540bd0131d58f508711272590", + "blockNumber": "0x50e1d6", + "from": "0x56272f6932e6ae0116d270a2e919d20d3052f206", + "gas": "0x5208", + "gasPrice": "0x17d9abf8b5", + "maxFeePerGas": "0x8bb2c97000", + "maxPriorityFeePerGas": "0x165a0bc00", + "maxFeePerBlobGas": "0xdf8475800", + "hash": "0xa97e14a2e87d322fcb97edc4b25cd976d18963cfad19bfd4b9c8066a6a2d97cf", + "input": "0x", + "nonce": "0x2836", + "to": "0x1803c760451dc8da8935c7b7e47e1c60910e6986", + "transactionIndex": "0x4c", + "value": "0x0", + "type": "0x3", + "accessList": [], + "chainId": "0xaa36a7", + "blobVersionedHashes": [ + "0x01adde6e37a3ba9e2a40052556b51960c2a4cc69c257992ae954c6d4f8d479c2", + "0x0142116f5d1b4b60672ac5b69edb7431ffddb700227d9b4dc9adafe599b38943", + "0x010ba493f0c9891f7109bd29e4914c4e79c7a35530981e746d02df66e5d57056" + ], + "v": "0x1", + "r": "0x82045878948921a0330ea7eb23b74f103f9f353704eaeab358e777bea238bfd", + "s": "0x378128f0fa8059df16cdc95f215f1e669dc81cee7c39b804e6371e486aa1e753", + "yParity": "0x1" + }`, + ), + }, + want: &evmtypes.Transaction{ + GasPrice: assets.NewWei(mustHexToBig(t, "17d9abf8b5")), + GasLimit: mustHextoUint32(t, "0x5208"), + MaxFeePerGas: assets.NewWei(mustHexToBig(t, "8bb2c97000")), + MaxPriorityFeePerGas: assets.NewWei(mustHexToBig(t, "165a0bc00")), + Type: 0x3, + Hash: common.HexToHash("0xa97e14a2e87d322fcb97edc4b25cd976d18963cfad19bfd4b9c8066a6a2d97cf"), + }, + }, { name: "sample parity txn", args: args{[]byte( @@ -756,7 +1069,7 @@ func TestTransaction_UnmarshalJSON(t *testing.T) { }`, )}, want: &evmtypes.Transaction{ - GasPrice: assets.NewWei(utils.HexToBig("4f7915f5")), + GasPrice: assets.NewWei(mustHexToBig(t, "4f7915f5")), GasLimit: mustHextoUint32(t, "0x2dc6c0"), MaxFeePerGas: nil, MaxPriorityFeePerGas: nil, @@ -779,10 +1092,10 @@ func TestTransaction_UnmarshalJSON(t *testing.T) { func TestTransaction_JSONRoundtrip(t *testing.T) { t.Parallel() want := &evmtypes.Transaction{ - GasPrice: assets.NewWei(utils.HexToBig("978a846d2")), + GasPrice: assets.NewWei(mustHexToBig(t, "978a846d2")), GasLimit: mustHextoUint32(t, "0xdbba0"), - MaxFeePerGas: assets.NewWei(utils.HexToBig("d0892241d")), - MaxPriorityFeePerGas: assets.NewWei(utils.HexToBig("3b9aca01")), + MaxFeePerGas: assets.NewWei(mustHexToBig(t, "d0892241d")), + MaxPriorityFeePerGas: assets.NewWei(mustHexToBig(t, "3b9aca01")), Type: evmtypes.TxType(2), Hash: common.HexToHash("0x754f49f0a2ca7680806d261dd36ee95ac88a81da59fef0b5d8d691478f075d46"), } @@ -856,3 +1169,9 @@ func mustHextoUint32(t *testing.T, hx string) uint32 { require.NoError(t, err) return uint32(*temp) } + +func mustHexToBig(t *testing.T, hx string) *big.Int { + n, err := hex.ParseBig(hx) + require.NoError(t, err) + return n +} diff --git a/core/chains/evm/types/nonce.go b/core/chains/evm/types/nonce.go index e9caf98c763..be295bdd2a9 100644 --- a/core/chains/evm/types/nonce.go +++ b/core/chains/evm/types/nonce.go @@ -19,5 +19,5 @@ func (n Nonce) String() string { } func GenerateNextNonce(prev Nonce) Nonce { - return Nonce(prev + 1) + return prev + 1 } diff --git a/core/chains/evm/types/types.go b/core/chains/evm/types/types.go index d0e7292b204..987fd987d3f 100644 --- a/core/chains/evm/types/types.go +++ b/core/chains/evm/types/types.go @@ -13,20 +13,20 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) type Configs interface { - Chains(ids ...relay.ChainID) ([]types.ChainStatus, int, error) + Chains(ids ...string) ([]types.ChainStatus, int, error) Node(name string) (Node, error) - Nodes(chainID relay.ChainID) (nodes []Node, err error) + Nodes(chainID string) (nodes []Node, err error) NodeStatus(name string) (types.NodeStatus, error) } type Node struct { Name string - EVMChainID utils.Big + EVMChainID ubig.Big WSURL null.String HTTPURL null.String SendOnly bool diff --git a/core/utils/big.go b/core/chains/evm/utils/big/big.go similarity index 90% rename from core/utils/big.go rename to core/chains/evm/utils/big/big.go index 69fab223de7..4bb51e27323 100644 --- a/core/utils/big.go +++ b/core/chains/evm/utils/big/big.go @@ -1,4 +1,4 @@ -package utils +package big import ( "database/sql/driver" @@ -9,6 +9,8 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" bigmath "github.com/smartcontractkit/chainlink-common/pkg/utils/big_math" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink-common/pkg/utils/bytes" ) @@ -50,8 +52,8 @@ func (b *BigFloat) Value() *big.Float { // Big stores large integers and can deserialize a variety of inputs. type Big big.Int -// NewBig constructs a Big from *big.Int. -func NewBig(i *big.Int) *Big { +// New constructs a Big from *big.Int. +func New(i *big.Int) *Big { if i != nil { var b big.Int b.Set(i) @@ -60,9 +62,9 @@ func NewBig(i *big.Int) *Big { return nil } -// NewBigI constructs a Big from int64. -func NewBigI(i int64) *Big { - return NewBig(big.NewInt(i)) +// NewI constructs a Big from int64. +func NewI(i int64) *Big { + return New(big.NewInt(i)) } // MarshalText marshals this instance to base 10 number as string. @@ -83,7 +85,7 @@ func (b Big) MarshalJSON() ([]byte, error) { func (b *Big) UnmarshalText(input []byte) error { input = bytes.TrimQuotes(input) str := string(input) - if HasHexPrefix(str) { + if hex.HasPrefix(str) { decoded, err := hexutil.DecodeBig(str) if err != nil { return err @@ -174,15 +176,15 @@ func (b *Big) Int64() int64 { // Add returns the sum of b and c func (b *Big) Add(c *Big) *Big { - return NewBig(bigmath.Add(b.ToInt(), c.ToInt())) + return New(bigmath.Add(b.ToInt(), c.ToInt())) } // Sub returns the differencs between b and c func (b *Big) Sub(c *Big) *Big { - return NewBig(bigmath.Sub(b.ToInt(), c.ToInt())) + return New(bigmath.Sub(b.ToInt(), c.ToInt())) } // Sub returns b % c func (b *Big) Mod(c *Big) *Big { - return NewBig(bigmath.Mod(b.ToInt(), c.ToInt())) + return New(bigmath.Mod(b.ToInt(), c.ToInt())) } diff --git a/core/utils/big_test.go b/core/chains/evm/utils/big/big_test.go similarity index 95% rename from core/utils/big_test.go rename to core/chains/evm/utils/big/big_test.go index e46d46a0651..c4774cf1988 100644 --- a/core/utils/big_test.go +++ b/core/chains/evm/utils/big/big_test.go @@ -1,4 +1,4 @@ -package utils +package big import ( "encoding/json" @@ -198,15 +198,15 @@ func TestBig_Scan(t *testing.T) { input interface{} want *Big }{ - {"zero string", "0", NewBig(big.NewInt(0))}, - {"one string", "1", NewBig(big.NewInt(1))}, + {"zero string", "0", New(big.NewInt(0))}, + {"one string", "1", New(big.NewInt(1))}, { "large string", "115792089237316195423570985008687907853269984665640564039457584007913129639935", - NewBig(uint256Max), + New(uint256Max), }, - {"zero as bytes", []uint8{48}, NewBig(big.NewInt(0))}, - {"small number as bytes", []uint8{49, 52}, NewBig(big.NewInt(14))}, + {"zero as bytes", []uint8{48}, New(big.NewInt(0))}, + {"small number as bytes", []uint8{49, 52}, New(big.NewInt(14))}, { "max number as bytes", []uint8{ @@ -216,7 +216,7 @@ func TestBig_Scan(t *testing.T) { 48, 51, 57, 52, 53, 55, 53, 56, 52, 48, 48, 55, 57, 49, 51, 49, 50, 57, 54, 51, 57, 57, 51, 53, }, - NewBig(uint256Max), + New(uint256Max), }, } for _, test := range tests { diff --git a/core/utils/ethabi.go b/core/chains/evm/utils/ethabi.go similarity index 97% rename from core/utils/ethabi.go rename to core/chains/evm/utils/ethabi.go index 76c2f186e83..61d365933d2 100644 --- a/core/utils/ethabi.go +++ b/core/chains/evm/utils/ethabi.go @@ -12,6 +12,8 @@ import ( "github.com/pkg/errors" "github.com/shopspring/decimal" "github.com/tidwall/gjson" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" ) const ( @@ -115,8 +117,8 @@ func parseDecimalString(input string) (*big.Int, error) { } func parseNumericString(input string) (*big.Int, error) { - if HasHexPrefix(input) { - output, ok := big.NewInt(0).SetString(RemoveHexPrefix(input), 16) + if hex.HasPrefix(input) { + output, ok := big.NewInt(0).SetString(hex.TrimPrefix(input), 16) if !ok { return nil, fmt.Errorf("error parsing hex %s", input) } diff --git a/core/utils/ethabi_test.go b/core/chains/evm/utils/ethabi_test.go similarity index 99% rename from core/utils/ethabi_test.go rename to core/chains/evm/utils/ethabi_test.go index 4cecab48e4c..b99d906eae7 100644 --- a/core/utils/ethabi_test.go +++ b/core/chains/evm/utils/ethabi_test.go @@ -12,6 +12,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" + + commonhex "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" ) func pow2(arg int64) *big.Int { @@ -590,7 +592,7 @@ func EVMTranscodeJSONWithFormat(value gjson.Result, format string) ([]byte, erro case FormatBytes: return EVMTranscodeBytes(value) case FormatPreformatted: - return hex.DecodeString(RemoveHexPrefix(value.Str)) + return hex.DecodeString(commonhex.TrimPrefix(value.Str)) case FormatUint256: data, err := EVMTranscodeUint256(value) if err != nil { diff --git a/core/chains/evm/utils/utils.go b/core/chains/evm/utils/utils.go new file mode 100644 index 00000000000..6784d33cdb7 --- /dev/null +++ b/core/chains/evm/utils/utils.go @@ -0,0 +1,263 @@ +package utils + +import ( + "context" + "crypto/rand" + "fmt" + "math/big" + "sync/atomic" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/jpillora/backoff" + "golang.org/x/crypto/sha3" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" +) + +// EVMWordByteLen the length of an EVM Word Byte +const EVMWordByteLen = 32 + +// ZeroAddress is an address of all zeroes, otherwise in Ethereum as +// 0x0000000000000000000000000000000000000000 +var ZeroAddress = common.Address{} + +// EmptyHash is a hash of all zeroes, otherwise in Ethereum as +// 0x0000000000000000000000000000000000000000000000000000000000000000 +var EmptyHash = common.Hash{} + +func RandomAddress() common.Address { + b := make([]byte, 20) + _, _ = rand.Read(b) // Assignment for errcheck. Only used in tests so we can ignore. + return common.BytesToAddress(b) +} + +func RandomHash() common.Hash { + b := make([]byte, 32) + _, _ = rand.Read(b) // Assignment for errcheck. Only used in tests so we can ignore. + return common.BytesToHash(b) +} + +// IsEmptyAddress checks that the address is empty, synonymous with the zero +// account/address. No logs can come from this address, as there is no contract +// present there. +// +// See https://stackoverflow.com/questions/48219716/what-is-address0-in-solidity +// for the more info on the zero address. +func IsEmptyAddress(addr common.Address) bool { + return addr == ZeroAddress +} + +func RandomBytes32() (r [32]byte) { + b := make([]byte, 32) + _, _ = rand.Read(b[:]) // Assignment for errcheck. Only used in tests so we can ignore. + copy(r[:], b) + return +} + +func Bytes32ToSlice(a [32]byte) (r []byte) { + r = append(r, a[:]...) + return +} + +// Uint256ToBytes is x represented as the bytes of a uint256 +func Uint256ToBytes(x *big.Int) (uint256 []byte, err error) { + if x.Cmp(MaxUint256) > 0 { + return nil, fmt.Errorf("too large to convert to uint256") + } + uint256 = common.LeftPadBytes(x.Bytes(), EVMWordByteLen) + if x.Cmp(big.NewInt(0).SetBytes(uint256)) != 0 { + panic("failed to round-trip uint256 back to source big.Int") + } + return uint256, err +} + +// NewHash return random Keccak256 +func NewHash() common.Hash { + b := make([]byte, 32) + _, err := rand.Read(b) + if err != nil { + panic(err) + } + return common.BytesToHash(b) +} + +// PadByteToHash returns a hash with zeros padded on the left of the given byte. +func PadByteToHash(b byte) common.Hash { + var h [32]byte + h[31] = b + return h +} + +// Uint256ToBytes32 returns the bytes32 encoding of the big int provided +func Uint256ToBytes32(n *big.Int) []byte { + if n.BitLen() > 256 { + panic("vrf.uint256ToBytes32: too big to marshal to uint256") + } + return common.LeftPadBytes(n.Bytes(), 32) +} + +// MustHash returns the keccak256 hash, or panics on failure. +func MustHash(in string) common.Hash { + out, err := Keccak256([]byte(in)) + if err != nil { + panic(err) + } + return common.BytesToHash(out) +} + +// HexToUint256 returns the uint256 represented by s, or an error if it doesn't +// represent one. +func HexToUint256(s string) (*big.Int, error) { + rawNum, err := hexutil.Decode(s) + if err != nil { + return nil, fmt.Errorf("error while parsing %s as hex: %w", s, err) + } + rv := big.NewInt(0).SetBytes(rawNum) // can't be negative number + if err := CheckUint256(rv); err != nil { + return nil, err + } + return rv, nil +} + +var zero = big.NewInt(0) + +// CheckUint256 returns an error if n is out of bounds for a uint256 +func CheckUint256(n *big.Int) error { + if n.Cmp(zero) < 0 || n.Cmp(MaxUint256) >= 0 { + return fmt.Errorf("number out of range for uint256") + } + return nil +} + +// Keccak256 is a simplified interface for the legacy SHA3 implementation that +// Ethereum uses. +func Keccak256(in []byte) ([]byte, error) { + hash := sha3.NewLegacyKeccak256() + _, err := hash.Write(in) + return hash.Sum(nil), err +} + +func Keccak256Fixed(in []byte) [32]byte { + hash := sha3.NewLegacyKeccak256() + // Note this Keccak256 cannot error https://github.com/golang/crypto/blob/master/sha3/sha3.go#L126 + // if we start supporting hashing algos which do, we can change this API to include an error. + hash.Write(in) + var h [32]byte + copy(h[:], hash.Sum(nil)) + return h +} + +// EIP55CapitalizedAddress returns true iff possibleAddressString has the correct +// capitalization for an Ethereum address, per EIP 55 +func EIP55CapitalizedAddress(possibleAddressString string) bool { + possibleAddressString = hex.EnsurePrefix(possibleAddressString) + EIP55Capitalized := common.HexToAddress(possibleAddressString).Hex() + return possibleAddressString == EIP55Capitalized +} + +// ParseEthereumAddress returns addressString as a go-ethereum Address, or an +// error if it's invalid, e.g. if EIP 55 capitalization check fails +func ParseEthereumAddress(addressString string) (common.Address, error) { + if !common.IsHexAddress(addressString) { + return common.Address{}, fmt.Errorf( + "not a valid Ethereum address: %s", addressString) + } + address := common.HexToAddress(addressString) + if !EIP55CapitalizedAddress(addressString) { + return common.Address{}, fmt.Errorf( + "%s treated as Ethereum address, but it has an invalid capitalization! "+ + "The correctly-capitalized address would be %s, but "+ + "check carefully before copying and pasting! ", + addressString, address.Hex()) + } + return address, nil +} + +// NewRedialBackoff is a standard backoff to use for redialling or reconnecting to +// unreachable network endpoints +func NewRedialBackoff() backoff.Backoff { + return backoff.Backoff{ + Min: 1 * time.Second, + Max: 15 * time.Second, + Jitter: true, + } + +} + +// RetryWithBackoff retries the sleeper and backs off if not Done +func RetryWithBackoff(ctx context.Context, fn func() (retry bool)) { + sleeper := NewBackoffSleeper() + sleeper.Reset() + for { + retry := fn() + if !retry { + return + } + + select { + case <-ctx.Done(): + return + case <-time.After(sleeper.After()): + continue + } + } +} + +// NewBackoffSleeper returns a BackoffSleeper that is configured to +// sleep for 0 seconds initially, then backs off from 1 second minimum +// to 10 seconds maximum. +func NewBackoffSleeper() *BackoffSleeper { + return &BackoffSleeper{ + Backoff: backoff.Backoff{ + Min: 1 * time.Second, + Max: 10 * time.Second, + }, + } +} + +// BackoffSleeper is a sleeper that backs off on subsequent attempts. +type BackoffSleeper struct { + backoff.Backoff + beenRun atomic.Bool +} + +// Sleep waits for the given duration, incrementing the back off. +func (bs *BackoffSleeper) Sleep() { + if bs.beenRun.CompareAndSwap(false, true) { + return + } + time.Sleep(bs.Backoff.Duration()) +} + +// After returns the duration for the next stop, and increments the backoff. +func (bs *BackoffSleeper) After() time.Duration { + if bs.beenRun.CompareAndSwap(false, true) { + return 0 + } + return bs.Backoff.Duration() +} + +// Duration returns the current duration value. +func (bs *BackoffSleeper) Duration() time.Duration { + if !bs.beenRun.Load() { + return 0 + } + return bs.ForAttempt(bs.Attempt()) +} + +// Reset resets the backoff intervals. +func (bs *BackoffSleeper) Reset() { + bs.beenRun.Store(false) + bs.Backoff.Reset() +} + +// RandUint256 generates a random bigNum up to 2 ** 256 - 1 +func RandUint256() *big.Int { + n, err := rand.Int(rand.Reader, MaxUint256) + if err != nil { + panic(err) + } + return n +} diff --git a/core/chains/evm/utils/utils_test.go b/core/chains/evm/utils/utils_test.go new file mode 100644 index 00000000000..9e8b44864ad --- /dev/null +++ b/core/chains/evm/utils/utils_test.go @@ -0,0 +1,231 @@ +package utils_test + +import ( + "context" + "math/big" + "strings" + "sync/atomic" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/assert" + "go.uber.org/multierr" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" +) + +func TestKeccak256(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input string + want string + }{ + {"basic", "0xf00b", "0x2433bb36d5f9b14e4fea87c2d32d79abfe34e56808b891e471f4400fca2a336c"}, + {"long input", "0xf00b2433bb36d5f9b14e4fea87c2d32d79abfe34e56808b891e471f4400fca2a336c", "0x6b917c56ad7bea7d09132b9e1e29bb5d9aa7d32d067c638dfa886bbbf6874cdf"}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + input, err := hexutil.Decode(test.input) + assert.NoError(t, err) + result, err := utils.Keccak256(input) + assert.NoError(t, err) + + assert.Equal(t, test.want, hexutil.Encode(result)) + }) + } +} + +func TestUtils_IsEmptyAddress(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + addr common.Address + want bool + }{ + {"zero address", common.Address{}, true}, + {"non-zero address", testutils.NewAddress(), false}, + } + + for _, test := range tests { + test := test + + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + actual := utils.IsEmptyAddress(test.addr) + assert.Equal(t, test.want, actual) + }) + } +} + +// From https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md#test-cases +var testAddresses = []string{ + "0x52908400098527886E0F7030069857D2E4169EE7", + "0x8617E340B3D01FA5F11F306F4090FD50E238070D", + "0xde709f2102306220921060314715629080e2fb77", + "0x27b1fdb04752bbc536007a920d24acb045561c26", + "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", + "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", + "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", + "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", +} + +func TestClient_EIP55CapitalizedAddress(t *testing.T) { + t.Parallel() + + valid := utils.EIP55CapitalizedAddress + for _, address := range testAddresses { + assert.True(t, valid(address)) + assert.False(t, valid(strings.ToLower(address)) && + valid(strings.ToUpper(address))) + } +} + +func TestClient_ParseEthereumAddress(t *testing.T) { + t.Parallel() + + parse := utils.ParseEthereumAddress + for _, address := range testAddresses { + a1, err := parse(address) + assert.NoError(t, err) + no0xPrefix := address[2:] + a2, err := parse(no0xPrefix) + assert.NoError(t, err) + assert.True(t, a1 == a2) + _, lowerErr := parse(strings.ToLower(address)) + _, upperErr := parse(strings.ToUpper(address)) + shouldBeError := multierr.Combine(lowerErr, upperErr) + assert.Error(t, shouldBeError) + assert.True(t, strings.Contains(shouldBeError.Error(), no0xPrefix)) + } + _, notHexErr := parse("0xCeci n'est pas une chaîne hexadécimale") + assert.Error(t, notHexErr) + _, tooLongErr := parse("0x0123456789abcdef0123456789abcdef0123456789abcdef") + assert.Error(t, tooLongErr) +} + +func TestUint256ToBytes(t *testing.T) { + t.Parallel() + + v := big.NewInt(0).Sub(utils.MaxUint256, big.NewInt(1)) + uint256, err := utils.Uint256ToBytes(v) + assert.NoError(t, err) + + b32 := utils.Uint256ToBytes32(v) + assert.Equal(t, uint256, b32) + + large := big.NewInt(0).Add(utils.MaxUint256, big.NewInt(1)) + _, err = utils.Uint256ToBytes(large) + assert.Error(t, err, "too large to convert to uint256") + + negative := big.NewInt(-1) + assert.Panics(t, func() { + _, _ = utils.Uint256ToBytes(negative) + }, "failed to round-trip uint256 back to source big.Int") +} + +func TestCheckUint256(t *testing.T) { + t.Parallel() + + large := big.NewInt(0).Add(utils.MaxUint256, big.NewInt(1)) + err := utils.CheckUint256(large) + assert.Error(t, err, "number out of range for uint256") + + negative := big.NewInt(-123) + err = utils.CheckUint256(negative) + assert.Error(t, err, "number out of range for uint256") + + err = utils.CheckUint256(big.NewInt(123)) + assert.NoError(t, err) +} + +func TestRandUint256(t *testing.T) { + t.Parallel() + + for i := 0; i < 1000; i++ { + uint256 := utils.RandUint256() + assert.NoError(t, utils.CheckUint256(uint256)) + } +} + +func TestHexToUint256(t *testing.T) { + t.Parallel() + + b, err := utils.HexToUint256("0x00") + assert.NoError(t, err) + assert.Zero(t, b.Cmp(big.NewInt(0))) + + b, err = utils.HexToUint256("0xFFFFFFFF") + assert.NoError(t, err) + assert.Zero(t, b.Cmp(big.NewInt(4294967295))) +} + +func TestNewHash(t *testing.T) { + t.Parallel() + + h1 := utils.NewHash() + h2 := utils.NewHash() + assert.NotEqual(t, h1, h2) + assert.NotEqual(t, h1, common.HexToHash("0x0")) + assert.NotEqual(t, h2, common.HexToHash("0x0")) +} + +func TestPadByteToHash(t *testing.T) { + t.Parallel() + + h := utils.PadByteToHash(1) + assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000001", h.String()) +} + +func TestUtils_BackoffSleeper(t *testing.T) { + t.Parallel() + + bs := utils.NewBackoffSleeper() + assert.Equal(t, time.Duration(0), bs.Duration(), "should initially return immediately") + bs.Sleep() + + d := 1 * time.Nanosecond + bs.Min = d + bs.Factor = 2 + assert.Equal(t, d, bs.Duration()) + bs.Sleep() + + d2 := 2 * time.Nanosecond + assert.Equal(t, d2, bs.Duration()) + + bs.Reset() + assert.Equal(t, time.Duration(0), bs.Duration(), "should initially return immediately") +} + +func TestRetryWithBackoff(t *testing.T) { + t.Parallel() + + var counter atomic.Int32 + ctx, cancel := context.WithCancel(testutils.Context(t)) + + utils.RetryWithBackoff(ctx, func() bool { + return false + }) + + retry := func() bool { + return counter.Add(1) < 3 + } + + go utils.RetryWithBackoff(ctx, retry) + + assert.Eventually(t, func() bool { + return counter.Load() == 3 + }, testutils.WaitTimeout(t), testutils.TestInterval) + + cancel() + + utils.RetryWithBackoff(ctx, retry) + assert.Equal(t, int32(4), counter.Load()) +} diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index 4b4c69f1ab6..92936299cdb 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -16,6 +16,7 @@ import ( common "github.com/smartcontractkit/chainlink-common/pkg/chains" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" commonclient "github.com/smartcontractkit/chainlink/v2/common/client" commonconfig "github.com/smartcontractkit/chainlink/v2/common/config" @@ -32,11 +33,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/monitor" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name Chain --output ./mocks/ --case=underscore @@ -126,7 +126,7 @@ type chain struct { } type errChainDisabled struct { - ChainID *utils.Big + ChainID *ubig.Big } func (e errChainDisabled) Error() string { @@ -163,9 +163,8 @@ func (c ChainRelayExtenderConfig) Validate() error { type ChainOpts struct { AppConfig AppConfig - EventBroadcaster pg.EventBroadcaster - MailMon *utils.MailboxMonitor - GasEstimator gas.EvmFeeEstimator + MailMon *mailbox.Monitor + GasEstimator gas.EvmFeeEstimator *sqlx.DB @@ -184,9 +183,7 @@ func (o ChainOpts) Validate() error { if o.AppConfig == nil { err = errors.Join(err, errors.New("nil AppConfig")) } - if o.EventBroadcaster == nil { - err = errors.Join(err, errors.New("nil EventBroadcaster")) - } + if o.MailMon == nil { err = errors.Join(err, errors.New("nil MailMon")) } @@ -477,15 +474,13 @@ func newEthClientFromCfg(cfg evmconfig.NodePool, noNewHeadsThreshold time.Durati var sendonlys []commonclient.SendOnlyNode[*big.Int, evmclient.RPCCLient] for i, node := range nodes { if node.SendOnly != nil && *node.SendOnly { - name := fmt.Sprintf("eth-sendonly-rpc-%d", i) - rpc := evmclient.NewRPCClient(lggr, empty, (*url.URL)(node.HTTPURL), name, int32(i), chainID, + rpc := evmclient.NewRPCClient(lggr, empty, (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, commonclient.Secondary) sendonly := commonclient.NewSendOnlyNode[*big.Int, evmclient.RPCCLient](lggr, (url.URL)(*node.HTTPURL), *node.Name, chainID, rpc) sendonlys = append(sendonlys, sendonly) } else { - name := fmt.Sprintf("eth-primary-rpc-%d", i) - rpc := evmclient.NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), name, int32(i), + rpc := evmclient.NewRPCClient(lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, commonclient.Primary) primaryNode := commonclient.NewNode[*big.Int, *evmtypes.Head, evmclient.RPCCLient](cfg, noNewHeadsThreshold, lggr, (url.URL)(*node.WSURL), (*url.URL)(node.HTTPURL), *node.Name, int32(i), chainID, *node.Order, diff --git a/core/chains/legacyevm/chain_test.go b/core/chains/legacyevm/chain_test.go index 4fcd51c39d9..e639db6e7cc 100644 --- a/core/chains/legacyevm/chain_test.go +++ b/core/chains/legacyevm/chain_test.go @@ -8,12 +8,12 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" "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/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestLegacyChains(t *testing.T) { @@ -33,10 +33,9 @@ func TestLegacyChains(t *testing.T) { func TestChainOpts_Validate(t *testing.T) { type fields struct { - AppConfig legacyevm.AppConfig - EventBroadcaster pg.EventBroadcaster - MailMon *utils.MailboxMonitor - DB *sqlx.DB + AppConfig legacyevm.AppConfig + MailMon *mailbox.Monitor + DB *sqlx.DB } tests := []struct { name string @@ -46,19 +45,17 @@ func TestChainOpts_Validate(t *testing.T) { { name: "valid", fields: fields{ - AppConfig: configtest.NewTestGeneralConfig(t), - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &utils.MailboxMonitor{}, - DB: pgtest.NewSqlxDB(t), + AppConfig: configtest.NewTestGeneralConfig(t), + MailMon: &mailbox.Monitor{}, + DB: pgtest.NewSqlxDB(t), }, }, { name: "invalid", fields: fields{ - AppConfig: nil, - EventBroadcaster: nil, - MailMon: nil, - DB: nil, + AppConfig: nil, + MailMon: nil, + DB: nil, }, wantErr: true, }, @@ -66,10 +63,9 @@ func TestChainOpts_Validate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { o := legacyevm.ChainOpts{ - AppConfig: tt.fields.AppConfig, - EventBroadcaster: tt.fields.EventBroadcaster, - MailMon: tt.fields.MailMon, - DB: tt.fields.DB, + AppConfig: tt.fields.AppConfig, + MailMon: tt.fields.MailMon, + DB: tt.fields.DB, } if err := o.Validate(); (err != nil) != tt.wantErr { t.Errorf("ChainOpts.Validate() error = %v, wantErr %v", err, tt.wantErr) diff --git a/core/chains/legacyevm/mocks/chain.go b/core/chains/legacyevm/mocks/chain.go index 3a686887d76..d8cc4895493 100644 --- a/core/chains/legacyevm/mocks/chain.go +++ b/core/chains/legacyevm/mocks/chain.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -42,6 +42,10 @@ type Chain struct { func (_m *Chain) BalanceMonitor() monitor.BalanceMonitor { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BalanceMonitor") + } + var r0 monitor.BalanceMonitor if rf, ok := ret.Get(0).(func() monitor.BalanceMonitor); ok { r0 = rf() @@ -58,6 +62,10 @@ func (_m *Chain) BalanceMonitor() monitor.BalanceMonitor { func (_m *Chain) Client() client.Client { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Client") + } + var r0 client.Client if rf, ok := ret.Get(0).(func() client.Client); ok { r0 = rf() @@ -74,6 +82,10 @@ func (_m *Chain) Client() client.Client { func (_m *Chain) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -88,6 +100,10 @@ func (_m *Chain) Close() error { func (_m *Chain) Config() config.ChainScopedConfig { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Config") + } + var r0 config.ChainScopedConfig if rf, ok := ret.Get(0).(func() config.ChainScopedConfig); ok { r0 = rf() @@ -104,6 +120,10 @@ func (_m *Chain) Config() config.ChainScopedConfig { func (_m *Chain) GasEstimator() gas.EvmFeeEstimator { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GasEstimator") + } + var r0 gas.EvmFeeEstimator if rf, ok := ret.Get(0).(func() gas.EvmFeeEstimator); ok { r0 = rf() @@ -120,6 +140,10 @@ func (_m *Chain) GasEstimator() gas.EvmFeeEstimator { func (_m *Chain) GetChainStatus(ctx context.Context) (types.ChainStatus, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetChainStatus") + } + var r0 types.ChainStatus var r1 error if rf, ok := ret.Get(0).(func(context.Context) (types.ChainStatus, error)); ok { @@ -144,6 +168,10 @@ func (_m *Chain) GetChainStatus(ctx context.Context) (types.ChainStatus, error) func (_m *Chain) HeadBroadcaster() commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HeadBroadcaster") + } + var r0 commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash] if rf, ok := ret.Get(0).(func() commontypes.HeadBroadcaster[*evmtypes.Head, common.Hash]); ok { r0 = rf() @@ -160,6 +188,10 @@ func (_m *Chain) HeadBroadcaster() commontypes.HeadBroadcaster[*evmtypes.Head, c func (_m *Chain) HeadTracker() commontypes.HeadTracker[*evmtypes.Head, common.Hash] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HeadTracker") + } + var r0 commontypes.HeadTracker[*evmtypes.Head, common.Hash] if rf, ok := ret.Get(0).(func() commontypes.HeadTracker[*evmtypes.Head, common.Hash]); ok { r0 = rf() @@ -176,6 +208,10 @@ func (_m *Chain) HeadTracker() commontypes.HeadTracker[*evmtypes.Head, common.Ha func (_m *Chain) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -192,6 +228,10 @@ func (_m *Chain) HealthReport() map[string]error { func (_m *Chain) ID() *big.Int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ID") + } + var r0 *big.Int if rf, ok := ret.Get(0).(func() *big.Int); ok { r0 = rf() @@ -208,6 +248,10 @@ func (_m *Chain) ID() *big.Int { func (_m *Chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) ([]types.NodeStatus, string, int, error) { ret := _m.Called(ctx, pageSize, pageToken) + if len(ret) == 0 { + panic("no return value specified for ListNodeStatuses") + } + var r0 []types.NodeStatus var r1 string var r2 int @@ -248,6 +292,10 @@ func (_m *Chain) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken func (_m *Chain) LogBroadcaster() log.Broadcaster { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LogBroadcaster") + } + var r0 log.Broadcaster if rf, ok := ret.Get(0).(func() log.Broadcaster); ok { r0 = rf() @@ -264,6 +312,10 @@ func (_m *Chain) LogBroadcaster() log.Broadcaster { func (_m *Chain) LogPoller() logpoller.LogPoller { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LogPoller") + } + var r0 logpoller.LogPoller if rf, ok := ret.Get(0).(func() logpoller.LogPoller); ok { r0 = rf() @@ -280,6 +332,10 @@ func (_m *Chain) LogPoller() logpoller.LogPoller { func (_m *Chain) Logger() logger.Logger { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Logger") + } + var r0 logger.Logger if rf, ok := ret.Get(0).(func() logger.Logger); ok { r0 = rf() @@ -296,6 +352,10 @@ func (_m *Chain) Logger() logger.Logger { func (_m *Chain) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -310,6 +370,10 @@ func (_m *Chain) Name() string { func (_m *Chain) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -324,6 +388,10 @@ func (_m *Chain) Ready() error { func (_m *Chain) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -338,6 +406,10 @@ func (_m *Chain) Start(_a0 context.Context) error { func (_m *Chain) Transact(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { ret := _m.Called(ctx, from, to, amount, balanceCheck) + if len(ret) == 0 { + panic("no return value specified for Transact") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, *big.Int, bool) error); ok { r0 = rf(ctx, from, to, amount, balanceCheck) @@ -352,6 +424,10 @@ func (_m *Chain) Transact(ctx context.Context, from string, to string, amount *b func (_m *Chain) TxManager() txmgr.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TxManager") + } + var r0 txmgr.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] if rf, ok := ret.Get(0).(func() txmgr.TxManager[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee]); ok { r0 = rf() diff --git a/core/chains/legacyevm/mocks/legacy_chain_container.go b/core/chains/legacyevm/mocks/legacy_chain_container.go index 9ebacb890aa..812b95d3697 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type LegacyChainContainer struct { func (_m *LegacyChainContainer) ChainNodeConfigs() types.Configs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainNodeConfigs") + } + var r0 types.Configs if rf, ok := ret.Get(0).(func() types.Configs); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *LegacyChainContainer) ChainNodeConfigs() types.Configs { func (_m *LegacyChainContainer) Get(id string) (legacyevm.Chain, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 legacyevm.Chain var r1 error if rf, ok := ret.Get(0).(func(string) (legacyevm.Chain, error)); ok { @@ -60,6 +68,10 @@ func (_m *LegacyChainContainer) Get(id string) (legacyevm.Chain, error) { func (_m *LegacyChainContainer) Len() int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Len") + } + var r0 int if rf, ok := ret.Get(0).(func() int); ok { r0 = rf() @@ -80,6 +92,10 @@ func (_m *LegacyChainContainer) List(ids ...string) ([]legacyevm.Chain, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for List") + } + var r0 []legacyevm.Chain var r1 error if rf, ok := ret.Get(0).(func(...string) ([]legacyevm.Chain, error)); ok { @@ -106,6 +122,10 @@ func (_m *LegacyChainContainer) List(ids ...string) ([]legacyevm.Chain, error) { func (_m *LegacyChainContainer) Slice() []legacyevm.Chain { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Slice") + } + var r0 []legacyevm.Chain if rf, ok := ret.Get(0).(func() []legacyevm.Chain); ok { r0 = rf() diff --git a/core/cmd/admin_commands.go b/core/cmd/admin_commands.go index 24e78e5e2bb..799709ad205 100644 --- a/core/cmd/admin_commands.go +++ b/core/cmd/admin_commands.go @@ -17,6 +17,8 @@ import ( "github.com/urfave/cli" "go.uber.org/multierr" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -155,7 +157,7 @@ func (p *AdminUsersPresenter) RenderTable(rt RendererTable) error { renderList(adminUsersTableHeaders, rows, rt.Writer) - return utils.JustError(rt.Write([]byte("\n"))) + return cutils.JustError(rt.Write([]byte("\n"))) } type AdminUsersPresenters []AdminUsersPresenter @@ -173,12 +175,12 @@ func (ps AdminUsersPresenters) RenderTable(rt RendererTable) error { } renderList(adminUsersTableHeaders, rows, rt.Writer) - return utils.JustError(rt.Write([]byte("\n"))) + return cutils.JustError(rt.Write([]byte("\n"))) } // ListUsers renders all API users and their roles func (s *Shell) ListUsers(_ *cli.Context) (err error) { - resp, err := s.HTTP.Get("/v2/users/", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/users/", nil) if err != nil { return s.errorOut(err) } @@ -193,7 +195,7 @@ func (s *Shell) ListUsers(_ *cli.Context) (err error) { // CreateUser creates a new user by prompting for email, password, and role func (s *Shell) CreateUser(c *cli.Context) (err error) { - resp, err := s.HTTP.Get("/v2/users/", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/users/", nil) if err != nil { return s.errorOut(err) } @@ -232,7 +234,7 @@ func (s *Shell) CreateUser(c *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - response, err := s.HTTP.Post("/v2/users", buf) + response, err := s.HTTP.Post(s.ctx(), "/v2/users", buf) if err != nil { return s.errorOut(err) } @@ -261,7 +263,7 @@ func (s *Shell) ChangeRole(c *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - response, err := s.HTTP.Patch("/v2/users", buf) + response, err := s.HTTP.Patch(s.ctx(), "/v2/users", buf) if err != nil { return s.errorOut(err) } @@ -281,7 +283,7 @@ func (s *Shell) DeleteUser(c *cli.Context) (err error) { return s.errorOut(errors.New("email flag is empty, must specify an email")) } - response, err := s.HTTP.Delete(fmt.Sprintf("/v2/users/%s", email)) + response, err := s.HTTP.Delete(s.ctx(), fmt.Sprintf("/v2/users/%s", email)) if err != nil { return s.errorOut(err) } @@ -295,8 +297,8 @@ func (s *Shell) DeleteUser(c *cli.Context) (err error) { } // Status will display the health of various services -func (s *Shell) Status(_ *cli.Context) error { - resp, err := s.HTTP.Get("/health?full=1", nil) +func (s *Shell) Status(c *cli.Context) error { + resp, err := s.HTTP.Get(s.ctx(), "/health?full=1", nil) if err != nil { return s.errorOut(err) } @@ -311,6 +313,7 @@ func (s *Shell) Status(_ *cli.Context) error { // Profile will collect pprof metrics and store them in a folder. func (s *Shell) Profile(c *cli.Context) error { + ctx := s.ctx() seconds := c.Uint("seconds") baseDir := c.String("output_dir") @@ -340,7 +343,7 @@ func (s *Shell) Profile(c *cli.Context) error { go func(vt string) { defer wgPprof.Done() uri := fmt.Sprintf("/v2/debug/pprof/%s?seconds=%d", vt, seconds) - resp, err := s.HTTP.Get(uri) + resp, err := s.HTTP.Get(ctx, uri) if err != nil { errs <- fmt.Errorf("error collecting %s: %w", vt, err) return diff --git a/core/cmd/app.go b/core/cmd/app.go index 17a4da85002..8e61380156c 100644 --- a/core/cmd/app.go +++ b/core/cmd/app.go @@ -162,6 +162,17 @@ func NewApp(s *Shell) *cli.App { Usage: "Commands for the node's configuration", Subcommands: initRemoteConfigSubCmds(s), }, + { + Name: "health", + Usage: "Prints a health report", + Action: s.Health, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "json, j", + Usage: "json output", + }, + }, + }, { Name: "jobs", Usage: "Commands for managing Jobs", diff --git a/core/cmd/blocks_commands.go b/core/cmd/blocks_commands.go index 29c9e7642a5..72b0523e18d 100644 --- a/core/cmd/blocks_commands.go +++ b/core/cmd/blocks_commands.go @@ -52,7 +52,7 @@ func (s *Shell) ReplayFromBlock(c *cli.Context) (err error) { } buf := bytes.NewBufferString("{}") - resp, err := s.HTTP.Post( + resp, err := s.HTTP.Post(s.ctx(), fmt.Sprintf( "/v2/replay_from_block/%v?%s", blockNumber, diff --git a/core/cmd/blocks_commands_test.go b/core/cmd/blocks_commands_test.go index d0c0e118f9d..30540748cb1 100644 --- a/core/cmd/blocks_commands_test.go +++ b/core/cmd/blocks_commands_test.go @@ -8,15 +8,15 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_ReplayFromBlock(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = (*utils.Big)(big.NewInt(5)) + c.EVM[0].ChainID = (*ubig.Big)(big.NewInt(5)) c.EVM[0].Enabled = ptr(true) }) diff --git a/core/cmd/bridge_commands.go b/core/cmd/bridge_commands.go index 8389d548c79..398d466c43a 100644 --- a/core/cmd/bridge_commands.go +++ b/core/cmd/bridge_commands.go @@ -91,7 +91,7 @@ func (s *Shell) ShowBridge(c *cli.Context) (err error) { return s.errorOut(errors.New("must pass the name of the bridge to be shown")) } bridgeName := c.Args().First() - resp, err := s.HTTP.Get("/v2/bridge_types/" + bridgeName) + resp, err := s.HTTP.Get(s.ctx(), "/v2/bridge_types/"+bridgeName) if err != nil { return s.errorOut(err) } @@ -115,7 +115,7 @@ func (s *Shell) CreateBridge(c *cli.Context) (err error) { return s.errorOut(err) } - resp, err := s.HTTP.Post("/v2/bridge_types", buf) + resp, err := s.HTTP.Post(s.ctx(), "/v2/bridge_types", buf) if err != nil { return s.errorOut(err) } @@ -134,7 +134,7 @@ func (s *Shell) RemoveBridge(c *cli.Context) (err error) { return s.errorOut(errors.New("must pass the name of the bridge to be removed")) } bridgeName := c.Args().First() - resp, err := s.HTTP.Delete("/v2/bridge_types/" + bridgeName) + resp, err := s.HTTP.Delete(s.ctx(), "/v2/bridge_types/"+bridgeName) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/cosmos_keys_commands.go b/core/cmd/cosmos_keys_commands.go index e951ff37a18..11974198fd6 100644 --- a/core/cmd/cosmos_keys_commands.go +++ b/core/cmd/cosmos_keys_commands.go @@ -1,8 +1,8 @@ package cmd import ( + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/cosmos_keys_commands_test.go b/core/cmd/cosmos_keys_commands_test.go index 2cab11379d0..16609daadc6 100644 --- a/core/cmd/cosmos_keys_commands_test.go +++ b/core/cmd/cosmos_keys_commands_test.go @@ -11,11 +11,11 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "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/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/cosmoskey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/cosmos_transaction_commands.go b/core/cmd/cosmos_transaction_commands.go index 7c53d1ff1da..576a64adfb0 100644 --- a/core/cmd/cosmos_transaction_commands.go +++ b/core/cmd/cosmos_transaction_commands.go @@ -115,7 +115,7 @@ func (s *Shell) CosmosSendNativeToken(c *cli.Context) (err error) { buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Post("/v2/transfers/cosmos", buf) + resp, err := s.HTTP.Post(s.ctx(), "/v2/transfers/cosmos", buf) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/csa_keys_commands.go b/core/cmd/csa_keys_commands.go index 4874176d335..1c0fe54ab09 100644 --- a/core/cmd/csa_keys_commands.go +++ b/core/cmd/csa_keys_commands.go @@ -12,6 +12,7 @@ import ( "github.com/urfave/cli" "go.uber.org/multierr" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -102,12 +103,12 @@ func (ps CSAKeyPresenters) RenderTable(rt RendererTable) error { return err } renderList(headers, rows, rt.Writer) - return utils.JustError(rt.Write([]byte("\n"))) + return cutils.JustError(rt.Write([]byte("\n"))) } // ListCSAKeys retrieves a list of all CSA keys func (s *Shell) ListCSAKeys(_ *cli.Context) (err error) { - resp, err := s.HTTP.Get("/v2/keys/csa", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/csa", nil) if err != nil { return s.errorOut(err) } @@ -122,7 +123,7 @@ func (s *Shell) ListCSAKeys(_ *cli.Context) (err error) { // CreateCSAKey creates a new CSA key func (s *Shell) CreateCSAKey(_ *cli.Context) (err error) { - resp, err := s.HTTP.Post("/v2/keys/csa", nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/csa", nil) if err != nil { return s.errorOut(err) } @@ -164,7 +165,7 @@ func (s *Shell) ImportCSAKey(c *cli.Context) (err error) { query.Set("oldpassword", normalizePassword(string(oldPassword))) exportUrl.RawQuery = query.Encode() - resp, err := s.HTTP.Post(exportUrl.String(), bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), exportUrl.String(), bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -207,7 +208,7 @@ func (s *Shell) ExportCSAKey(c *cli.Context) (err error) { query.Set("newpassword", normalizePassword(string(newPassword))) exportUrl.RawQuery = query.Encode() - resp, err := s.HTTP.Post(exportUrl.String(), nil) + resp, err := s.HTTP.Post(s.ctx(), exportUrl.String(), nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/csa_keys_commands_test.go b/core/cmd/csa_keys_commands_test.go index 869608fa72b..a181922979a 100644 --- a/core/cmd/csa_keys_commands_test.go +++ b/core/cmd/csa_keys_commands_test.go @@ -11,11 +11,11 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "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/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/dkgencrypt_keys_commands.go b/core/cmd/dkgencrypt_keys_commands.go index 6a8334454b8..ddcc80a33be 100644 --- a/core/cmd/dkgencrypt_keys_commands.go +++ b/core/cmd/dkgencrypt_keys_commands.go @@ -1,8 +1,8 @@ package cmd import ( + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/dkgencrypt_keys_commands_test.go b/core/cmd/dkgencrypt_keys_commands_test.go index a7505ce46dc..b4c6d6f6e91 100644 --- a/core/cmd/dkgencrypt_keys_commands_test.go +++ b/core/cmd/dkgencrypt_keys_commands_test.go @@ -11,11 +11,11 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "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/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgencryptkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/dkgsign_keys_commands.go b/core/cmd/dkgsign_keys_commands.go index 6c345ce42a2..b0435450e32 100644 --- a/core/cmd/dkgsign_keys_commands.go +++ b/core/cmd/dkgsign_keys_commands.go @@ -1,8 +1,8 @@ package cmd import ( + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/dkgsign_keys_commands_test.go b/core/cmd/dkgsign_keys_commands_test.go index 1948800d677..717f988b328 100644 --- a/core/cmd/dkgsign_keys_commands_test.go +++ b/core/cmd/dkgsign_keys_commands_test.go @@ -11,11 +11,11 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "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/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/dkgsignkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/eth_keys_commands.go b/core/cmd/eth_keys_commands.go index c13bea80f2f..5adac3b382b 100644 --- a/core/cmd/eth_keys_commands.go +++ b/core/cmd/eth_keys_commands.go @@ -14,6 +14,7 @@ import ( "github.com/urfave/cli" "go.uber.org/multierr" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -123,15 +124,27 @@ type EthKeyPresenter struct { } func (p *EthKeyPresenter) ToRow() []string { + eth := "Unknown" + if p.EthBalance != nil { + eth = p.EthBalance.String() + } + link := "Unknown" + if p.LinkBalance != nil { + link = p.LinkBalance.String() + } + gas := "None" + if p.MaxGasPriceWei != nil { + gas = p.MaxGasPriceWei.String() + } return []string{ p.Address, p.EVMChainID.String(), - p.EthBalance.String(), - p.LinkBalance.String(), + eth, + link, fmt.Sprintf("%v", p.Disabled), p.CreatedAt.String(), p.UpdatedAt.String(), - p.MaxGasPriceWei.String(), + gas, } } @@ -143,7 +156,7 @@ func (p *EthKeyPresenter) RenderTable(rt RendererTable) error { renderList(ethKeysTableHeaders, rows, rt.Writer) - return utils.JustError(rt.Write([]byte("\n"))) + return cutils.JustError(rt.Write([]byte("\n"))) } type EthKeyPresenters []EthKeyPresenter @@ -163,7 +176,7 @@ func (ps EthKeyPresenters) RenderTable(rt RendererTable) error { // ListETHKeys renders the active account address with its ETH & LINK balance func (s *Shell) ListETHKeys(_ *cli.Context) (err error) { - resp, err := s.HTTP.Get("/v2/keys/evm") + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/evm") if err != nil { return s.errorOut(err) @@ -193,7 +206,7 @@ func (s *Shell) CreateETHKey(c *cli.Context) (err error) { } createUrl.RawQuery = query.Encode() - resp, err := s.HTTP.Post(createUrl.String(), nil) + resp, err := s.HTTP.Post(s.ctx(), createUrl.String(), nil) if err != nil { return s.errorOut(err) } @@ -218,7 +231,7 @@ func (s *Shell) DeleteETHKey(c *cli.Context) (err error) { return nil } - resp, err := s.HTTP.Delete("/v2/keys/evm/" + address) + resp, err := s.HTTP.Delete(s.ctx(), "/v2/keys/evm/"+address) if err != nil { return s.errorOut(err) } @@ -277,7 +290,7 @@ func (s *Shell) ImportETHKey(c *cli.Context) (err error) { } importUrl.RawQuery = query.Encode() - resp, err := s.HTTP.Post(importUrl.String(), bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), importUrl.String(), bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -319,7 +332,7 @@ func (s *Shell) ExportETHKey(c *cli.Context) (err error) { query.Set("newpassword", strings.TrimSpace(string(newPassword))) exportUrl.RawQuery = query.Encode() - resp, err := s.HTTP.Post(exportUrl.String(), nil) + resp, err := s.HTTP.Post(s.ctx(), exportUrl.String(), nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } @@ -372,7 +385,7 @@ func (s *Shell) UpdateChainEVMKey(c *cli.Context) (err error) { } chainURL.RawQuery = query.Encode() - resp, err := s.HTTP.Post(chainURL.String(), nil) + resp, err := s.HTTP.Post(s.ctx(), chainURL.String(), nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/eth_keys_commands_test.go b/core/cmd/eth_keys_commands_test.go index 3eb45e27bd0..de40a5bf873 100644 --- a/core/cmd/eth_keys_commands_test.go +++ b/core/cmd/eth_keys_commands_test.go @@ -13,12 +13,14 @@ import ( "github.com/pkg/errors" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "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/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" "github.com/stretchr/testify/assert" @@ -39,7 +41,7 @@ func TestEthKeysPresenter_RenderTable(t *testing.T) { isDisabled = true createdAt = time.Now() updatedAt = time.Now().Add(time.Second) - maxGasPriceWei = utils.NewBigI(12345) + maxGasPriceWei = ubig.NewI(12345) bundleID = cltest.DefaultOCRKeyBundleID buffer = bytes.NewBufferString("") r = cmd.RendererTable{Writer: buffer} @@ -159,8 +161,8 @@ func TestShell_ListETHKeys_Disabled(t *testing.T) { assert.Nil(t, balances[0].LinkBalance) assert.Nil(t, balances[0].MaxGasPriceWei) assert.Equal(t, []string{ - k.Address.String(), "0", "", "0", "false", - balances[0].UpdatedAt.String(), balances[0].CreatedAt.String(), "", + k.Address.String(), "0", "Unknown", "Unknown", "false", + balances[0].UpdatedAt.String(), balances[0].CreatedAt.String(), "None", }, balances[0].ToRow()) } diff --git a/core/cmd/evm_chains_commands_test.go b/core/cmd/evm_chains_commands_test.go index b4891271210..fa6d7bb519c 100644 --- a/core/cmd/evm_chains_commands_test.go +++ b/core/cmd/evm_chains_commands_test.go @@ -8,15 +8,15 @@ import ( "github.com/stretchr/testify/require" client2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "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/utils" ) -func newRandChainID() *utils.Big { - return utils.NewBig(testutils.NewRandomEVMChainID()) +func newRandChainID() *big.Big { + return big.New(testutils.NewRandomEVMChainID()) } func TestShell_IndexEVMChains(t *testing.T) { diff --git a/core/cmd/evm_node_commands_test.go b/core/cmd/evm_node_commands_test.go index 869ef1b9b3e..dae950fce01 100644 --- a/core/cmd/evm_node_commands_test.go +++ b/core/cmd/evm_node_commands_test.go @@ -9,11 +9,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func assertTableRenders(t *testing.T, r *cltest.RendererMock) { @@ -31,15 +31,15 @@ func TestShell_IndexEVMNodes(t *testing.T) { chainID := newRandChainID() node1 := evmcfg.Node{ Name: ptr("Test node 1"), - WSURL: models.MustParseURL("ws://localhost:8546"), - HTTPURL: models.MustParseURL("http://localhost:8546"), + WSURL: commonconfig.MustParseURL("ws://localhost:8546"), + HTTPURL: commonconfig.MustParseURL("http://localhost:8546"), SendOnly: ptr(false), Order: ptr(int32(15)), } node2 := evmcfg.Node{ Name: ptr("Test node 2"), - WSURL: models.MustParseURL("ws://localhost:8547"), - HTTPURL: models.MustParseURL("http://localhost:8547"), + WSURL: commonconfig.MustParseURL("ws://localhost:8547"), + HTTPURL: commonconfig.MustParseURL("http://localhost:8547"), SendOnly: ptr(false), Order: ptr(int32(36)), } diff --git a/core/cmd/evm_transaction_commands.go b/core/cmd/evm_transaction_commands.go index d702bc3b799..28a4fa23a3b 100644 --- a/core/cmd/evm_transaction_commands.go +++ b/core/cmd/evm_transaction_commands.go @@ -11,8 +11,9 @@ import ( "go.uber.org/multierr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "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/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -116,7 +117,7 @@ func (s *Shell) ShowTransaction(c *cli.Context) (err error) { return s.errorOut(errors.New("must pass the hash of the transaction")) } hash := c.Args().First() - resp, err := s.HTTP.Get("/v2/transactions/evm/" + hash) + resp, err := s.HTTP.Get(s.ctx(), "/v2/transactions/evm/"+hash) if err != nil { return s.errorOut(err) } @@ -186,7 +187,7 @@ func (s *Shell) SendEther(c *cli.Context) (err error) { DestinationAddress: destinationAddress, FromAddress: fromAddress, Amount: amount, - EVMChainID: (*utils.Big)(evmChainID), + EVMChainID: (*ubig.Big)(evmChainID), AllowHigherAmounts: c.IsSet("force"), } @@ -197,7 +198,7 @@ func (s *Shell) SendEther(c *cli.Context) (err error) { buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Post("/v2/transfers/evm", buf) + resp, err := s.HTTP.Post(s.ctx(), "/v2/transfers/evm", buf) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/evm_transaction_commands_test.go b/core/cmd/evm_transaction_commands_test.go index 6c079a12495..588e65027f2 100644 --- a/core/cmd/evm_transaction_commands_test.go +++ b/core/cmd/evm_transaction_commands_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -19,8 +20,9 @@ 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/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestShell_IndexTransactions(t *testing.T) { @@ -149,14 +151,15 @@ func TestShell_SendEther_From_Txm(t *testing.T) { // NOTE: FallbackPollInterval is used in this test to quickly create TxAttempts // Testing triggers requires committing transactions and does not work with transactional tests - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(time.Second) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(time.Second) }, withKey(), withMocks(ethMock, key), ) client, r := app.NewShellAndRenderer() db := app.GetSqlxDB() - + cfg := pgtest.NewQConfig(false) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) set := flag.NewFlagSet("sendether", 0) flagSetApplyFromAction(client.SendEther, set, "") @@ -170,21 +173,26 @@ func TestShell_SendEther_From_Txm(t *testing.T) { assert.NoError(t, client.SendEther(c)) - dbEvmTx := txmgr.DbEthTx{} - require.NoError(t, db.Get(&dbEvmTx, `SELECT * FROM evm.txes`)) - require.Equal(t, "100.500000000000000000", dbEvmTx.Value.String()) - require.Equal(t, fromAddress, dbEvmTx.FromAddress) - require.Equal(t, to, dbEvmTx.ToAddress.String()) + evmTxes, err := txStore.GetAllTxes(testutils.Context(t)) + require.NoError(t, err) + require.Len(t, evmTxes, 1) + evmTx := evmTxes[0] + value := assets.Eth(evmTx.Value) + require.Equal(t, "100.500000000000000000", value.String()) + require.Equal(t, fromAddress, evmTx.FromAddress) + require.Equal(t, to, evmTx.ToAddress.String()) output := *r.Renders[0].(*cmd.EthTxPresenter) - assert.Equal(t, &dbEvmTx.FromAddress, output.From) - assert.Equal(t, &dbEvmTx.ToAddress, output.To) - assert.Equal(t, dbEvmTx.Value.String(), output.Value) - assert.Equal(t, fmt.Sprintf("%d", *dbEvmTx.Nonce), output.Nonce) - - var dbEvmTxAttempt txmgr.DbEthTxAttempt - require.NoError(t, db.Get(&dbEvmTxAttempt, `SELECT * FROM evm.tx_attempts`)) - assert.Equal(t, dbEvmTxAttempt.Hash, output.Hash) + assert.Equal(t, &evmTx.FromAddress, output.From) + assert.Equal(t, &evmTx.ToAddress, output.To) + assert.Equal(t, value.String(), output.Value) + assert.Equal(t, fmt.Sprintf("%d", *evmTx.Sequence), output.Nonce) + + attempts, err := txStore.GetAllTxAttempts(testutils.Context(t)) + require.NoError(t, err) + require.Len(t, attempts, 1) + assert.Equal(t, attempts[0].Hash, output.Hash) + } func TestShell_SendEther_From_Txm_WEI(t *testing.T) { @@ -209,13 +217,15 @@ func TestShell_SendEther_From_Txm_WEI(t *testing.T) { // NOTE: FallbackPollInterval is used in this test to quickly create TxAttempts // Testing triggers requires committing transactions and does not work with transactional tests - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(time.Second) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(time.Second) }, withKey(), withMocks(ethMock, key), ) client, r := app.NewShellAndRenderer() db := app.GetSqlxDB() + cfg := pgtest.NewQConfig(false) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) set := flag.NewFlagSet("sendether", 0) flagSetApplyFromAction(client.SendEther, set, "") @@ -236,19 +246,23 @@ func TestShell_SendEther_From_Txm_WEI(t *testing.T) { assert.NoError(t, client.SendEther(c)) - dbEvmTx := txmgr.DbEthTx{} - require.NoError(t, db.Get(&dbEvmTx, `SELECT * FROM evm.txes`)) - require.Equal(t, "1.000000000000000000", dbEvmTx.Value.String()) - require.Equal(t, fromAddress, dbEvmTx.FromAddress) - require.Equal(t, to, dbEvmTx.ToAddress.String()) + evmTxes, err := txStore.GetAllTxes(testutils.Context(t)) + require.NoError(t, err) + require.Len(t, evmTxes, 1) + evmTx := evmTxes[0] + value := assets.Eth(evmTx.Value) + require.Equal(t, "1.000000000000000000", value.String()) + require.Equal(t, fromAddress, evmTx.FromAddress) + require.Equal(t, to, evmTx.ToAddress.String()) output := *r.Renders[0].(*cmd.EthTxPresenter) - assert.Equal(t, &dbEvmTx.FromAddress, output.From) - assert.Equal(t, &dbEvmTx.ToAddress, output.To) - assert.Equal(t, dbEvmTx.Value.String(), output.Value) - assert.Equal(t, fmt.Sprintf("%d", *dbEvmTx.Nonce), output.Nonce) - - var dbEvmTxAttempt txmgr.DbEthTxAttempt - require.NoError(t, db.Get(&dbEvmTxAttempt, `SELECT * FROM evm.tx_attempts`)) - assert.Equal(t, dbEvmTxAttempt.Hash, output.Hash) + assert.Equal(t, &evmTx.FromAddress, output.From) + assert.Equal(t, &evmTx.ToAddress, output.To) + assert.Equal(t, value.String(), output.Value) + assert.Equal(t, fmt.Sprintf("%d", *evmTx.Sequence), output.Nonce) + + attempts, err := txStore.GetAllTxAttempts(testutils.Context(t)) + require.NoError(t, err) + require.Len(t, attempts, 1) + assert.Equal(t, attempts[0].Hash, output.Hash) } diff --git a/core/cmd/forwarders_commands.go b/core/cmd/forwarders_commands.go index 51e90a4390c..2445be5bfec 100644 --- a/core/cmd/forwarders_commands.go +++ b/core/cmd/forwarders_commands.go @@ -14,7 +14,7 @@ import ( "github.com/urfave/cli" "go.uber.org/multierr" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -102,7 +102,7 @@ func (s *Shell) DeleteForwarder(c *cli.Context) (err error) { if !c.Args().Present() { return s.errorOut(errors.New("must pass the forwarder id to be archived")) } - resp, err := s.HTTP.Delete("/v2/nodes/evm/forwarders/" + c.Args().First()) + resp, err := s.HTTP.Delete(s.ctx(), "/v2/nodes/evm/forwarders/"+c.Args().First()) if err != nil { return s.errorOut(err) } @@ -136,14 +136,14 @@ func (s *Shell) TrackForwarder(c *cli.Context) (err error) { } request, err := json.Marshal(web.TrackEVMForwarderRequest{ - EVMChainID: (*utils.Big)(chainID), + EVMChainID: (*ubig.Big)(chainID), Address: address, }) if err != nil { return s.errorOut(err) } - resp, err := s.HTTP.Post("/v2/nodes/evm/forwarders/track", bytes.NewReader(request)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/nodes/evm/forwarders/track", bytes.NewReader(request)) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/forwarders_commands_test.go b/core/cmd/forwarders_commands_test.go index 179216b8e41..b5a96a73aa8 100644 --- a/core/cmd/forwarders_commands_test.go +++ b/core/cmd/forwarders_commands_test.go @@ -10,10 +10,11 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -23,7 +24,7 @@ func TestEVMForwarderPresenter_RenderTable(t *testing.T) { var ( id = "1" address = utils.RandomAddress() - evmChainID = utils.NewBigI(4) + evmChainID = big.NewI(4) createdAt = time.Now() updatedAt = time.Now().Add(time.Second) buffer = bytes.NewBufferString("") diff --git a/core/cmd/jobs_commands.go b/core/cmd/jobs_commands.go index d6e752e1a10..1f9ca33c78e 100644 --- a/core/cmd/jobs_commands.go +++ b/core/cmd/jobs_commands.go @@ -212,7 +212,7 @@ func (s *Shell) ShowJob(c *cli.Context) (err error) { return s.errorOut(errors.New("must provide the id of the job")) } id := c.Args().First() - resp, err := s.HTTP.Get("/v2/jobs/" + id) + resp, err := s.HTTP.Get(s.ctx(), "/v2/jobs/"+id) if err != nil { return s.errorOut(err) } @@ -244,7 +244,7 @@ func (s *Shell) CreateJob(c *cli.Context) (err error) { return s.errorOut(err) } - resp, err := s.HTTP.Post("/v2/jobs", bytes.NewReader(request)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/jobs", bytes.NewReader(request)) if err != nil { return s.errorOut(err) } @@ -273,7 +273,7 @@ func (s *Shell) DeleteJob(c *cli.Context) error { if !c.Args().Present() { return s.errorOut(errors.New("must pass the job id to be archived")) } - resp, err := s.HTTP.Delete("/v2/jobs/" + c.Args().First()) + resp, err := s.HTTP.Delete(s.ctx(), "/v2/jobs/"+c.Args().First()) if err != nil { return s.errorOut(err) } @@ -291,7 +291,7 @@ func (s *Shell) TriggerPipelineRun(c *cli.Context) error { if !c.Args().Present() { return s.errorOut(errors.New("Must pass the job id to trigger a run")) } - resp, err := s.HTTP.Post("/v2/jobs/"+c.Args().First()+"/runs", nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/jobs/"+c.Args().First()+"/runs", nil) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/jobs_commands_test.go b/core/cmd/jobs_commands_test.go index 04908e18ff3..75e95db84ca 100644 --- a/core/cmd/jobs_commands_test.go +++ b/core/cmd/jobs_commands_test.go @@ -9,10 +9,12 @@ import ( "time" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/urfave/cli" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -366,9 +368,10 @@ func TestShell_CreateJobV2(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(100 * time.Millisecond) c.OCR.Enabled = ptr(true) - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = &cltest.DefaultP2PPeerID c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) @@ -403,7 +406,7 @@ func TestShell_DeleteJob(t *testing.T) { t.Parallel() app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(100 * time.Millisecond) c.EVM[0].Enabled = ptr(true) c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) diff --git a/core/cmd/keys_commands.go b/core/cmd/keys_commands.go index 07340c9cf08..7408d168887 100644 --- a/core/cmd/keys_commands.go +++ b/core/cmd/keys_commands.go @@ -105,7 +105,7 @@ func newKeysClient[K keystore.Key, P TableRenderer, P2 ~[]P](typ string, s *Shel // ListKeys retrieves a list of all keys func (cli *keysClient[K, P, P2]) ListKeys(_ *cli.Context) (err error) { - resp, err := cli.HTTP.Get(cli.path, nil) + resp, err := cli.HTTP.Get(cli.ctx(), cli.path, nil) if err != nil { return cli.errorOut(err) } @@ -121,7 +121,7 @@ func (cli *keysClient[K, P, P2]) ListKeys(_ *cli.Context) (err error) { // CreateKey creates a new key func (cli *keysClient[K, P, P2]) CreateKey(_ *cli.Context) (err error) { - resp, err := cli.HTTP.Post(cli.path, nil) + resp, err := cli.HTTP.Post(cli.ctx(), cli.path, nil) if err != nil { return cli.errorOut(err) } @@ -152,7 +152,7 @@ func (cli *keysClient[K, P, P2]) DeleteKey(c *cli.Context) (err error) { queryStr = "?hard=true" } - resp, err := cli.HTTP.Delete(fmt.Sprintf(cli.path+"/%s%s", id, queryStr)) + resp, err := cli.HTTP.Delete(cli.ctx(), fmt.Sprintf(cli.path+"/%s%s", id, queryStr)) if err != nil { return cli.errorOut(err) } @@ -189,7 +189,7 @@ func (cli *keysClient[K, P, P2]) ImportKey(c *cli.Context) (err error) { } normalizedPassword := normalizePassword(string(oldPassword)) - resp, err := cli.HTTP.Post(cli.path+"/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) + resp, err := cli.HTTP.Post(cli.ctx(), cli.path+"/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) if err != nil { return cli.errorOut(err) } @@ -227,7 +227,7 @@ func (cli *keysClient[K, P, P2]) ExportKey(c *cli.Context) (err error) { ID := c.Args().Get(0) normalizedPassword := normalizePassword(string(newPassword)) - resp, err := cli.HTTP.Post(cli.path+"/export/"+ID+"?newpassword="+normalizedPassword, nil) + resp, err := cli.HTTP.Post(cli.ctx(), cli.path+"/export/"+ID+"?newpassword="+normalizedPassword, nil) if err != nil { return cli.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/mocks/prompter.go b/core/cmd/mocks/prompter.go index c0f682d5b9f..a05d24d671b 100644 --- a/core/cmd/mocks/prompter.go +++ b/core/cmd/mocks/prompter.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -13,6 +13,10 @@ type Prompter struct { func (_m *Prompter) IsTerminal() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsTerminal") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -27,6 +31,10 @@ func (_m *Prompter) IsTerminal() bool { func (_m *Prompter) PasswordPrompt(_a0 string) string { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for PasswordPrompt") + } + var r0 string if rf, ok := ret.Get(0).(func(string) string); ok { r0 = rf(_a0) @@ -41,6 +49,10 @@ func (_m *Prompter) PasswordPrompt(_a0 string) string { func (_m *Prompter) Prompt(_a0 string) string { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Prompt") + } + var r0 string if rf, ok := ret.Get(0).(func(string) string); ok { r0 = rf(_a0) diff --git a/core/cmd/ocr-bootstrap-spec.yml b/core/cmd/ocr-bootstrap-spec.yml index 9db118b77cd..058fdeb2c14 100644 --- a/core/cmd/ocr-bootstrap-spec.yml +++ b/core/cmd/ocr-bootstrap-spec.yml @@ -4,7 +4,5 @@ contractAddress = "0x27548a32b9aD5D64c5945EaE9Da5337bc3169D15" externalJobID = "%s" name = "%s" evmChainID = "0" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = true diff --git a/core/cmd/ocr2_keys_commands.go b/core/cmd/ocr2_keys_commands.go index f1df2626fbc..1d469024878 100644 --- a/core/cmd/ocr2_keys_commands.go +++ b/core/cmd/ocr2_keys_commands.go @@ -11,6 +11,7 @@ import ( "github.com/urfave/cli" "go.uber.org/multierr" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -92,7 +93,7 @@ func (p *OCR2KeyBundlePresenter) RenderTable(rt RendererTable) error { } renderList(headers, rows, rt.Writer) - return utils.JustError(rt.Write([]byte("\n"))) + return cutils.JustError(rt.Write([]byte("\n"))) } func (p *OCR2KeyBundlePresenter) ToRow() []string { @@ -121,12 +122,12 @@ func (ps OCR2KeyBundlePresenters) RenderTable(rt RendererTable) error { } renderList(headers, rows, rt.Writer) - return utils.JustError(rt.Write([]byte("\n"))) + return cutils.JustError(rt.Write([]byte("\n"))) } // ListOCR2KeyBundles lists the available OCR2 Key Bundles func (s *Shell) ListOCR2KeyBundles(_ *cli.Context) error { - resp, err := s.HTTP.Get("/v2/keys/ocr2", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/ocr2", nil) if err != nil { return s.errorOut(err) } @@ -148,7 +149,7 @@ func (s *Shell) CreateOCR2KeyBundle(c *cli.Context) error { ) } chainType := c.Args().Get(0) - resp, err := s.HTTP.Post(fmt.Sprintf("/v2/keys/ocr2/%s", chainType), nil) + resp, err := s.HTTP.Post(s.ctx(), fmt.Sprintf("/v2/keys/ocr2/%s", chainType), nil) if err != nil { return s.errorOut(err) } @@ -181,7 +182,7 @@ func (s *Shell) DeleteOCR2KeyBundle(c *cli.Context) error { queryStr = "?hard=true" } - resp, err := s.HTTP.Delete(fmt.Sprintf("/v2/keys/ocr2/%s%s", id, queryStr)) + resp, err := s.HTTP.Delete(s.ctx(), fmt.Sprintf("/v2/keys/ocr2/%s%s", id, queryStr)) if err != nil { return s.errorOut(err) } @@ -217,7 +218,7 @@ func (s *Shell) ImportOCR2Key(c *cli.Context) (err error) { } normalizedPassword := normalizePassword(string(oldPassword)) - resp, err := s.HTTP.Post("/v2/keys/ocr2/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/ocr2/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -254,7 +255,7 @@ func (s *Shell) ExportOCR2Key(c *cli.Context) (err error) { ID := c.Args().Get(0) normalizedPassword := normalizePassword(string(newPassword)) - resp, err := s.HTTP.Post("/v2/keys/ocr2/export/"+ID+"?newpassword="+normalizedPassword, nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/ocr2/export/"+ID+"?newpassword="+normalizedPassword, nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/ocr2_keys_commands_test.go b/core/cmd/ocr2_keys_commands_test.go index dd2ac2544da..5a861fafa7c 100644 --- a/core/cmd/ocr2_keys_commands_test.go +++ b/core/cmd/ocr2_keys_commands_test.go @@ -11,11 +11,11 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "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/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/ocr2vrf_configure_commands.go b/core/cmd/ocr2vrf_configure_commands.go index cf014d5e5dc..06f26ddb6a4 100644 --- a/core/cmd/ocr2vrf_configure_commands.go +++ b/core/cmd/ocr2vrf_configure_commands.go @@ -17,6 +17,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -342,7 +343,7 @@ func (s *Shell) authorizeForwarder(c *cli.Context, db *sqlx.DB, lggr logger.Logg // Create forwarder for management in forwarder_manager.go. orm := forwarders.NewORM(db, lggr, s.Config.Database()) - _, err = orm.CreateForwarder(common.HexToAddress(forwarderAddress), *utils.NewBigI(chainID)) + _, err = orm.CreateForwarder(common.HexToAddress(forwarderAddress), *ubig.NewI(chainID)) if err != nil { return err } diff --git a/core/cmd/ocr_keys_commands.go b/core/cmd/ocr_keys_commands.go index b9343a4a3f3..399333bba93 100644 --- a/core/cmd/ocr_keys_commands.go +++ b/core/cmd/ocr_keys_commands.go @@ -11,6 +11,7 @@ import ( "github.com/urfave/cli" "go.uber.org/multierr" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -91,7 +92,7 @@ func (p *OCRKeyBundlePresenter) RenderTable(rt RendererTable) error { } renderList(headers, rows, rt.Writer) - return utils.JustError(rt.Write([]byte("\n"))) + return cutils.JustError(rt.Write([]byte("\n"))) } func (p *OCRKeyBundlePresenter) ToRow() []string { @@ -107,7 +108,7 @@ type OCRKeyBundlePresenters []OCRKeyBundlePresenter // ListOCRKeyBundles lists the available OCR Key Bundles func (s *Shell) ListOCRKeyBundles(_ *cli.Context) error { - resp, err := s.HTTP.Get("/v2/keys/ocr", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/ocr", nil) if err != nil { return s.errorOut(err) } @@ -135,12 +136,12 @@ func (ps OCRKeyBundlePresenters) RenderTable(rt RendererTable) error { } renderList(headers, rows, rt.Writer) - return utils.JustError(rt.Write([]byte("\n"))) + return cutils.JustError(rt.Write([]byte("\n"))) } // CreateOCR2KeyBundle creates an OCR key bundle and saves it to the keystore func (s *Shell) CreateOCRKeyBundle(_ *cli.Context) error { - resp, err := s.HTTP.Post("/v2/keys/ocr", nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/ocr", nil) if err != nil { return s.errorOut(err) } @@ -173,7 +174,7 @@ func (s *Shell) DeleteOCRKeyBundle(c *cli.Context) error { queryStr = "?hard=true" } - resp, err := s.HTTP.Delete(fmt.Sprintf("/v2/keys/ocr/%s%s", id, queryStr)) + resp, err := s.HTTP.Delete(s.ctx(), fmt.Sprintf("/v2/keys/ocr/%s%s", id, queryStr)) if err != nil { return s.errorOut(err) } @@ -209,7 +210,7 @@ func (s *Shell) ImportOCRKey(c *cli.Context) (err error) { } normalizedPassword := normalizePassword(string(oldPassword)) - resp, err := s.HTTP.Post("/v2/keys/ocr/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/ocr/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -246,7 +247,7 @@ func (s *Shell) ExportOCRKey(c *cli.Context) (err error) { ID := c.Args().Get(0) normalizedPassword := normalizePassword(string(newPassword)) - resp, err := s.HTTP.Post("/v2/keys/ocr/export/"+ID+"?newpassword="+normalizedPassword, nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/ocr/export/"+ID+"?newpassword="+normalizedPassword, nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/ocr_keys_commands_test.go b/core/cmd/ocr_keys_commands_test.go index aeda9006610..f5da3294903 100644 --- a/core/cmd/ocr_keys_commands_test.go +++ b/core/cmd/ocr_keys_commands_test.go @@ -11,11 +11,11 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "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/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocrkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/p2p_keys_commands.go b/core/cmd/p2p_keys_commands.go index 4ef3c349faf..da3bf412a04 100644 --- a/core/cmd/p2p_keys_commands.go +++ b/core/cmd/p2p_keys_commands.go @@ -11,6 +11,7 @@ import ( "github.com/urfave/cli" "go.uber.org/multierr" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -90,7 +91,7 @@ func (p *P2PKeyPresenter) RenderTable(rt RendererTable) error { } renderList(headers, rows, rt.Writer) - return utils.JustError(rt.Write([]byte("\n"))) + return cutils.JustError(rt.Write([]byte("\n"))) } func (p *P2PKeyPresenter) ToRow() []string { @@ -119,12 +120,12 @@ func (ps P2PKeyPresenters) RenderTable(rt RendererTable) error { } renderList(headers, rows, rt.Writer) - return utils.JustError(rt.Write([]byte("\n"))) + return cutils.JustError(rt.Write([]byte("\n"))) } // ListP2PKeys retrieves a list of all P2P keys func (s *Shell) ListP2PKeys(_ *cli.Context) (err error) { - resp, err := s.HTTP.Get("/v2/keys/p2p", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/p2p", nil) if err != nil { return s.errorOut(err) } @@ -139,7 +140,7 @@ func (s *Shell) ListP2PKeys(_ *cli.Context) (err error) { // CreateP2PKey creates a new P2P key func (s *Shell) CreateP2PKey(_ *cli.Context) (err error) { - resp, err := s.HTTP.Post("/v2/keys/p2p", nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/p2p", nil) if err != nil { return s.errorOut(err) } @@ -169,7 +170,7 @@ func (s *Shell) DeleteP2PKey(c *cli.Context) (err error) { queryStr = "?hard=true" } - resp, err := s.HTTP.Delete(fmt.Sprintf("/v2/keys/p2p/%s%s", id, queryStr)) + resp, err := s.HTTP.Delete(s.ctx(), fmt.Sprintf("/v2/keys/p2p/%s%s", id, queryStr)) if err != nil { return s.errorOut(err) } @@ -205,7 +206,7 @@ func (s *Shell) ImportP2PKey(c *cli.Context) (err error) { } normalizedPassword := normalizePassword(string(oldPassword)) - resp, err := s.HTTP.Post("/v2/keys/p2p/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/p2p/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -242,7 +243,7 @@ func (s *Shell) ExportP2PKey(c *cli.Context) (err error) { ID := c.Args().Get(0) normalizedPassword := normalizePassword(string(newPassword)) - resp, err := s.HTTP.Post("/v2/keys/p2p/export/"+ID+"?newpassword="+normalizedPassword, nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/p2p/export/"+ID+"?newpassword="+normalizedPassword, nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } diff --git a/core/cmd/p2p_keys_commands_test.go b/core/cmd/p2p_keys_commands_test.go index 683129fafa7..87269e02711 100644 --- a/core/cmd/p2p_keys_commands_test.go +++ b/core/cmd/p2p_keys_commands_test.go @@ -11,12 +11,12 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "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/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 2e382be4ccf..5ca938b1b40 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" "io" + "log/slog" "net" "net/http" "net/url" @@ -32,6 +33,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -42,7 +44,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/periodicbackup" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" "github.com/smartcontractkit/chainlink/v2/core/services/versioning" @@ -56,6 +57,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/plugins" ) +func init() { + // hack to undo geth's disruption of the std default logger + // remove with geth v1.13.10 + slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, nil))) +} + var ( initGlobalsOnce sync.Once prometheus *ginprom.Prometheus @@ -153,10 +160,8 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G } keyStore := keystore.New(db, utils.GetScryptParams(cfg), appLggr, cfg.Database()) - mailMon := utils.NewMailboxMonitor(cfg.AppID().String()) + mailMon := mailbox.NewMonitor(cfg.AppID().String(), appLggr.Named("Mailbox")) - dbListener := cfg.Database().Listener() - eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), dbListener.MinReconnectInterval(), dbListener.MaxReconnectDuration(), appLggr, cfg.AppID()) loopRegistry := plugins.NewLoopRegistry(appLggr, cfg.Tracing()) mercuryPool := wsrpc.NewPool(appLggr, cache.Config{ @@ -175,7 +180,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G evmFactoryCfg := chainlink.EVMFactoryConfig{ CSAETHKeystore: keyStore, - ChainOpts: legacyevm.ChainOpts{AppConfig: cfg, EventBroadcaster: eventBroadcaster, MailMon: mailMon, DB: db}, + ChainOpts: legacyevm.ChainOpts{AppConfig: cfg, MailMon: mailMon, DB: db}, } // evm always enabled for backward compatibility // TODO BCF-2510 this needs to change in order to clear the path for EVM extraction @@ -225,7 +230,6 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G SqlxDB: db, KeyStore: keyStore, RelayerChainInteroperators: relayChainInterops, - EventBroadcaster: eventBroadcaster, MailMon: mailMon, Logger: appLggr, AuditLogger: auditLogger, @@ -476,11 +480,11 @@ func createServer(handler *gin.Engine, addr string, requestTimeout time.Duration // HTTPClient encapsulates all methods used to interact with a chainlink node API. type HTTPClient interface { - Get(string, ...map[string]string) (*http.Response, error) - Post(string, io.Reader) (*http.Response, error) - Put(string, io.Reader) (*http.Response, error) - Patch(string, io.Reader, ...map[string]string) (*http.Response, error) - Delete(string) (*http.Response, error) + Get(context.Context, string, ...map[string]string) (*http.Response, error) + Post(context.Context, string, io.Reader) (*http.Response, error) + Put(context.Context, string, io.Reader) (*http.Response, error) + Patch(context.Context, string, io.Reader, ...map[string]string) (*http.Response, error) + Delete(context.Context, string) (*http.Response, error) } type authenticatedHTTPClient struct { @@ -514,31 +518,31 @@ func newHttpClient(lggr logger.Logger, insecureSkipVerify bool) *http.Client { } // Get performs an HTTP Get using the authenticated HTTP client's cookie. -func (h *authenticatedHTTPClient) Get(path string, headers ...map[string]string) (*http.Response, error) { - return h.doRequest("GET", path, nil, headers...) +func (h *authenticatedHTTPClient) Get(ctx context.Context, path string, headers ...map[string]string) (*http.Response, error) { + return h.doRequest(ctx, "GET", path, nil, headers...) } // Post performs an HTTP Post using the authenticated HTTP client's cookie. -func (h *authenticatedHTTPClient) Post(path string, body io.Reader) (*http.Response, error) { - return h.doRequest("POST", path, body) +func (h *authenticatedHTTPClient) Post(ctx context.Context, path string, body io.Reader) (*http.Response, error) { + return h.doRequest(ctx, "POST", path, body) } // Put performs an HTTP Put using the authenticated HTTP client's cookie. -func (h *authenticatedHTTPClient) Put(path string, body io.Reader) (*http.Response, error) { - return h.doRequest("PUT", path, body) +func (h *authenticatedHTTPClient) Put(ctx context.Context, path string, body io.Reader) (*http.Response, error) { + return h.doRequest(ctx, "PUT", path, body) } // Patch performs an HTTP Patch using the authenticated HTTP client's cookie. -func (h *authenticatedHTTPClient) Patch(path string, body io.Reader, headers ...map[string]string) (*http.Response, error) { - return h.doRequest("PATCH", path, body, headers...) +func (h *authenticatedHTTPClient) Patch(ctx context.Context, path string, body io.Reader, headers ...map[string]string) (*http.Response, error) { + return h.doRequest(ctx, "PATCH", path, body, headers...) } // Delete performs an HTTP Delete using the authenticated HTTP client's cookie. -func (h *authenticatedHTTPClient) Delete(path string) (*http.Response, error) { - return h.doRequest("DELETE", path, nil) +func (h *authenticatedHTTPClient) Delete(ctx context.Context, path string) (*http.Response, error) { + return h.doRequest(ctx, "DELETE", path, nil) } -func (h *authenticatedHTTPClient) doRequest(verb, path string, body io.Reader, headerArgs ...map[string]string) (*http.Response, error) { +func (h *authenticatedHTTPClient) doRequest(ctx context.Context, verb, path string, body io.Reader, headerArgs ...map[string]string) (*http.Response, error) { var headers map[string]string if len(headerArgs) > 0 { headers = headerArgs[0] @@ -546,7 +550,7 @@ func (h *authenticatedHTTPClient) doRequest(verb, path string, body io.Reader, h headers = map[string]string{} } - request, err := http.NewRequest(verb, h.remoteNodeURL.String()+path, body) + request, err := http.NewRequestWithContext(ctx, verb, h.remoteNodeURL.String()+path, body) if err != nil { return nil, err } @@ -568,7 +572,7 @@ func (h *authenticatedHTTPClient) doRequest(verb, path string, body io.Reader, h } if response.StatusCode == http.StatusUnauthorized && (h.sessionRequest.Email != "" || h.sessionRequest.Password != "") { var cookieerr error - cookie, cookieerr = h.cookieAuth.Authenticate(h.sessionRequest) + cookie, cookieerr = h.cookieAuth.Authenticate(ctx, h.sessionRequest) if cookieerr != nil { return response, err } @@ -586,7 +590,7 @@ func (h *authenticatedHTTPClient) doRequest(verb, path string, body io.Reader, h // future HTTP requests. type CookieAuthenticator interface { Cookie() (*http.Cookie, error) - Authenticate(sessions.SessionRequest) (*http.Cookie, error) + Authenticate(context.Context, sessions.SessionRequest) (*http.Cookie, error) Logout() error } @@ -615,14 +619,14 @@ func (t *SessionCookieAuthenticator) Cookie() (*http.Cookie, error) { } // Authenticate retrieves a session ID via a cookie and saves it to disk. -func (t *SessionCookieAuthenticator) Authenticate(sessionRequest sessions.SessionRequest) (*http.Cookie, error) { +func (t *SessionCookieAuthenticator) Authenticate(ctx context.Context, sessionRequest sessions.SessionRequest) (*http.Cookie, error) { b := new(bytes.Buffer) err := json.NewEncoder(b).Encode(sessionRequest) if err != nil { return nil, err } url := t.config.RemoteNodeURL.String() + "/sessions" - req, err := http.NewRequest("POST", url, b) + req, err := http.NewRequestWithContext(ctx, "POST", url, b) if err != nil { return nil, err } diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index a1f7fdb857c..b970b516413 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -33,11 +33,13 @@ import ( "github.com/jmoiron/sqlx" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/build" "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/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -49,6 +51,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" webPresenters "github.com/smartcontractkit/chainlink/v2/core/web/presenters" + "github.com/smartcontractkit/chainlink/v2/internal/testdb" ) var ErrProfileTooLong = errors.New("requested profile duration too large") @@ -256,13 +259,6 @@ func initLocalSubCmds(s *Shell, safe bool) []cli.Command { // ownerPermsMask are the file permission bits reserved for owner. const ownerPermsMask = os.FileMode(0o700) -// PristineDBName is a clean copy of test DB with migrations. -// Used by heavyweight.FullTestDB* functions. -const ( - PristineDBName = "chainlink_test_pristine" - TestDBNamePrefix = "chainlink_test_" -) - // RunNode starts the Chainlink core. func (s *Shell) RunNode(c *cli.Context) error { if err := s.runNode(c); err != nil { @@ -807,13 +803,13 @@ func dropDanglingTestDBs(lggr logger.Logger, db *sqlx.DB) (err error) { defer wg.Done() for dbname := range ch { lggr.Infof("Dropping old, dangling test database: %q", dbname) - gerr := utils.JustError(db.Exec(fmt.Sprintf(`DROP DATABASE IF EXISTS %s`, dbname))) + gerr := cutils.JustError(db.Exec(fmt.Sprintf(`DROP DATABASE IF EXISTS %s`, dbname))) errCh <- gerr } }() } for _, dbname := range dbs { - if strings.HasPrefix(dbname, TestDBNamePrefix) && !strings.HasSuffix(dbname, "_pristine") { + if strings.HasPrefix(dbname, testdb.TestDBNamePrefix) && !strings.HasSuffix(dbname, "_pristine") { ch <- dbname } } @@ -855,7 +851,7 @@ func randomizeTestDBSequences(db *sqlx.DB) error { } var randNum *big.Int - randNum, err = crand.Int(crand.Reader, utils.NewBigI(10000).ToInt()) + randNum, err = crand.Int(crand.Reader, ubig.NewI(10000).ToInt()) if err != nil { return fmt.Errorf("%s: failed to generate random number", failedToRandomizeTestDBSequencesError{}) } @@ -1010,9 +1006,8 @@ func (s *Shell) CleanupChainTables(c *cli.Context) error { rows, err := db.Query(tablesToDeleteFromQuery, "evm_chain_id") if err != nil { return err - } else if rows.Err() != nil { - return rows.Err() } + defer rows.Close() var tablesToDeleteFrom []string for rows.Next() { @@ -1023,6 +1018,9 @@ func (s *Shell) CleanupChainTables(c *cli.Context) error { } tablesToDeleteFrom = append(tablesToDeleteFrom, schema+"."+name) } + if rows.Err() != nil { + return rows.Err() + } for _, tableName := range tablesToDeleteFrom { query := fmt.Sprintf(`DELETE FROM %s WHERE "evm_chain_id"=$1;`, tableName) @@ -1083,11 +1081,11 @@ func dropAndCreateDB(parsed url.URL) (err error) { } func dropAndCreatePristineDB(db *sqlx.DB, template string) (err error) { - _, err = db.Exec(fmt.Sprintf(`DROP DATABASE IF EXISTS "%s"`, PristineDBName)) + _, err = db.Exec(fmt.Sprintf(`DROP DATABASE IF EXISTS "%s"`, testdb.PristineDBName)) if err != nil { return fmt.Errorf("unable to drop postgres database: %v", err) } - _, err = db.Exec(fmt.Sprintf(`CREATE DATABASE "%s" WITH TEMPLATE "%s"`, PristineDBName, template)) + _, err = db.Exec(fmt.Sprintf(`CREATE DATABASE "%s" WITH TEMPLATE "%s"`, testdb.PristineDBName, template)) if err != nil { return fmt.Errorf("unable to create postgres database: %v", err) } diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index fac2d7f040b..72c2f2b5bbd 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -8,6 +8,9 @@ import ( "testing" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/common/client" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/cmd" @@ -23,7 +26,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" chainlinkmocks "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" evmrelayer "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" @@ -72,8 +74,8 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { s.Password.Keystore = models.NewSecret("dummy") c.EVM[0].Nodes[0].Name = ptr("fake") - c.EVM[0].Nodes[0].HTTPURL = models.MustParseURL("http://fake.com") - c.EVM[0].Nodes[0].WSURL = models.MustParseURL("WSS://fake.com/ws") + c.EVM[0].Nodes[0].HTTPURL = commonconfig.MustParseURL("http://fake.com") + c.EVM[0].Nodes[0].WSURL = commonconfig.MustParseURL("WSS://fake.com/ws") // seems to be needed for config validate c.Insecure.OCRDevelopmentMode = nil }) @@ -87,10 +89,9 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { Logger: lggr, KeyStore: keyStore.Eth(), ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &utils.MailboxMonitor{}, - DB: db, + AppConfig: cfg, + MailMon: &mailbox.Monitor{}, + DB: db, }, } testRelayers := genTestEVMRelayers(t, opts, keyStore) @@ -166,8 +167,8 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { s.Password.Keystore = models.NewSecret("16charlengthp4SsW0rD1!@#_") c.EVM[0].Nodes[0].Name = ptr("fake") - c.EVM[0].Nodes[0].WSURL = models.MustParseURL("WSS://fake.com/ws") - c.EVM[0].Nodes[0].HTTPURL = models.MustParseURL("http://fake.com") + c.EVM[0].Nodes[0].WSURL = commonconfig.MustParseURL("WSS://fake.com/ws") + c.EVM[0].Nodes[0].HTTPURL = commonconfig.MustParseURL("http://fake.com") // seems to be needed for config validate c.Insecure.OCRDevelopmentMode = nil }) @@ -192,10 +193,9 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { Logger: lggr, KeyStore: keyStore.Eth(), ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &utils.MailboxMonitor{}, - DB: db, + AppConfig: cfg, + MailMon: &mailbox.Monitor{}, + DB: db, }, } testRelayers := genTestEVMRelayers(t, opts, keyStore) @@ -418,7 +418,7 @@ func TestShell_RebroadcastTransactions_OutsideRange_Txm(t *testing.T) { assert.NoError(t, c.RebroadcastTransactions(ctx)) - cltest.AssertEthTxAttemptCountStays(t, app.GetSqlxDB(), 1) + cltest.AssertEthTxAttemptCountStays(t, txStore, 1) }) } } diff --git a/core/cmd/shell_remote.go b/core/cmd/shell_remote.go index fa72d21ee6f..aab4a94da6f 100644 --- a/core/cmd/shell_remote.go +++ b/core/cmd/shell_remote.go @@ -11,6 +11,7 @@ import ( "strconv" "strings" + "github.com/gin-gonic/gin" "github.com/manyminds/api2go/jsonapi" "github.com/mitchellh/go-homedir" "github.com/pelletier/go-toml" @@ -109,7 +110,7 @@ func (s *Shell) CreateExternalInitiator(c *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Post("/v2/external_initiators", buf) + resp, err := s.HTTP.Post(s.ctx(), "/v2/external_initiators", buf) if err != nil { return s.errorOut(err) } @@ -130,7 +131,7 @@ func (s *Shell) DeleteExternalInitiator(c *cli.Context) (err error) { return s.errorOut(errors.New("Must pass the name of the external initiator to delete")) } - resp, err := s.HTTP.Delete("/v2/external_initiators/" + c.Args().First()) + resp, err := s.HTTP.Delete(s.ctx(), "/v2/external_initiators/"+c.Args().First()) if err != nil { return s.errorOut(err) } @@ -154,7 +155,7 @@ func (s *Shell) getPage(requestURI string, page int, model interface{}) (err err } uri.RawQuery = q.Encode() - resp, err := s.HTTP.Get(uri.String()) + resp, err := s.HTTP.Get(s.ctx(), uri.String()) if err != nil { return s.errorOut(err) } @@ -179,7 +180,7 @@ func (s *Shell) RemoteLogin(c *cli.Context) error { if err != nil { return s.errorOut(err) } - _, err = s.CookieAuthenticator.Authenticate(sessionRequest) + _, err = s.CookieAuthenticator.Authenticate(s.ctx(), sessionRequest) if err != nil { return s.errorOut(err) } @@ -193,7 +194,7 @@ func (s *Shell) RemoteLogin(c *cli.Context) error { // Logout removes local and remote session. func (s *Shell) Logout(_ *cli.Context) (err error) { - resp, err := s.HTTP.Delete("/sessions") + resp, err := s.HTTP.Delete(s.ctx(), "/sessions") if err != nil { return s.errorOut(err) } @@ -223,7 +224,7 @@ func (s *Shell) ChangePassword(_ *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Patch("/v2/user/password", buf) + resp, err := s.HTTP.Patch(s.ctx(), "/v2/user/password", buf) if err != nil { return s.errorOut(err) } @@ -312,7 +313,7 @@ func (s *Shell) ConfigV2(c *cli.Context) error { } func (s *Shell) configV2Str(userOnly bool) (string, error) { - resp, err := s.HTTP.Get(fmt.Sprintf("/v2/config/v2?userOnly=%t", userOnly)) + resp, err := s.HTTP.Get(s.ctx(), fmt.Sprintf("/v2/config/v2?userOnly=%t", userOnly)) if err != nil { return "", s.errorOut(err) } @@ -350,7 +351,7 @@ func (s *Shell) SetLogLevel(c *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Patch("/v2/log", buf) + resp, err := s.HTTP.Patch(s.ctx(), "/v2/log", buf) if err != nil { return s.errorOut(err) } @@ -382,7 +383,7 @@ func (s *Shell) SetLogSQL(c *cli.Context) (err error) { } buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Patch("/v2/log", buf) + resp, err := s.HTTP.Patch(s.ctx(), "/v2/log", buf) if err != nil { return s.errorOut(err) } @@ -475,7 +476,7 @@ func parseResponse(resp *http.Response) ([]byte, error) { } func (s *Shell) checkRemoteBuildCompatibility(lggr logger.Logger, onlyWarn bool, cliVersion, cliSha string) error { - resp, err := s.HTTP.Get("/v2/build_info") + resp, err := s.HTTP.Get(s.ctx(), "/v2/build_info") if err != nil { lggr.Warnw("Got error querying for version. Remote node version is unknown and CLI may behave in unexpected ways.", "err", err) return nil @@ -511,6 +512,23 @@ func (s *Shell) checkRemoteBuildCompatibility(lggr logger.Logger, onlyWarn bool, return nil } +func (s *Shell) Health(c *cli.Context) error { + mime := gin.MIMEPlain + if c.Bool("json") { + mime = gin.MIMEJSON + } + resp, err := s.HTTP.Get(s.ctx(), "/health", map[string]string{"Accept": mime}) + if err != nil { + return s.errorOut(err) + } + b, err := parseResponse(resp) + if err != nil { + return s.errorOut(err) + } + fmt.Println(string(b)) + return nil +} + // ErrIncompatible is returned when the cli and remote versions are not compatible. type ErrIncompatible struct { CLIVersion, CLISha string diff --git a/core/cmd/shell_remote_test.go b/core/cmd/shell_remote_test.go index 6143d678a90..dbd9968daab 100644 --- a/core/cmd/shell_remote_test.go +++ b/core/cmd/shell_remote_test.go @@ -2,6 +2,7 @@ package cmd_test import ( "bytes" + "context" "errors" "flag" "fmt" @@ -13,12 +14,14 @@ import ( "time" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/kylelemons/godebug/diff" "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/urfave/cli" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -32,7 +35,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/static" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/web" ) @@ -59,10 +61,9 @@ func startNewApplicationV2(t *testing.T, overrideFn func(c *chainlink.Config, s } config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(30 * time.Millisecond) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(30 * time.Millisecond) f := false c.EVM[0].Enabled = &f - c.P2P.V1.Enabled = &f c.P2P.V2.Enabled = &f if overrideFn != nil { @@ -383,7 +384,7 @@ type mockHTTPClient struct { mockSha string } -func (h *mockHTTPClient) Get(path string, headers ...map[string]string) (*http.Response, error) { +func (h *mockHTTPClient) Get(ctx context.Context, path string, headers ...map[string]string) (*http.Response, error) { if path == "/v2/build_info" { // Return mocked response here json := fmt.Sprintf(`{"version":"%s","commitSHA":"%s"}`, h.mockVersion, h.mockSha) @@ -393,23 +394,23 @@ func (h *mockHTTPClient) Get(path string, headers ...map[string]string) (*http.R Body: r, }, nil } - return h.HTTP.Get(path, headers...) + return h.HTTP.Get(ctx, path, headers...) } -func (h *mockHTTPClient) Post(path string, body io.Reader) (*http.Response, error) { - return h.HTTP.Post(path, body) +func (h *mockHTTPClient) Post(ctx context.Context, path string, body io.Reader) (*http.Response, error) { + return h.HTTP.Post(ctx, path, body) } -func (h *mockHTTPClient) Put(path string, body io.Reader) (*http.Response, error) { - return h.HTTP.Put(path, body) +func (h *mockHTTPClient) Put(ctx context.Context, path string, body io.Reader) (*http.Response, error) { + return h.HTTP.Put(ctx, path, body) } -func (h *mockHTTPClient) Patch(path string, body io.Reader, headers ...map[string]string) (*http.Response, error) { - return h.HTTP.Patch(path, body, headers...) +func (h *mockHTTPClient) Patch(ctx context.Context, path string, body io.Reader, headers ...map[string]string) (*http.Response, error) { + return h.HTTP.Patch(ctx, path, body, headers...) } -func (h *mockHTTPClient) Delete(path string) (*http.Response, error) { - return h.HTTP.Delete(path) +func (h *mockHTTPClient) Delete(ctx context.Context, path string) (*http.Response, error) { + return h.HTTP.Delete(ctx, path) } func TestShell_ChangePassword(t *testing.T) { @@ -567,7 +568,8 @@ func TestShell_RunOCRJob_HappyPath(t *testing.T) { app := startNewApplicationV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].Enabled = ptr(true) c.OCR.Enabled = ptr(true) - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = &cltest.DefaultP2PPeerID c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") }, func(opts *startOptions) { @@ -699,7 +701,7 @@ func (FailingAuthenticator) Cookie() (*http.Cookie, error) { } // Authenticate retrieves a session ID via a cookie and saves it to disk. -func (FailingAuthenticator) Authenticate(sessionRequest sessions.SessionRequest) (*http.Cookie, error) { +func (FailingAuthenticator) Authenticate(context.Context, sessions.SessionRequest) (*http.Cookie, error) { return nil, errors.New("no luck") } diff --git a/core/cmd/shell_test.go b/core/cmd/shell_test.go index ade14aa0d8a..f265d5f4787 100644 --- a/core/cmd/shell_test.go +++ b/core/cmd/shell_test.go @@ -38,6 +38,7 @@ import ( func TestTerminalCookieAuthenticator_AuthenticateWithoutSession(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) @@ -54,7 +55,7 @@ func TestTerminalCookieAuthenticator_AuthenticateWithoutSession(t *testing.T) { sr := sessions.SessionRequest{Email: test.email, Password: test.pwd} store := &cmd.MemoryCookieStore{} tca := cmd.NewSessionCookieAuthenticator(cmd.ClientOpts{}, store, logger.TestLogger(t)) - cookie, err := tca.Authenticate(sr) + cookie, err := tca.Authenticate(ctx, sr) assert.Error(t, err) assert.Nil(t, cookie) @@ -68,8 +69,9 @@ func TestTerminalCookieAuthenticator_AuthenticateWithoutSession(t *testing.T) { func TestTerminalCookieAuthenticator_AuthenticateWithSession(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) u := cltest.NewUserWithSession(t, app.AuthenticationProvider()) @@ -87,7 +89,7 @@ func TestTerminalCookieAuthenticator_AuthenticateWithSession(t *testing.T) { sr := sessions.SessionRequest{Email: test.email, Password: test.pwd} store := &cmd.MemoryCookieStore{} tca := cmd.NewSessionCookieAuthenticator(app.NewClientOpts(), store, logger.TestLogger(t)) - cookie, err := tca.Authenticate(sr) + cookie, err := tca.Authenticate(ctx, sr) if test.wantError { assert.Error(t, err) @@ -378,6 +380,17 @@ func TestSetupSolanaRelayer(t *testing.T) { } }) + t2Config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.Solana = solana.TOMLConfigs{ + &solana.TOMLConfig{ + ChainID: ptr[string]("solana-id-1"), + Enabled: ptr(true), + Chain: solcfg.Chain{}, + Nodes: []*solcfg.Node{}, + }, + } + }) + rf := chainlink.RelayerFactory{ Logger: lggr, LoopRegistry: reg, @@ -433,6 +446,23 @@ func TestSetupSolanaRelayer(t *testing.T) { _, err := rf.NewSolana(ks, duplicateConfig.SolanaConfigs()) require.Error(t, err) }) + + t.Run("plugin env parsing fails", func(t *testing.T) { + t.Setenv("CL_SOLANA_CMD", "phony_solana_cmd") + t.Setenv("CL_SOLANA_ENV", "fake_path") + + _, err := rf.NewSolana(ks, t2Config.SolanaConfigs()) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to parse Solana env file") + }) + + t.Run("plugin already registered", func(t *testing.T) { + t.Setenv("CL_SOLANA_CMD", "phony_solana_cmd") + + _, err := rf.NewSolana(ks, tConfig.SolanaConfigs()) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to create Solana LOOP command") + }) } func TestSetupStarkNetRelayer(t *testing.T) { @@ -463,6 +493,17 @@ func TestSetupStarkNetRelayer(t *testing.T) { }, } }) + + t2Config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.Starknet = stkcfg.TOMLConfigs{ + &stkcfg.TOMLConfig{ + ChainID: ptr[string]("starknet-id-3"), + Enabled: ptr(true), + Chain: stkcfg.Chain{}, + Nodes: []*config.Node{}, + }, + } + }) rf := chainlink.RelayerFactory{ Logger: lggr, LoopRegistry: reg, @@ -518,6 +559,23 @@ func TestSetupStarkNetRelayer(t *testing.T) { _, err := rf.NewStarkNet(ks, duplicateConfig.StarknetConfigs()) require.Error(t, err) }) + + t.Run("plugin env parsing fails", func(t *testing.T) { + t.Setenv("CL_STARKNET_CMD", "phony_starknet_cmd") + t.Setenv("CL_STARKNET_ENV", "fake_path") + + _, err := rf.NewStarkNet(ks, t2Config.StarknetConfigs()) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to parse Starknet env file") + }) + + t.Run("plugin already registered", func(t *testing.T) { + t.Setenv("CL_STARKNET_CMD", "phony_starknet_cmd") + + _, err := rf.NewStarkNet(ks, tConfig.StarknetConfigs()) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to create StarkNet LOOP command") + }) } // flagSetApplyFromAction applies the flags from action to the flagSet. diff --git a/core/cmd/solana_keys_commands.go b/core/cmd/solana_keys_commands.go index 4dac505af51..636f8a7014a 100644 --- a/core/cmd/solana_keys_commands.go +++ b/core/cmd/solana_keys_commands.go @@ -1,8 +1,8 @@ package cmd import ( + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/solkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/solana_keys_commands_test.go b/core/cmd/solana_keys_commands_test.go index e72343be45c..d58c3657019 100644 --- a/core/cmd/solana_keys_commands_test.go +++ b/core/cmd/solana_keys_commands_test.go @@ -11,11 +11,11 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "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/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/solkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/solana_transaction_commands.go b/core/cmd/solana_transaction_commands.go index c92cc3e29dd..23e94eee50b 100644 --- a/core/cmd/solana_transaction_commands.go +++ b/core/cmd/solana_transaction_commands.go @@ -105,7 +105,7 @@ func (s *Shell) SolanaSendSol(c *cli.Context) (err error) { buf := bytes.NewBuffer(requestData) - resp, err := s.HTTP.Post("/v2/transfers/solana", buf) + resp, err := s.HTTP.Post(s.ctx(), "/v2/transfers/solana", buf) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/starknet_keys_commands.go b/core/cmd/starknet_keys_commands.go index 3b98a1d11e8..5722e5bd946 100644 --- a/core/cmd/starknet_keys_commands.go +++ b/core/cmd/starknet_keys_commands.go @@ -1,8 +1,8 @@ package cmd import ( + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/starkkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/starknet_keys_commands_test.go b/core/cmd/starknet_keys_commands_test.go index b1fa4d88f05..0cf0065129d 100644 --- a/core/cmd/starknet_keys_commands_test.go +++ b/core/cmd/starknet_keys_commands_test.go @@ -11,11 +11,11 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "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/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/starkkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/cmd/vrf_keys_commands.go b/core/cmd/vrf_keys_commands.go index 1a04ef37c3e..32d32334af5 100644 --- a/core/cmd/vrf_keys_commands.go +++ b/core/cmd/vrf_keys_commands.go @@ -118,7 +118,7 @@ func (ps VRFKeyPresenters) RenderTable(rt RendererTable) error { // CreateVRFKey creates a key in the VRF keystore, protected by the password in // the vrf password file provided when starting the chainlink node. func (s *Shell) CreateVRFKey(_ *cli.Context) error { - resp, err := s.HTTP.Post("/v2/keys/vrf", nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/vrf", nil) if err != nil { return s.errorOut(err) } @@ -154,7 +154,7 @@ func (s *Shell) ImportVRFKey(c *cli.Context) error { } normalizedPassword := normalizePassword(string(oldPassword)) - resp, err := s.HTTP.Post("/v2/keys/vrf/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/vrf/import?oldpassword="+normalizedPassword, bytes.NewReader(keyJSON)) if err != nil { return s.errorOut(err) } @@ -195,7 +195,7 @@ func (s *Shell) ExportVRFKey(c *cli.Context) error { } normalizedPassword := normalizePassword(string(newPassword)) - resp, err := s.HTTP.Post("/v2/keys/vrf/export/"+pk.String()+"?newpassword="+normalizedPassword, nil) + resp, err := s.HTTP.Post(s.ctx(), "/v2/keys/vrf/export/"+pk.String()+"?newpassword="+normalizedPassword, nil) if err != nil { return s.errorOut(errors.Wrap(err, "Could not make HTTP request")) } @@ -248,7 +248,7 @@ func (s *Shell) DeleteVRFKey(c *cli.Context) error { queryStr = "?hard=true" } - resp, err := s.HTTP.Delete(fmt.Sprintf("/v2/keys/vrf/%s%s", id, queryStr)) + resp, err := s.HTTP.Delete(s.ctx(), fmt.Sprintf("/v2/keys/vrf/%s%s", id, queryStr)) if err != nil { return s.errorOut(err) } @@ -276,7 +276,7 @@ func getPublicKey(c *cli.Context) (secp256k1.PublicKey, error) { // ListKeys Lists the keys in the db func (s *Shell) ListVRFKeys(_ *cli.Context) error { - resp, err := s.HTTP.Get("/v2/keys/vrf", nil) + resp, err := s.HTTP.Get(s.ctx(), "/v2/keys/vrf", nil) if err != nil { return s.errorOut(err) } diff --git a/core/cmd/vrf_keys_commands_test.go b/core/cmd/vrf_keys_commands_test.go index a061067771d..f912e861a64 100644 --- a/core/cmd/vrf_keys_commands_test.go +++ b/core/cmd/vrf_keys_commands_test.go @@ -8,14 +8,14 @@ import ( "github.com/urfave/cli" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/web/presenters" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) func TestVRFKeyPresenter_RenderTable(t *testing.T) { diff --git a/core/config/audit_logger_config.go b/core/config/audit_logger_config.go index e5078897722..b83ca5b00d0 100644 --- a/core/config/audit_logger_config.go +++ b/core/config/audit_logger_config.go @@ -1,12 +1,13 @@ package config import ( + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/store/models" ) type AuditLogger interface { Enabled() bool - ForwardToUrl() (models.URL, error) + ForwardToUrl() (commonconfig.URL, error) Environment() string JsonWrapperKey() string Headers() (models.ServiceHeaders, error) diff --git a/core/config/auto_pprof_config.go b/core/config/auto_pprof_config.go index f87777cbbd0..c69ff2c86af 100644 --- a/core/config/auto_pprof_config.go +++ b/core/config/auto_pprof_config.go @@ -1,7 +1,7 @@ package config import ( - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -9,13 +9,13 @@ type AutoPprof interface { BlockProfileRate() int CPUProfileRate() int Enabled() bool - GatherDuration() models.Duration - GatherTraceDuration() models.Duration + GatherDuration() commonconfig.Duration + GatherTraceDuration() commonconfig.Duration GoroutineThreshold() int MaxProfileSize() utils.FileSize MemProfileRate() int MemThreshold() utils.FileSize MutexProfileFraction() int - PollInterval() models.Duration + PollInterval() commonconfig.Duration ProfileRoot() string } diff --git a/core/config/docs/chains-evm.toml b/core/config/docs/chains-evm.toml index 711889b3fa5..53f5cb68529 100644 --- a/core/config/docs/chains-evm.toml +++ b/core/config/docs/chains-evm.toml @@ -14,7 +14,7 @@ BlockBackfillDepth = 10 # Default # BlockBackfillSkip enables skipping of very long backfills. BlockBackfillSkip = false # Default # ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. -# Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix, zksync +# Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix, zksync, scroll ChainType = 'arbitrum' # Example # FinalityDepth is the number of blocks after which an ethereum transaction is considered "final". Note that the default is automatically set based on chain ID so it should not be necessary to change this under normal operation. # BlocksConsideredFinal determines how deeply we look back to ensure that transactions are confirmed onto the longest chain diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index e438f4553fe..95d59cca062 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -88,10 +88,6 @@ LeaseRefreshInterval = '1s' # Default UniConn = true # Default # Logging toggles verbose logging of the raw telemetry messages being sent. Logging = false # Default -# ServerPubKey is the public key of the telemetry server. This field will be removed in a furture version -ServerPubKey = 'test-pub-key' # Example -# URL is where to send telemetry. This field will be removed in a furture version -URL = 'https://prom.test' # Example # BufferSize is the number of telemetry messages to buffer before dropping new ones. BufferSize = 100 # Default # MaxBatchSize is the maximum number of messages to batch into one telemetry request. @@ -394,13 +390,7 @@ CaptureEATelemetry = false # Default # TraceLogging enables trace level logging. TraceLogging = false # Default -# P2P supports multiple networking stack versions. You may configure `[P2P.V1]`, `[P2P.V2]`, or both to run simultaneously. -# If both are configured, then for each link with another peer, V2 networking will be preferred. If V2 does not work, the link will -# automatically fall back to V1. If V2 starts working again later, it will automatically be preferred again. This is useful -# for migrating networks without downtime. Note that the two networking stacks _must not_ be configured to bind to the same IP/port. -# -# Note: P2P.V1 is deprecated will be removed in the future. -# +# P2P has a versioned networking stack. Currenly only `[P2P.V2]` is supported. # All nodes in the OCR network should share the same networking stack. [P2P] # IncomingMessageBufferSize is the per-remote number of incoming @@ -419,50 +409,6 @@ PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' # Example # TraceLogging enables trace level logging. TraceLogging = false # Default -# P2P.V1 is deprecated and will be removed in a future version. -[P2P.V1] -# Enabled enables P2P V1. -Enabled = false # Default -# AnnounceIP should be set as the externally reachable IP address of the Chainlink node. -AnnounceIP = '1.2.3.4' # Example -# AnnouncePort should be set as the externally reachable port of the Chainlink node. -AnnouncePort = 1337 # Example -# BootstrapCheckInterval is the interval at which nodes check connections to bootstrap nodes and reconnect if any of them is lost. -# Setting this to a small value would allow newly joined bootstrap nodes to get more connectivity -# more quickly, which helps to make bootstrap process faster. The cost of this operation is relatively -# cheap. We set this to 1 minute during our test. -BootstrapCheckInterval = '20s' # Default -# DefaultBootstrapPeers is the default set of bootstrap peers. -DefaultBootstrapPeers = ['/dns4/example.com/tcp/1337/p2p/12D3KooWMHMRLQkgPbFSYHwD3NBuwtS1AmxhvKVUrcfyaGDASR4U', '/ip4/1.2.3.4/tcp/9999/p2p/12D3KooWLZ9uTC3MrvKfDpGju6RAQubiMDL7CuJcAgDRTYP7fh7R'] # Example -# DHTAnnouncementCounterUserPrefix can be used to restore the node's -# ability to announce its IP/port on the P2P network after a database -# rollback. Make sure to only increase this value, and *never* decrease it. -# Don't use this variable unless you really know what you're doing, since you -# could semi-permanently exclude your node from the P2P network by -# misconfiguring it. -DHTAnnouncementCounterUserPrefix = 0 # Default -# **ADVANCED** -# DHTLookupInterval is the interval between which we do the expensive peer -# lookup using DHT. -# -# Every DHTLookupInterval failures to open a stream to a peer, we will -# attempt to lookup its IP from DHT -DHTLookupInterval = 10 # Default -# ListenIP is the default IP address to bind to. -ListenIP = '0.0.0.0' # Default -# ListenPort is the port to listen on. If left blank, the node randomly selects a different port each time it boots. It is highly recommended to set this to a static value to avoid network instability. -ListenPort = 1337 # Example -# **ADVANCED** -# NewStreamTimeout is the maximum length of time to wait to open a -# stream before we give up. -# We shouldn't hit this in practice since libp2p will give up fast if -# it can't get a connection, but it is here anyway as a failsafe. -# Set to 0 to disable any timeout on top of what libp2p gives us by default. -NewStreamTimeout = '10s' # Default -# **ADVANCED** -# PeerstoreWriteInterval controls how often the peerstore for the OCR V1 networking stack is persisted to the database. -PeerstoreWriteInterval = '5m' # Default - [P2P.V2] # Enabled enables P2P V2. # Note: V1.Enabled is true by default, so it must be set false in order to run V2 only. @@ -624,3 +570,8 @@ MaxStaleAge = "1h" # Default # LatestReportDeadline controls how long to wait for a response from the # mercury server before retrying. Setting this to zero will wait indefinitely. LatestReportDeadline = "5s" # Default + +# Mercury.TLS controls client settings for when the node talks to traditional web servers or load balancers. +[Mercury.TLS] +# CertFile is the path to a PEM file of trusted root certificate authority certificates +CertFile = "/path/to/client/certs.pem" # Example diff --git a/core/config/docs/defaults.go b/core/config/docs/defaults.go index 8946d75cc65..53e6433a8ef 100644 --- a/core/config/docs/defaults.go +++ b/core/config/docs/defaults.go @@ -4,10 +4,10 @@ import ( "log" "strings" + "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/cfgtest" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" - "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) var ( diff --git a/core/config/docs/docs_test.go b/core/config/docs/docs_test.go index 74fa6682c96..dc1e0f2af12 100644 --- a/core/config/docs/docs_test.go +++ b/core/config/docs/docs_test.go @@ -14,14 +14,13 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/solana" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" + "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config/docs" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/cfgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) func TestDoc(t *testing.T) { @@ -38,12 +37,6 @@ func TestDoc(t *testing.T) { require.NoError(t, err) } - // Except for TelemetryIngress.ServerPubKey and TelemetryIngress.URL as this will be removed in the future - // and its only use is to signal to NOPs that these fields are no longer allowed - emptyString := "" - c.TelemetryIngress.ServerPubKey = &emptyString - c.TelemetryIngress.URL = new(models.URL) - cfgtest.AssertFieldsNotNil(t, c) var defaults chainlink.Config diff --git a/core/config/env/env.go b/core/config/env/env.go index ea84a50b754..f22310a6cf8 100644 --- a/core/config/env/env.go +++ b/core/config/env/env.go @@ -1,6 +1,7 @@ package env import ( + "fmt" "os" "strings" @@ -8,12 +9,24 @@ import ( ) var ( - Config = Var("CL_CONFIG") + Config = Var("CL_CONFIG") + DatabaseAllowSimplePasswords = Var("CL_DATABASE_ALLOW_SIMPLE_PASSWORDS") + DatabaseURL = Secret("CL_DATABASE_URL") + DatabaseBackupURL = Secret("CL_DATABASE_BACKUP_URL") + PasswordKeystore = Secret("CL_PASSWORD_KEYSTORE") + PasswordVRF = Secret("CL_PASSWORD_VRF") + PyroscopeAuthToken = Secret("CL_PYROSCOPE_AUTH_TOKEN") + PrometheusAuthToken = Secret("CL_PROMETHEUS_AUTH_TOKEN") + ThresholdKeyShare = Secret("CL_THRESHOLD_KEY_SHARE") + // Migrations env vars + EVMChainIDNotNullMigration0195 = "CL_EVM_CHAINID_NOT_NULL_MIGRATION_0195" +) - // LOOPP commands and vars - MedianPluginCmd = Var("CL_MEDIAN_CMD") - SolanaPluginCmd = Var("CL_SOLANA_CMD") - StarknetPluginCmd = Var("CL_STARKNET_CMD") +// LOOPP commands and vars +var ( + MedianPlugin = NewPlugin("median") + SolanaPlugin = NewPlugin("solana") + StarknetPlugin = NewPlugin("starknet") // PrometheusDiscoveryHostName is the externally accessible hostname // published by the node in the `/discovery` endpoint. Generally, it is expected to match // the public hostname of node. @@ -22,22 +35,13 @@ var ( // In house we observed that the resolved value of os.Hostname was not accessible to // outside of the given pod PrometheusDiscoveryHostName = Var("CL_PROMETHEUS_DISCOVERY_HOSTNAME") - // EnvLooopHostName is the hostname used for HTTP communication between the + // LOOPPHostName is the hostname used for HTTP communication between the // node and LOOPps. In most cases this does not need to be set explicitly. LOOPPHostName = Var("CL_LOOPP_HOSTNAME") // Work around for Solana LOOPPs configured with zero values. MinOCR2MaxDurationQuery = Var("CL_MIN_OCR2_MAX_DURATION_QUERY") - - DatabaseAllowSimplePasswords = Var("CL_DATABASE_ALLOW_SIMPLE_PASSWORDS") - DatabaseURL = Secret("CL_DATABASE_URL") - DatabaseBackupURL = Secret("CL_DATABASE_BACKUP_URL") - PasswordKeystore = Secret("CL_PASSWORD_KEYSTORE") - PasswordVRF = Secret("CL_PASSWORD_VRF") - PyroscopeAuthToken = Secret("CL_PYROSCOPE_AUTH_TOKEN") - PrometheusAuthToken = Secret("CL_PROMETHEUS_AUTH_TOKEN") - ThresholdKeyShare = Secret("CL_THRESHOLD_KEY_SHARE") - // Migrations env vars - EVMChainIDNotNullMigration0195 = "CL_EVM_CHAINID_NOT_NULL_MIGRATION_0195" + // PipelineOvertime is an undocumented escape hatch for overriding the default padding in pipeline executions. + PipelineOvertime = Var("CL_PIPELINE_OVERTIME") ) type Var string @@ -52,3 +56,16 @@ func (e Var) IsTrue() bool { return strings.ToLower(e.Get()) == "true" } type Secret string func (e Secret) Get() models.Secret { return models.Secret(os.Getenv(string(e))) } + +type Plugin struct { + Cmd Var + Env Var +} + +func NewPlugin(kind string) Plugin { + kind = strings.ToUpper(kind) + return Plugin{ + Cmd: Var(fmt.Sprintf("CL_%s_CMD", kind)), + Env: Var(fmt.Sprintf("CL_%s_ENV", kind)), + } +} diff --git a/core/config/env/env_test.go b/core/config/env/env_test.go new file mode 100644 index 00000000000..b6638758d6f --- /dev/null +++ b/core/config/env/env_test.go @@ -0,0 +1,24 @@ +package env + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNewPlugin(t *testing.T) { + for _, tt := range []struct { + name string + kind string + exp Plugin + }{ + {"lower", "foo", Plugin{Cmd: "CL_FOO_CMD", Env: "CL_FOO_ENV"}}, + {"upper", "BAR", Plugin{Cmd: "CL_BAR_CMD", Env: "CL_BAR_ENV"}}, + {"mixed", "Baz", Plugin{Cmd: "CL_BAZ_CMD", Env: "CL_BAZ_ENV"}}, + } { + t.Run(tt.name, func(t *testing.T) { + got := NewPlugin(tt.kind) + require.Equal(t, tt.exp, got) + }) + } +} diff --git a/core/config/job_pipeline_config.go b/core/config/job_pipeline_config.go index 65010fc48c7..d4a01dbed03 100644 --- a/core/config/job_pipeline_config.go +++ b/core/config/job_pipeline_config.go @@ -3,12 +3,12 @@ package config import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) type JobPipeline interface { DefaultHTTPLimit() int64 - DefaultHTTPTimeout() models.Duration + DefaultHTTPTimeout() commonconfig.Duration MaxRunDuration() time.Duration MaxSuccessfulRuns() uint64 ReaperInterval() time.Duration diff --git a/core/config/mercury_config.go b/core/config/mercury_config.go index e530af6338f..1210fd282ef 100644 --- a/core/config/mercury_config.go +++ b/core/config/mercury_config.go @@ -3,7 +3,7 @@ package config import ( "time" - ocr2models "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) type MercuryCache interface { @@ -12,7 +12,12 @@ type MercuryCache interface { LatestReportDeadline() time.Duration } +type MercuryTLS interface { + CertFile() string +} + type Mercury interface { - Credentials(credName string) *ocr2models.MercuryCredentials + Credentials(credName string) *types.MercuryCredentials Cache() MercuryCache + TLS() MercuryTLS } diff --git a/core/config/mocks/telemetry_ingress.go b/core/config/mocks/telemetry_ingress.go index 59f4ed10dad..1a21c89e9ad 100644 --- a/core/config/mocks/telemetry_ingress.go +++ b/core/config/mocks/telemetry_ingress.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -7,8 +7,6 @@ import ( mock "github.com/stretchr/testify/mock" time "time" - - url "net/url" ) // TelemetryIngress is an autogenerated mock type for the TelemetryIngress type @@ -20,6 +18,10 @@ type TelemetryIngress struct { func (_m *TelemetryIngress) BufferSize() uint { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BufferSize") + } + var r0 uint if rf, ok := ret.Get(0).(func() uint); ok { r0 = rf() @@ -34,6 +36,10 @@ func (_m *TelemetryIngress) BufferSize() uint { func (_m *TelemetryIngress) Endpoints() []config.TelemetryIngressEndpoint { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Endpoints") + } + var r0 []config.TelemetryIngressEndpoint if rf, ok := ret.Get(0).(func() []config.TelemetryIngressEndpoint); ok { r0 = rf() @@ -50,6 +56,10 @@ func (_m *TelemetryIngress) Endpoints() []config.TelemetryIngressEndpoint { func (_m *TelemetryIngress) Logging() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Logging") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -64,6 +74,10 @@ func (_m *TelemetryIngress) Logging() bool { func (_m *TelemetryIngress) MaxBatchSize() uint { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for MaxBatchSize") + } + var r0 uint if rf, ok := ret.Get(0).(func() uint); ok { r0 = rf() @@ -78,6 +92,10 @@ func (_m *TelemetryIngress) MaxBatchSize() uint { func (_m *TelemetryIngress) SendInterval() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SendInterval") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -92,6 +110,10 @@ func (_m *TelemetryIngress) SendInterval() time.Duration { func (_m *TelemetryIngress) SendTimeout() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SendTimeout") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -102,40 +124,14 @@ func (_m *TelemetryIngress) SendTimeout() time.Duration { return r0 } -// ServerPubKey provides a mock function with given fields: -func (_m *TelemetryIngress) ServerPubKey() string { - ret := _m.Called() - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// URL provides a mock function with given fields: -func (_m *TelemetryIngress) URL() *url.URL { - ret := _m.Called() - - var r0 *url.URL - if rf, ok := ret.Get(0).(func() *url.URL); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*url.URL) - } - } - - return r0 -} - // UniConn provides a mock function with given fields: func (_m *TelemetryIngress) UniConn() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for UniConn") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -150,6 +146,10 @@ func (_m *TelemetryIngress) UniConn() bool { func (_m *TelemetryIngress) UseBatchSend() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for UseBatchSend") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() diff --git a/core/config/mocks/telemetry_ingress_endpoint.go b/core/config/mocks/telemetry_ingress_endpoint.go index 7aa6f46aa2b..08432cfe0ee 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type TelemetryIngressEndpoint struct { func (_m *TelemetryIngressEndpoint) ChainID() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ChainID") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -31,6 +35,10 @@ func (_m *TelemetryIngressEndpoint) ChainID() string { func (_m *TelemetryIngressEndpoint) Network() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Network") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -45,6 +53,10 @@ func (_m *TelemetryIngressEndpoint) Network() string { func (_m *TelemetryIngressEndpoint) ServerPubKey() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ServerPubKey") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -59,6 +71,10 @@ func (_m *TelemetryIngressEndpoint) ServerPubKey() string { func (_m *TelemetryIngressEndpoint) URL() *url.URL { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for URL") + } + var r0 *url.URL if rf, ok := ret.Get(0).(func() *url.URL); ok { r0 = rf() diff --git a/core/config/p2p_config.go b/core/config/p2p_config.go index 30693b3a259..4a7ec284173 100644 --- a/core/config/p2p_config.go +++ b/core/config/p2p_config.go @@ -1,15 +1,11 @@ package config import ( - ocrnetworking "github.com/smartcontractkit/libocr/networking" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) type P2P interface { V2() V2 - V1() V1 - NetworkStack() (n ocrnetworking.NetworkingStack) PeerID() p2pkey.PeerID IncomingMessageBufferSize() int OutgoingMessageBufferSize() int diff --git a/core/config/p2p_v1_config.go b/core/config/p2p_v1_config.go deleted file mode 100644 index 2e138285182..00000000000 --- a/core/config/p2p_v1_config.go +++ /dev/null @@ -1,20 +0,0 @@ -package config - -import ( - "net" - "time" -) - -type V1 interface { - Enabled() bool - AnnounceIP() net.IP - AnnouncePort() uint16 - DefaultBootstrapPeers() ([]string, error) - DHTAnnouncementCounterUserPrefix() uint32 - ListenIP() net.IP - ListenPort() uint16 - NewStreamTimeout() time.Duration - BootstrapCheckInterval() time.Duration - DHTLookupInterval() int - PeerstoreWriteInterval() time.Duration -} diff --git a/core/config/p2p_v2_config.go b/core/config/p2p_v2_config.go index 7b4a3c05fc4..ff640786ed2 100644 --- a/core/config/p2p_v2_config.go +++ b/core/config/p2p_v2_config.go @@ -1,16 +1,16 @@ package config import ( - ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" ) type V2 interface { Enabled() bool AnnounceAddresses() []string DefaultBootstrappers() (locators []ocrcommontypes.BootstrapperLocator) - DeltaDial() models.Duration - DeltaReconcile() models.Duration + DeltaDial() commonconfig.Duration + DeltaReconcile() commonconfig.Duration ListenAddresses() []string } diff --git a/core/config/telemetry_ingress_config.go b/core/config/telemetry_ingress_config.go index f6c9fa3f858..a4923391011 100644 --- a/core/config/telemetry_ingress_config.go +++ b/core/config/telemetry_ingress_config.go @@ -16,9 +16,6 @@ type TelemetryIngress interface { SendTimeout() time.Duration UseBatchSend() bool Endpoints() []TelemetryIngressEndpoint - - ServerPubKey() string // Deprecated: Use TelemetryIngressEndpoint.ServerPubKey instead, this field will be removed in future versions - URL() *url.URL // Deprecated: Use TelemetryIngressEndpoint.URL instead, this field will be removed in future versions } //go:generate mockery --quiet --name TelemetryIngressEndpoint --output ./mocks/ --case=underscore --filename telemetry_ingress_endpoint.go diff --git a/core/config/toml/types.go b/core/config/toml/types.go index c420d7f3f47..7b4656da1f6 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -13,8 +13,8 @@ import ( "go.uber.org/zap/zapcore" ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" - ocrnetworking "github.com/smartcontractkit/libocr/networking" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/parse" @@ -35,7 +35,7 @@ type Core struct { AppID uuid.UUID `toml:"-"` // random or test InsecureFastScrypt *bool RootDir *string - ShutdownGracePeriod *models.Duration + ShutdownGracePeriod *commonconfig.Duration Feature Feature `toml:",omitempty"` Database Database `toml:",omitempty"` @@ -311,9 +311,9 @@ func (f *Feature) setFrom(f2 *Feature) { } type Database struct { - DefaultIdleInTxSessionTimeout *models.Duration - DefaultLockTimeout *models.Duration - DefaultQueryTimeout *models.Duration + DefaultIdleInTxSessionTimeout *commonconfig.Duration + DefaultLockTimeout *commonconfig.Duration + DefaultQueryTimeout *commonconfig.Duration Dialect dialects.DialectName `toml:"-"` LogQueries *bool MaxIdleConns *int64 @@ -354,9 +354,9 @@ func (d *Database) setFrom(f *Database) { } type DatabaseListener struct { - MaxReconnectDuration *models.Duration - MinReconnectInterval *models.Duration - FallbackPollInterval *models.Duration + MaxReconnectDuration *commonconfig.Duration + MinReconnectInterval *commonconfig.Duration + FallbackPollInterval *commonconfig.Duration } func (d *DatabaseListener) setFrom(f *DatabaseListener) { @@ -373,8 +373,8 @@ func (d *DatabaseListener) setFrom(f *DatabaseListener) { type DatabaseLock struct { Enabled *bool - LeaseDuration *models.Duration - LeaseRefreshInterval *models.Duration + LeaseDuration *commonconfig.Duration + LeaseRefreshInterval *commonconfig.Duration } func (l *DatabaseLock) Mode() string { @@ -409,7 +409,7 @@ func (l *DatabaseLock) setFrom(f *DatabaseLock) { // Note: url is stored in Secrets.DatabaseBackupURL type DatabaseBackup struct { Dir *string - Frequency *models.Duration + Frequency *commonconfig.Duration Mode *config.DatabaseBackupMode OnVersionUpgrade *bool } @@ -434,19 +434,16 @@ type TelemetryIngress struct { Logging *bool BufferSize *uint16 MaxBatchSize *uint16 - SendInterval *models.Duration - SendTimeout *models.Duration + SendInterval *commonconfig.Duration + SendTimeout *commonconfig.Duration UseBatchSend *bool Endpoints []TelemetryIngressEndpoint `toml:",omitempty"` - - URL *models.URL `toml:",omitempty"` // Deprecated: Use TelemetryIngressEndpoint.URL instead, this field will be removed in future versions - ServerPubKey *string `toml:",omitempty"` // Deprecated: Use TelemetryIngressEndpoint.ServerPubKey instead, this field will be removed in future versions } type TelemetryIngressEndpoint struct { Network *string ChainID *string - URL *models.URL + URL *commonconfig.URL ServerPubKey *string } @@ -475,31 +472,11 @@ func (t *TelemetryIngress) setFrom(f *TelemetryIngress) { if v := f.Endpoints; v != nil { t.Endpoints = v } - if v := f.ServerPubKey; v != nil { - t.ServerPubKey = v - } - if v := f.URL; v != nil { - t.URL = v - } -} - -func (t *TelemetryIngress) ValidateConfig() (err error) { - if (!t.URL.IsZero() || *t.ServerPubKey != "") && len(t.Endpoints) > 0 { - return configutils.ErrInvalid{Name: "URL", Value: t.URL.String(), - Msg: `Cannot set both TelemetryIngress.URL and TelemetryIngress.ServerPubKey alongside TelemetryIngress.Endpoints. Please use only TelemetryIngress.Endpoints: - [[TelemetryIngress.Endpoints]] - Network = '...' # e.g. EVM. Solana, Starknet, Cosmos - ChainID = '...' # e.g. 1, 5, devnet, mainnet-beta - URL = '...' - ServerPubKey = '...'`} - } - - return nil } type AuditLogger struct { Enabled *bool - ForwardToUrl *models.URL + ForwardToUrl *commonconfig.URL JsonWrapperKey *string Headers *[]models.ServiceHeader } @@ -598,15 +575,15 @@ func (l *LogFile) setFrom(f *LogFile) { type WebServer struct { AuthenticationMethod *string AllowOrigins *string - BridgeResponseURL *models.URL - BridgeCacheTTL *models.Duration - HTTPWriteTimeout *models.Duration + BridgeResponseURL *commonconfig.URL + BridgeCacheTTL *commonconfig.Duration + HTTPWriteTimeout *commonconfig.Duration HTTPPort *uint16 SecureCookies *bool - SessionTimeout *models.Duration - SessionReaperExpiration *models.Duration + SessionTimeout *commonconfig.Duration + SessionReaperExpiration *commonconfig.Duration HTTPMaxSize *utils.FileSize - StartTimeout *models.Duration + StartTimeout *commonconfig.Duration ListenIP *net.IP LDAP WebServerLDAP `toml:",omitempty"` @@ -709,9 +686,9 @@ func (w *WebServerMFA) setFrom(f *WebServerMFA) { type WebServerRateLimit struct { Authenticated *int64 - AuthenticatedPeriod *models.Duration + AuthenticatedPeriod *commonconfig.Duration Unauthenticated *int64 - UnauthenticatedPeriod *models.Duration + UnauthenticatedPeriod *commonconfig.Duration } func (w *WebServerRateLimit) setFrom(f *WebServerRateLimit) { @@ -761,8 +738,8 @@ func (w *WebServerTLS) setFrom(f *WebServerTLS) { type WebServerLDAP struct { ServerTLS *bool - SessionTimeout *models.Duration - QueryTimeout *models.Duration + SessionTimeout *commonconfig.Duration + QueryTimeout *commonconfig.Duration BaseUserAttr *string BaseDN *string UsersDN *string @@ -774,9 +751,9 @@ type WebServerLDAP struct { RunUserGroupCN *string ReadUserGroupCN *string UserApiTokenEnabled *bool - UserAPITokenDuration *models.Duration - UpstreamSyncInterval *models.Duration - UpstreamSyncRateLimit *models.Duration + UserAPITokenDuration *commonconfig.Duration + UpstreamSyncInterval *commonconfig.Duration + UpstreamSyncRateLimit *commonconfig.Duration } func (w *WebServerLDAP) setFrom(f *WebServerLDAP) { @@ -865,10 +842,10 @@ func (w *WebServerSecrets) SetFrom(f *WebServerSecrets) error { type JobPipeline struct { ExternalInitiatorsEnabled *bool - MaxRunDuration *models.Duration + MaxRunDuration *commonconfig.Duration MaxSuccessfulRuns *uint64 - ReaperInterval *models.Duration - ReaperThreshold *models.Duration + ReaperInterval *commonconfig.Duration + ReaperThreshold *commonconfig.Duration ResultWriteQueueDepth *uint32 HTTPRequest JobPipelineHTTPRequest `toml:",omitempty"` @@ -898,7 +875,7 @@ func (j *JobPipeline) setFrom(f *JobPipeline) { } type JobPipelineHTTPRequest struct { - DefaultTimeout *models.Duration + DefaultTimeout *commonconfig.Duration MaxSize *utils.FileSize } @@ -928,11 +905,11 @@ func (m *FluxMonitor) setFrom(f *FluxMonitor) { type OCR2 struct { Enabled *bool ContractConfirmations *uint32 - BlockchainTimeout *models.Duration - ContractPollInterval *models.Duration - ContractSubscribeInterval *models.Duration - ContractTransmitterTransmitTimeout *models.Duration - DatabaseTimeout *models.Duration + BlockchainTimeout *commonconfig.Duration + ContractPollInterval *commonconfig.Duration + ContractSubscribeInterval *commonconfig.Duration + ContractTransmitterTransmitTimeout *commonconfig.Duration + DatabaseTimeout *commonconfig.Duration KeyBundleID *models.Sha256Hash CaptureEATelemetry *bool CaptureAutomationCustomTelemetry *bool @@ -985,10 +962,10 @@ func (o *OCR2) setFrom(f *OCR2) { type OCR struct { Enabled *bool - ObservationTimeout *models.Duration - BlockchainTimeout *models.Duration - ContractPollInterval *models.Duration - ContractSubscribeInterval *models.Duration + ObservationTimeout *commonconfig.Duration + BlockchainTimeout *commonconfig.Duration + ContractPollInterval *commonconfig.Duration + ContractSubscribeInterval *commonconfig.Duration DefaultTransactionQueueDepth *uint32 // Optional KeyBundleID *models.Sha256Hash @@ -1040,23 +1017,9 @@ type P2P struct { PeerID *p2pkey.PeerID TraceLogging *bool - V1 P2PV1 `toml:",omitempty"` V2 P2PV2 `toml:",omitempty"` } -func (p *P2P) NetworkStack() ocrnetworking.NetworkingStack { - v1, v2 := *p.V1.Enabled, *p.V2.Enabled - switch { - case v1 && v2: - return ocrnetworking.NetworkingStackV1V2 - case v2: - return ocrnetworking.NetworkingStackV2 - case v1: - return ocrnetworking.NetworkingStackV1 - } - return ocrnetworking.NetworkingStack(0) -} - func (p *P2P) setFrom(f *P2P) { if v := f.IncomingMessageBufferSize; v != nil { p.IncomingMessageBufferSize = v @@ -1071,74 +1034,15 @@ func (p *P2P) setFrom(f *P2P) { p.TraceLogging = v } - p.V1.setFrom(&f.V1) p.V2.setFrom(&f.V2) } -type P2PV1 struct { - Enabled *bool - AnnounceIP *net.IP - AnnouncePort *uint16 - BootstrapCheckInterval *models.Duration - DefaultBootstrapPeers *[]string - DHTAnnouncementCounterUserPrefix *uint32 - DHTLookupInterval *int64 - ListenIP *net.IP - ListenPort *uint16 - NewStreamTimeout *models.Duration - PeerstoreWriteInterval *models.Duration -} - -func (p *P2PV1) ValidateConfig() (err error) { - //TODO or empty? - if p.AnnouncePort != nil && p.AnnounceIP == nil { - err = multierr.Append(err, configutils.ErrMissing{Name: "AnnounceIP", Msg: fmt.Sprintf("required when AnnouncePort is set: %d", *p.AnnouncePort)}) - } - return -} - -func (p *P2PV1) setFrom(f *P2PV1) { - if v := f.Enabled; v != nil { - p.Enabled = v - } - if v := f.AnnounceIP; v != nil { - p.AnnounceIP = v - } - if v := f.AnnouncePort; v != nil { - p.AnnouncePort = v - } - if v := f.BootstrapCheckInterval; v != nil { - p.BootstrapCheckInterval = v - } - if v := f.DefaultBootstrapPeers; v != nil { - p.DefaultBootstrapPeers = v - } - if v := f.DHTAnnouncementCounterUserPrefix; v != nil { - p.DHTAnnouncementCounterUserPrefix = v - } - if v := f.DHTLookupInterval; v != nil { - p.DHTLookupInterval = v - } - if v := f.ListenIP; v != nil { - p.ListenIP = v - } - if v := f.ListenPort; v != nil { - p.ListenPort = v - } - if v := f.NewStreamTimeout; v != nil { - p.NewStreamTimeout = v - } - if v := f.PeerstoreWriteInterval; v != nil { - p.PeerstoreWriteInterval = v - } -} - type P2PV2 struct { Enabled *bool AnnounceAddresses *[]string DefaultBootstrappers *[]ocrcommontypes.BootstrapperLocator - DeltaDial *models.Duration - DeltaReconcile *models.Duration + DeltaDial *commonconfig.Duration + DeltaReconcile *commonconfig.Duration ListenAddresses *[]string } @@ -1202,7 +1106,7 @@ type KeeperRegistry struct { CheckGasOverhead *uint32 PerformGasOverhead *uint32 MaxPerformDataSize *uint32 - SyncInterval *models.Duration + SyncInterval *commonconfig.Duration SyncUpkeepQueueSize *uint32 } @@ -1227,9 +1131,9 @@ func (k *KeeperRegistry) setFrom(f *KeeperRegistry) { type AutoPprof struct { Enabled *bool ProfileRoot *string - PollInterval *models.Duration - GatherDuration *models.Duration - GatherTraceDuration *models.Duration + PollInterval *commonconfig.Duration + GatherDuration *commonconfig.Duration + GatherTraceDuration *commonconfig.Duration MaxProfileSize *utils.FileSize CPUProfileRate *int64 // runtime.SetCPUProfileRate MemProfileRate *int64 // runtime.MemProfileRate @@ -1361,9 +1265,9 @@ func (ins *Insecure) setFrom(f *Insecure) { } type MercuryCache struct { - LatestReportTTL *models.Duration - MaxStaleAge *models.Duration - LatestReportDeadline *models.Duration + LatestReportTTL *commonconfig.Duration + MaxStaleAge *commonconfig.Duration + LatestReportDeadline *commonconfig.Duration } func (mc *MercuryCache) setFrom(f *MercuryCache) { @@ -1378,12 +1282,37 @@ func (mc *MercuryCache) setFrom(f *MercuryCache) { } } +type MercuryTLS struct { + CertFile *string +} + +func (m *MercuryTLS) setFrom(f *MercuryTLS) { + if v := f.CertFile; v != nil { + m.CertFile = v + } +} + +func (m *MercuryTLS) ValidateConfig() (err error) { + if *m.CertFile != "" { + if !isValidFilePath(*m.CertFile) { + err = multierr.Append(err, configutils.ErrInvalid{Name: "CertFile", Value: *m.CertFile, Msg: "must be a valid file path"}) + } + } + return +} + type Mercury struct { Cache MercuryCache `toml:",omitempty"` + TLS MercuryTLS `toml:",omitempty"` } func (m *Mercury) setFrom(f *Mercury) { m.Cache.setFrom(&f.Cache) + m.TLS.setFrom(&f.TLS) +} + +func (m *Mercury) ValidateConfig() (err error) { + return m.TLS.ValidateConfig() } type MercuryCredentials struct { diff --git a/core/config/toml/types_test.go b/core/config/toml/types_test.go index e16d3a864da..9c3fd1d02df 100644 --- a/core/config/toml/types_test.go +++ b/core/config/toml/types_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -109,13 +110,13 @@ func Test_validateDBURL(t *testing.T) { } func TestDatabaseSecrets_ValidateConfig(t *testing.T) { - validUrl := models.URL(url.URL{Scheme: "https", Host: "localhost"}) + validUrl := commonconfig.URL(url.URL{Scheme: "https", Host: "localhost"}) validSecretURL := *models.NewSecretURL(&validUrl) - invalidEmptyUrl := models.URL(url.URL{}) + invalidEmptyUrl := commonconfig.URL(url.URL{}) invalidEmptySecretURL := *models.NewSecretURL(&invalidEmptyUrl) - invalidBackupURL := models.URL(url.URL{Scheme: "http", Host: "localhost"}) + invalidBackupURL := commonconfig.URL(url.URL{Scheme: "http", Host: "localhost"}) invalidBackupSecretURL := *models.NewSecretURL(&invalidBackupURL) tests := []struct { @@ -531,5 +532,50 @@ func TestTracing_ValidateMode(t *testing.T) { } } +func TestMercuryTLS_ValidateTLSCertPath(t *testing.T) { + tests := []struct { + name string + tlsCertPath *string + wantErr bool + errMsg string + }{ + { + name: "valid file path", + tlsCertPath: ptr("/etc/ssl/certs/cert.pem"), + wantErr: false, + }, + { + name: "relative file path", + tlsCertPath: ptr("certs/cert.pem"), + wantErr: false, + }, + { + name: "excessively long file path", + tlsCertPath: ptr(strings.Repeat("z", 4097)), + wantErr: true, + errMsg: "CertFile: invalid value (" + strings.Repeat("z", 4097) + "): must be a valid file path", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mercury := &Mercury{ + TLS: MercuryTLS{ + CertFile: tt.tlsCertPath, + }, + } + + err := mercury.ValidateConfig() + + if tt.wantErr { + assert.Error(t, err) + assert.Equal(t, tt.errMsg, err.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} + // ptr is a utility function for converting a value to a pointer to the value. func ptr[T any](t T) *T { return &t } diff --git a/core/config/web_config.go b/core/config/web_config.go index 429a31e7e82..1f1adc47f5d 100644 --- a/core/config/web_config.go +++ b/core/config/web_config.go @@ -7,7 +7,7 @@ import ( "github.com/gin-contrib/sessions" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) type TLS interface { @@ -37,7 +37,7 @@ type LDAP interface { ReadOnlyUserLogin() string ReadOnlyUserPass() string ServerTLS() bool - SessionTimeout() models.Duration + SessionTimeout() commonconfig.Duration QueryTimeout() time.Duration BaseUserAttr() string BaseDN() string @@ -50,9 +50,9 @@ type LDAP interface { RunUserGroupCN() string ReadUserGroupCN() string UserApiTokenEnabled() bool - UserAPITokenDuration() models.Duration - UpstreamSyncInterval() models.Duration - UpstreamSyncRateLimit() models.Duration + UserAPITokenDuration() commonconfig.Duration + UpstreamSyncInterval() commonconfig.Duration + UpstreamSyncRateLimit() commonconfig.Duration } type WebServer interface { @@ -64,10 +64,10 @@ type WebServer interface { StartTimeout() time.Duration HTTPWriteTimeout() time.Duration HTTPPort() uint16 - SessionReaperExpiration() models.Duration + SessionReaperExpiration() commonconfig.Duration SecureCookies() bool SessionOptions() sessions.Options - SessionTimeout() models.Duration + SessionTimeout() commonconfig.Duration ListenIP() net.IP TLS() TLS diff --git a/core/gethwrappers/abigen.go b/core/gethwrappers/abigen.go index d96d9f8c306..ed2558f4173 100644 --- a/core/gethwrappers/abigen.go +++ b/core/gethwrappers/abigen.go @@ -17,7 +17,7 @@ import ( gethParams "github.com/ethereum/go-ethereum/params" "golang.org/x/tools/go/ast/astutil" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) const headerComment = `// Code generated - DO NOT EDIT. diff --git a/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go b/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go index 0ccb08cdaa9..ff15cc75d41 100644 --- a/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go +++ b/core/gethwrappers/functions/generated/functions_allow_list/functions_allow_list.go @@ -36,8 +36,8 @@ type TermsOfServiceAllowListConfig struct { } var TermsOfServiceAllowListMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowList.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidUsage\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIsBlocked\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"AddedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"BlockedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structTermsOfServiceAllowList.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"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\":\"user\",\"type\":\"address\"}],\"name\":\"UnblockedAccess\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"}],\"name\":\"acceptTermsOfService\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"blockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAllowedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowList.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"getMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"hasAccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isBlockedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"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\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"unblockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowList.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60806040523480156200001157600080fd5b50604051620012c4380380620012c4833981016040819052620000349162000269565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018460201b60201c565b50620002ea565b336001600160a01b03821603620001335760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018e6200020b565b805160058054602080850180516001600160a81b0319909316941515610100600160a81b03198116959095176101006001600160a01b039485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910160405180910390a150565b6000546001600160a01b03163314620002675760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6000604082840312156200027c57600080fd5b604080519081016001600160401b0381118282101715620002ad57634e487b7160e01b600052604160045260246000fd5b60405282518015158114620002c157600080fd5b815260208301516001600160a01b0381168114620002de57600080fd5b60208201529392505050565b610fca80620002fa6000396000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806382184c7b1161008c578063a39b06e311610066578063a39b06e3146101b8578063a5e1d61d146101d9578063c3f909d4146101ec578063f2fde38b1461024b57600080fd5b806382184c7b1461016a57806389f9a2c41461017d5780638da5cb5b1461019057600080fd5b80636b14daf8116100bd5780636b14daf81461012a57806379ba50971461014d578063817ef62e1461015557600080fd5b8063181f5a77146100e45780633908c4d41461010257806347663acb14610117575b600080fd5b6100ec61025e565b6040516100f99190610c4f565b60405180910390f35b610115610110366004610ce4565b61027a565b005b610115610125366004610d45565b6104f0565b61013d610138366004610d60565b61057b565b60405190151581526020016100f9565b6101156105a5565b61015d6106a7565b6040516100f99190610de3565b610115610178366004610d45565b6106b8565b61011561018b366004610e3d565b61074b565b60005460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f9565b6101cb6101c6366004610ec6565b610806565b6040519081526020016100f9565b61013d6101e7366004610d45565b610864565b60408051808201825260008082526020918201528151808301835260055460ff8116151580835273ffffffffffffffffffffffffffffffffffffffff6101009092048216928401928352845190815291511691810191909152016100f9565b610115610259366004610d45565b6108a5565b6040518060600160405280602c8152602001610f92602c913981565b73ffffffffffffffffffffffffffffffffffffffff841660009081526004602052604090205460ff16156102da576040517f62b7a34d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006102e68686610806565b6040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c810191909152605c01604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201206005546000855291840180845281905260ff8616928401929092526060830187905260808301869052909250610100900473ffffffffffffffffffffffffffffffffffffffff169060019060a0016020604051602081039080840390855afa1580156103c0573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff1614610417576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff861614158061045c57503373ffffffffffffffffffffffffffffffffffffffff87161480159061045c5750333b155b15610493576040517f381cfcbd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61049e6002866108b9565b5060405173ffffffffffffffffffffffffffffffffffffffff861681527f87286ad1f399c8e82bf0c4ef4fcdc570ea2e1e92176e5c848b6413545b885db49060200160405180910390a1505050505050565b6104f86108db565b73ffffffffffffffffffffffffffffffffffffffff811660008181526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905590519182527f28bbd0761309a99e8fb5e5d02ada0b7b2db2e5357531ff5dbfc205c3f5b6592b91015b60405180910390a150565b60055460009060ff166105905750600161059e565b61059b60028561095e565b90505b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff16331461062b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60606106b3600261098d565b905090565b6106c06108db565b6106cb60028261099a565b5073ffffffffffffffffffffffffffffffffffffffff811660008181526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905590519182527f337cd0f3f594112b6d830afb510072d3b08556b446514f73b8109162fd1151e19101610570565b6107536108db565b805160058054602080850180517fffffffffffffffffffffff0000000000000000000000000000000000000000009093169415157fffffffffffffffffffffff0000000000000000000000000000000000000000ff81169590951761010073ffffffffffffffffffffffffffffffffffffffff9485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a9101610570565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084811b8216602084015283901b1660348201526000906048016040516020818303038152906040528051906020012090505b92915050565b60055460009060ff1661087957506000919050565b5073ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205460ff1690565b6108ad6108db565b6108b6816109bc565b50565b600061059e8373ffffffffffffffffffffffffffffffffffffffff8416610ab1565b60005473ffffffffffffffffffffffffffffffffffffffff16331461095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610622565b565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561059e565b6060600061059e83610b00565b600061059e8373ffffffffffffffffffffffffffffffffffffffff8416610b5c565b3373ffffffffffffffffffffffffffffffffffffffff821603610a3b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610622565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000818152600183016020526040812054610af85750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561085e565b50600061085e565b606081600001805480602002602001604051908101604052809291908181526020018280548015610b5057602002820191906000526020600020905b815481526020019060010190808311610b3c575b50505050509050919050565b60008181526001830160205260408120548015610c45576000610b80600183610ef9565b8554909150600090610b9490600190610ef9565b9050818114610bf9576000866000018281548110610bb457610bb4610f33565b9060005260206000200154905080876000018481548110610bd757610bd7610f33565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610c0a57610c0a610f62565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061085e565b600091505061085e565b600060208083528351808285015260005b81811015610c7c57858101830151858201604001528201610c60565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610cdf57600080fd5b919050565b600080600080600060a08688031215610cfc57600080fd5b610d0586610cbb565b9450610d1360208701610cbb565b93506040860135925060608601359150608086013560ff81168114610d3757600080fd5b809150509295509295909350565b600060208284031215610d5757600080fd5b61059e82610cbb565b600080600060408486031215610d7557600080fd5b610d7e84610cbb565b9250602084013567ffffffffffffffff80821115610d9b57600080fd5b818601915086601f830112610daf57600080fd5b813581811115610dbe57600080fd5b876020828501011115610dd057600080fd5b6020830194508093505050509250925092565b6020808252825182820181905260009190848201906040850190845b81811015610e3157835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610dff565b50909695505050505050565b600060408284031215610e4f57600080fd5b6040516040810181811067ffffffffffffffff82111715610e99577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405282358015158114610eac57600080fd5b8152610eba60208401610cbb565b60208201529392505050565b60008060408385031215610ed957600080fd5b610ee283610cbb565b9150610ef060208401610cbb565b90509250929050565b8181038181111561085e577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe46756e6374696f6e73205465726d73206f66205365727669636520416c6c6f77204c6973742076312e302e30a164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidUsage\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RecipientIsBlocked\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"AddedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"}],\"name\":\"BlockedAccess\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"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\":\"user\",\"type\":\"address\"}],\"name\":\"UnblockedAccess\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"}],\"name\":\"acceptTermsOfService\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"blockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAllowedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowedSendersCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"allowedSenderIdxStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"allowedSenderIdxEnd\",\"type\":\"uint64\"}],\"name\":\"getAllowedSendersInRange\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"allowedSenders\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockedSendersCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"blockedSenderIdxStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"blockedSenderIdxEnd\",\"type\":\"uint64\"}],\"name\":\"getBlockedSendersInRange\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"blockedSenders\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"acceptor\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"name\":\"getMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"hasAccess\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isBlockedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"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\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"unblockSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"enabled\",\"type\":\"bool\"},{\"internalType\":\"address\",\"name\":\"signerPublicKey\",\"type\":\"address\"}],\"internalType\":\"structTermsOfServiceAllowListConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60806040523480156200001157600080fd5b506040516200173438038062001734833981016040819052620000349162000269565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d9565b505050620000d2816200018460201b60201c565b50620002ea565b336001600160a01b03821603620001335760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200018e6200020b565b805160068054602080850180516001600160a81b0319909316941515610100600160a81b03198116959095176101006001600160a01b039485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910160405180910390a150565b6000546001600160a01b03163314620002675760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b6000604082840312156200027c57600080fd5b604080519081016001600160401b0381118282101715620002ad57634e487b7160e01b600052604160045260246000fd5b60405282518015158114620002c157600080fd5b815260208301516001600160a01b0381168114620002de57600080fd5b60208201529392505050565b61143a80620002fa6000396000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c8063817ef62e116100b2578063a39b06e311610081578063c3f909d411610066578063c3f909d4146102c3578063cc7ebf4914610322578063f2fde38b1461032a57600080fd5b8063a39b06e314610237578063a5e1d61d146102b057600080fd5b8063817ef62e146101e157806382184c7b146101e957806389f9a2c4146101fc5780638da5cb5b1461020f57600080fd5b80633908c4d4116100ee5780633908c4d41461018e57806347663acb146101a35780636b14daf8146101b657806379ba5097146101d957600080fd5b806301a05958146101205780630a8c9c2414610146578063181f5a771461016657806320229a861461017b575b600080fd5b61012861033d565b60405167ffffffffffffffff90911681526020015b60405180910390f35b610159610154366004610fd6565b61034e565b60405161013d9190611009565b61016e6104bc565b60405161013d9190611063565b610159610189366004610fd6565b6104d8565b6101a161019c3660046110f3565b61063e565b005b6101a16101b1366004611154565b6108e9565b6101c96101c436600461116f565b61094a565b604051901515815260200161013d565b6101a1610974565b610159610a76565b6101a16101f7366004611154565b610a82565b6101a161020a366004611221565b610ae8565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161013d565b6102a26102453660046112aa565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084811b8216602084015283901b16603482015260009060480160405160208183030381529060405280519060200120905092915050565b60405190815260200161013d565b6101c96102be366004611154565b610ba3565b60408051808201825260008082526020918201528151808301835260065460ff8116151580835273ffffffffffffffffffffffffffffffffffffffff61010090920482169284019283528451908152915116918101919091520161013d565b610128610bc3565b6101a1610338366004611154565b610bcf565b60006103496004610be3565b905090565b60608167ffffffffffffffff168367ffffffffffffffff16118061038557506103776002610be3565b8267ffffffffffffffff1610155b8061039757506103956002610be3565b155b156103ce576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6103d88383611303565b6103e3906001611324565b67ffffffffffffffff1667ffffffffffffffff811115610405576104056111f2565b60405190808252806020026020018201604052801561042e578160200160208202803683370190505b50905060005b61043e8484611303565b67ffffffffffffffff1681116104b45761046d6104658267ffffffffffffffff8716611345565b600290610bed565b82828151811061047f5761047f611358565b73ffffffffffffffffffffffffffffffffffffffff909216602092830291909101909101526104ad81611387565b9050610434565b505b92915050565b6040518060600160405280602c8152602001611402602c913981565b60608167ffffffffffffffff168367ffffffffffffffff16118061050f57506105016004610be3565b8267ffffffffffffffff1610155b80610521575061051f6004610be3565b155b15610558576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6105628383611303565b61056d906001611324565b67ffffffffffffffff1667ffffffffffffffff81111561058f5761058f6111f2565b6040519080825280602002602001820160405280156105b8578160200160208202803683370190505b50905060005b6105c88484611303565b67ffffffffffffffff1681116104b4576105f76105ef8267ffffffffffffffff8716611345565b600490610bed565b82828151811061060957610609611358565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015261063781611387565b90506105be565b610649600485610bf9565b15610680576040517f62b7a34d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051606087811b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009081166020808501919091529188901b16603483015282516028818403018152604890920190925280519101206000906040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c810191909152605c01604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815282825280516020918201206006546000855291840180845281905260ff8616928401929092526060830187905260808301869052909250610100900473ffffffffffffffffffffffffffffffffffffffff169060019060a0016020604051602081039080840390855afa1580156107b4573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff161461080b576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff861614158061085057503373ffffffffffffffffffffffffffffffffffffffff8716148015906108505750333b155b15610887576040517f381cfcbd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610892600286610c28565b156108e15760405173ffffffffffffffffffffffffffffffffffffffff861681527f87286ad1f399c8e82bf0c4ef4fcdc570ea2e1e92176e5c848b6413545b885db49060200160405180910390a15b505050505050565b6108f1610c4a565b6108fc600482610ccd565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527f28bbd0761309a99e8fb5e5d02ada0b7b2db2e5357531ff5dbfc205c3f5b6592b906020015b60405180910390a150565b60065460009060ff1661095f5750600161096d565b61096a600285610bf9565b90505b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146109fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60606103496002610cef565b610a8a610c4a565b610a95600282610ccd565b50610aa1600482610c28565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527f337cd0f3f594112b6d830afb510072d3b08556b446514f73b8109162fd1151e19060200161093f565b610af0610c4a565b805160068054602080850180517fffffffffffffffffffffff0000000000000000000000000000000000000000009093169415157fffffffffffffffffffffff0000000000000000000000000000000000000000ff81169590951761010073ffffffffffffffffffffffffffffffffffffffff9485160217909355604080519485529251909116908301527f0d22b8a99f411b3dd338c961284f608489ca0dab9cdad17366a343c361bcf80a910161093f565b60065460009060ff16610bb857506000919050565b6104b6600483610bf9565b60006103496002610be3565b610bd7610c4a565b610be081610cfc565b50565b60006104b6825490565b600061096d8383610df1565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600183016020526040812054151561096d565b600061096d8373ffffffffffffffffffffffffffffffffffffffff8416610e1b565b60005473ffffffffffffffffffffffffffffffffffffffff163314610ccb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016109f1565b565b600061096d8373ffffffffffffffffffffffffffffffffffffffff8416610e6a565b6060600061096d83610f5d565b3373ffffffffffffffffffffffffffffffffffffffff821603610d7b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016109f1565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000826000018281548110610e0857610e08611358565b9060005260206000200154905092915050565b6000818152600183016020526040812054610e62575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104b6565b5060006104b6565b60008181526001830160205260408120548015610f53576000610e8e6001836113bf565b8554909150600090610ea2906001906113bf565b9050818114610f07576000866000018281548110610ec257610ec2611358565b9060005260206000200154905080876000018481548110610ee557610ee5611358565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080610f1857610f186113d2565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506104b6565b60009150506104b6565b606081600001805480602002602001604051908101604052809291908181526020018280548015610fad57602002820191906000526020600020905b815481526020019060010190808311610f99575b50505050509050919050565b803567ffffffffffffffff81168114610fd157600080fd5b919050565b60008060408385031215610fe957600080fd5b610ff283610fb9565b915061100060208401610fb9565b90509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561105757835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611025565b50909695505050505050565b600060208083528351808285015260005b8181101561109057858101830151858201604001528201611074565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610fd157600080fd5b600080600080600060a0868803121561110b57600080fd5b611114866110cf565b9450611122602087016110cf565b93506040860135925060608601359150608086013560ff8116811461114657600080fd5b809150509295509295909350565b60006020828403121561116657600080fd5b61096d826110cf565b60008060006040848603121561118457600080fd5b61118d846110cf565b9250602084013567ffffffffffffffff808211156111aa57600080fd5b818601915086601f8301126111be57600080fd5b8135818111156111cd57600080fd5b8760208285010111156111df57600080fd5b6020830194508093505050509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006040828403121561123357600080fd5b6040516040810181811067ffffffffffffffff8211171561127d577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040528235801515811461129057600080fd5b815261129e602084016110cf565b60208201529392505050565b600080604083850312156112bd57600080fd5b6112c6836110cf565b9150611000602084016110cf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff8281168282160390808211156104b4576104b46112d4565b67ffffffffffffffff8181168382160190808211156104b4576104b46112d4565b808201808211156104b6576104b66112d4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036113b8576113b86112d4565b5060010190565b818103818111156104b6576104b66112d4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe46756e6374696f6e73205465726d73206f66205365727669636520416c6c6f77204c6973742076312e312e30a164736f6c6343000813000a", } var TermsOfServiceAllowListABI = TermsOfServiceAllowListMetaData.ABI @@ -198,6 +198,94 @@ func (_TermsOfServiceAllowList *TermsOfServiceAllowListCallerSession) GetAllAllo return _TermsOfServiceAllowList.Contract.GetAllAllowedSenders(&_TermsOfServiceAllowList.CallOpts) } +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCaller) GetAllowedSendersCount(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _TermsOfServiceAllowList.contract.Call(opts, &out, "getAllowedSendersCount") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListSession) GetAllowedSendersCount() (uint64, error) { + return _TermsOfServiceAllowList.Contract.GetAllowedSendersCount(&_TermsOfServiceAllowList.CallOpts) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCallerSession) GetAllowedSendersCount() (uint64, error) { + return _TermsOfServiceAllowList.Contract.GetAllowedSendersCount(&_TermsOfServiceAllowList.CallOpts) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCaller) GetAllowedSendersInRange(opts *bind.CallOpts, allowedSenderIdxStart uint64, allowedSenderIdxEnd uint64) ([]common.Address, error) { + var out []interface{} + err := _TermsOfServiceAllowList.contract.Call(opts, &out, "getAllowedSendersInRange", allowedSenderIdxStart, allowedSenderIdxEnd) + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListSession) GetAllowedSendersInRange(allowedSenderIdxStart uint64, allowedSenderIdxEnd uint64) ([]common.Address, error) { + return _TermsOfServiceAllowList.Contract.GetAllowedSendersInRange(&_TermsOfServiceAllowList.CallOpts, allowedSenderIdxStart, allowedSenderIdxEnd) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCallerSession) GetAllowedSendersInRange(allowedSenderIdxStart uint64, allowedSenderIdxEnd uint64) ([]common.Address, error) { + return _TermsOfServiceAllowList.Contract.GetAllowedSendersInRange(&_TermsOfServiceAllowList.CallOpts, allowedSenderIdxStart, allowedSenderIdxEnd) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCaller) GetBlockedSendersCount(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _TermsOfServiceAllowList.contract.Call(opts, &out, "getBlockedSendersCount") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListSession) GetBlockedSendersCount() (uint64, error) { + return _TermsOfServiceAllowList.Contract.GetBlockedSendersCount(&_TermsOfServiceAllowList.CallOpts) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCallerSession) GetBlockedSendersCount() (uint64, error) { + return _TermsOfServiceAllowList.Contract.GetBlockedSendersCount(&_TermsOfServiceAllowList.CallOpts) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCaller) GetBlockedSendersInRange(opts *bind.CallOpts, blockedSenderIdxStart uint64, blockedSenderIdxEnd uint64) ([]common.Address, error) { + var out []interface{} + err := _TermsOfServiceAllowList.contract.Call(opts, &out, "getBlockedSendersInRange", blockedSenderIdxStart, blockedSenderIdxEnd) + + if err != nil { + return *new([]common.Address), err + } + + out0 := *abi.ConvertType(out[0], new([]common.Address)).(*[]common.Address) + + return out0, err + +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListSession) GetBlockedSendersInRange(blockedSenderIdxStart uint64, blockedSenderIdxEnd uint64) ([]common.Address, error) { + return _TermsOfServiceAllowList.Contract.GetBlockedSendersInRange(&_TermsOfServiceAllowList.CallOpts, blockedSenderIdxStart, blockedSenderIdxEnd) +} + +func (_TermsOfServiceAllowList *TermsOfServiceAllowListCallerSession) GetBlockedSendersInRange(blockedSenderIdxStart uint64, blockedSenderIdxEnd uint64) ([]common.Address, error) { + return _TermsOfServiceAllowList.Contract.GetBlockedSendersInRange(&_TermsOfServiceAllowList.CallOpts, blockedSenderIdxStart, blockedSenderIdxEnd) +} + func (_TermsOfServiceAllowList *TermsOfServiceAllowListCaller) GetConfig(opts *bind.CallOpts) (TermsOfServiceAllowListConfig, error) { var out []interface{} err := _TermsOfServiceAllowList.contract.Call(opts, &out, "getConfig") @@ -1193,6 +1281,14 @@ func (_TermsOfServiceAllowList *TermsOfServiceAllowList) Address() common.Addres type TermsOfServiceAllowListInterface interface { GetAllAllowedSenders(opts *bind.CallOpts) ([]common.Address, error) + GetAllowedSendersCount(opts *bind.CallOpts) (uint64, error) + + GetAllowedSendersInRange(opts *bind.CallOpts, allowedSenderIdxStart uint64, allowedSenderIdxEnd uint64) ([]common.Address, error) + + GetBlockedSendersCount(opts *bind.CallOpts) (uint64, error) + + GetBlockedSendersInRange(opts *bind.CallOpts, blockedSenderIdxStart uint64, blockedSenderIdxEnd uint64) ([]common.Address, error) + GetConfig(opts *bind.CallOpts) (TermsOfServiceAllowListConfig, error) GetMessage(opts *bind.CallOpts, acceptor common.Address, recipient common.Address) ([32]byte, error) diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index 5f0d2d45f2d..a280297782e 100644 --- a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go +++ b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go @@ -71,8 +71,8 @@ type FunctionsResponseRequestMeta struct { } var FunctionsCoordinatorMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"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\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"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\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1FeeShareWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"callbackCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestBilled\",\"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\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"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\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"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\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"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\":\"report\",\"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\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b50604051620056d0380380620056d083398101604081905262000034916200046d565b8282828233806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c28162000139565b5050506001600160a01b038116620000ed57604051632530e88560e11b815260040160405180910390fd5b6001600160a01b03908116608052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200012d82620001e4565b5050505050506200062c565b336001600160a01b03821603620001935760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001ee62000342565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033790839062000576565b60405180910390a150565b6200034c6200034e565b565b6000546001600160a01b031633146200034c5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000086565b80516001600160a01b0381168114620003c257600080fd5b919050565b60405161012081016001600160401b0381118282101715620003f957634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c257600080fd5b80516001600160481b0381168114620003c257600080fd5b805164ffffffffff81168114620003c257600080fd5b805161ffff81168114620003c257600080fd5b80516001600160e01b0381168114620003c257600080fd5b60008060008385036101608112156200048557600080fd5b6200049085620003aa565b935061012080601f1983011215620004a757600080fd5b620004b1620003c7565b9150620004c160208701620003ff565b8252620004d160408701620003ff565b6020830152620004e460608701620003ff565b6040830152620004f760808701620003ff565b60608301526200050a60a0870162000414565b60808301526200051d60c087016200042c565b60a08301526200053060e0870162000442565b60c08301526101006200054581880162000455565b60e084015262000557828801620003ff565b908301525091506200056d6101408501620003aa565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005c960808401826001600160481b03169052565b5060a0830151620005e360a084018264ffffffffff169052565b5060c0830151620005fa60c084018261ffff169052565b5060e08301516200061660e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805161505e6200067260003960008181610845015281816109d301528181610ca601528181610f3a01528181611045015281816117890152613490015261505e6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a03660046139d4565b61059c565b005b6101a56101b5366004613b7d565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b6040516102039190613ca1565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613d42565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613dd1565b6108d7565b6101a5610a90565b6101a5610b92565b6101a56102933660046139d4565b610d92565b6102a0610de2565b6040516102039190613e5b565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613e6e565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613e87565b610fd4565b6040516102039190613fdc565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004614030565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b60405161020391906140e7565b61053b6105363660046141d7565b611785565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f66118e5565b6101a561056e3660046142f0565b61193c565b61057b6124b8565b604051908152602001610203565b6101a56105973660046143bd565b612711565b6105a4612725565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec828483614473565b505050565b6105f96127a8565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906108369083906140e7565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d29190614599565b905090565b6108df6127b0565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff166145e5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6127a8565b610ba26127b0565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd261460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c3161460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf561460a565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614639565b9050610bb1565b5050565b610d9a612725565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec828483614473565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e60906143da565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea8906143da565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed4906143da565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a883614671565b61295c565b90506110bf60608301604084016143bd565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a0880161475e565b61111f610160880161014089016143bd565b611129888061477b565b61113b6101208b016101008c016147e0565b60208b01356111516101008d0160e08e016147fb565b8b60405161116799989796959493929190614818565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16111d68a8a8a8a8a8a612dfa565b6003546000906002906111f49060ff808216916101009004166148c0565b6111fe9190614908565b6112099060016148c0565b60ff169050878114611277576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b878614611306576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f7265706f727420727320616e64207373206d757374206265206f66206571756160448201527f6c206c656e6774680000000000000000000000000000000000000000000000006064820152608401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113495761134961492a565b600281111561135a5761135a61492a565b90525090506002816020015160028111156113775761137761492a565b141580156113c057506006816000015160ff168154811061139a5761139a61460a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b15611427576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b5050505061143361396c565b6000808a8a604051611446929190614959565b60405190819003812061145d918e90602001614969565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156117675760006001848984602081106114c6576114c661460a565b6114d391901a601b6148c0565b8e8e868181106114e5576114e561460a565b905060200201358d8d878181106114fe576114fe61460a565b905060200201356040516000815260200160405260405161153b949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa15801561155d573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156115dd576115dd61492a565b60028111156115ee576115ee61492a565b905250925060018360200151600281111561160b5761160b61492a565b14611672576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061168c5761168c61460a565b602002015173ffffffffffffffffffffffffffffffffffffffff161461170e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117285761172861460a565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117536001866148c0565b9450508061176090614639565b90506114a7565b505050611778833383858e8e612eb1565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b15801561182557600080fd5b505afa158015611839573d6000803e3d6000fd5b5050505066038d7ea4c6800082111561187e576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611888610841565b905060006118cb87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b90506118d9858583856130b0565b98975050505050505050565b6060600c80546118f4906143da565b905060000361192f576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea8906143da565b855185518560ff16601f8311156119af576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611a19576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611aa7576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611ab281600361497d565b8311611b1a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611b22612725565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611b69908861321d565b60055415611d1e57600554600090611b8390600190614994565b9050600060058281548110611b9a57611b9a61460a565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611bd457611bd461460a565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611c5457611c546149a7565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611cbd57611cbd6149a7565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611b69915050565b60005b8151518110156122d557815180516000919083908110611d4357611d4361460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611dc8576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7369676e6572206d757374206e6f7420626520656d70747900000000000000006044820152606401610b0d565b600073ffffffffffffffffffffffffffffffffffffffff1682602001518281518110611df657611df661460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611e7b576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7472616e736d6974746572206d757374206e6f7420626520656d7074790000006044820152606401610b0d565b60006004600084600001518481518110611e9757611e9761460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611ee157611ee161492a565b14611f48576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611f7957611f7961460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561201a5761201a61492a565b02179055506000915061202a9050565b60046000846020015184815181106120445761204461460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561208e5761208e61492a565b146120f5576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff8216815260208101600281525060046000846020015184815181106121285761212861460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156121c9576121c961492a565b0217905550508251805160059250839081106121e7576121e761460a565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106122635761226361460a565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055806122cd81614639565b915050611d21565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161238d918491740100000000000000000000000000000000000000009004166149d6565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123ec4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613236565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986124a3988b9891977401000000000000000000000000000000000000000090920463ffffffff169690959194919391926149f3565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612646573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266a9190614aa3565b50935050925050804261267d9190614994565b836020015163ffffffff1610801561269f57506000836020015163ffffffff16115b156126cd57505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b6000821361270a576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b612719612725565b612722816132e1565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146127a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6127a6612725565b600b546bffffffffffffffffffffffff166000036127ca57565b60006127d4610de2565b80519091506000819003612814576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b546000906128339083906bffffffffffffffffffffffff16614af3565b905060005b828110156128fe5781600a60008684815181106128575761285761460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128bf9190614b1e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550806128f790614639565b9050612838565b506129098282614b43565b600b80546000906129299084906bffffffffffffffffffffffff166145e5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612b17576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612b548560e001513a8488608001516130b0565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612bb0576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612bc99190614b6b565b905060003087604001518860a001518960c001516001612be99190614b7e565b8a5180516020918201206101008d015160e08e0151604051612c9d98979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612dac9190613fdc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612e0782602061497d565b612e1285602061497d565b612e1e88610144614b6b565b612e289190614b6b565b612e329190614b6b565b612e3d906000614b6b565b9050368114612ea8576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b600080808080612ec386880188614c7a565b84519499509297509095509350915060ff16801580612ee3575084518114155b80612eef575083518114155b80612efb575082518114155b80612f07575081518114155b15612f6e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4669656c6473206d75737420626520657175616c206c656e67746800000000006044820152606401610b0d565b60005b818110156130a1576000613006888381518110612f9057612f9061460a565b6020026020010151888481518110612faa57612faa61460a565b6020026020010151888581518110612fc457612fc461460a565b6020026020010151888681518110612fde57612fde61460a565b6020026020010151888781518110612ff857612ff861460a565b6020026020010151886133d6565b9050600081600681111561301c5761301c61492a565b1480613039575060018160068111156130375761303761492a565b145b15613090578782815181106130505761305061460a565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b5061309a81614639565b9050612f71565b50505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561310b57600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b600854600090612710906131259063ffffffff168761497d565b61312f9190614d4c565b6131399086614b6b565b60085490915060009087906131729063ffffffff6c010000000000000000000000008204811691680100000000000000009004166149d6565b61317c91906149d6565b63ffffffff16905060006131c66000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136ea92505050565b905060006131e7826131d8858761497d565b6131e29190614b6b565b61382c565b9050600061320368ffffffffffffffffff808916908a16614b1e565b905061320f8183614b1e565b9a9950505050505050505050565b6000613227610de2565b511115610d8e57610d8e6127b0565b6000808a8a8a8a8a8a8a8a8a60405160200161325a99989796959493929190614d60565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613360576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133ed9190614e2c565b905060003a8261012001518361010001516134089190614ef4565b64ffffffffff16613419919061497d565b905060008460ff166134616000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136ea92505050565b61346b9190614d4c565b9050600061347c6131e28385614b6b565b905060006134893a61382c565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60e0015168ffffffffffffffffff16896134e89190614b1e565b338d6040518763ffffffff1660e01b815260040161350b96959493929190614f12565b60408051808303816000875af1158015613529573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354d9190614f8e565b909250905060008260068111156135665761356661492a565b1480613583575060018260068111156135815761358161492a565b145b156136d95760008e8152600760205260408120556135a18185614b1e565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0890151600b805468ffffffffffffffffff9092169390929161360d91859116614b1e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e0468487848b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff16878b61368c9190614b1e565b6136969190614b1e565b6136a09190614b1e565b604080516bffffffffffffffffffffffff9586168152602081019490945291841683830152909216606082015290519081900360800190a25b509c9b505050505050505050505050565b6000466136f681613860565b1561377257606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613747573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376b9190614fc1565b9392505050565b61377b81613883565b156138235773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e8460405180608001604052806048815260200161500a604891396040516020016137db929190614fda565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016138069190613ca1565b602060405180830381865afa158015613747573d6000803e3d6000fd5b50600092915050565b600061385a6138396124b8565b61384b84670de0b6b3a764000061497d565b6138559190614d4c565b6138ca565b92915050565b600061a4b1821480613874575062066eed82145b8061385a57505062066eee1490565b6000600a82148061389557506101a482145b806138a2575062aa37dc82145b806138ae575061210582145b806138bb575062014a3382145b8061385a57505062014a341490565b60006bffffffffffffffffffffffff821115613968576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f84011261399d57600080fd5b50813567ffffffffffffffff8111156139b557600080fd5b6020830191508360208285010111156139cd57600080fd5b9250929050565b600080602083850312156139e757600080fd5b823567ffffffffffffffff8111156139fe57600080fd5b613a0a8582860161398b565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613a6957613a69613a16565b60405290565b604051610160810167ffffffffffffffff81118282101715613a6957613a69613a16565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a16565b604052919050565b63ffffffff8116811461272257600080fd5b803561117081613ae2565b68ffffffffffffffffff8116811461272257600080fd5b803561117081613aff565b64ffffffffff8116811461272257600080fd5b803561117081613b21565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613b9057600080fd5b613b98613a45565b613ba183613af4565b8152613baf60208401613af4565b6020820152613bc060408401613af4565b6040820152613bd160608401613af4565b6060820152613be260808401613b16565b6080820152613bf360a08401613b34565b60a0820152613c0460c08401613b3f565b60c0820152613c1560e08401613b51565b60e0820152610100613c28818501613af4565b908201529392505050565b60005b83811015613c4e578181015183820152602001613c36565b50506000910152565b60008151808452613c6f816020860160208601613c33565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061376b6020830184613c57565b600082601f830112613cc557600080fd5b813567ffffffffffffffff811115613cdf57613cdf613a16565b613d1060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613a93565b818152846020838601011115613d2557600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613d5457600080fd5b813567ffffffffffffffff811115613d6b57600080fd5b613d7784828501613cb4565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461272257600080fd5b803561117081613d7f565b6bffffffffffffffffffffffff8116811461272257600080fd5b803561117081613dac565b60008060408385031215613de457600080fd5b8235613def81613d7f565b91506020830135613dff81613dac565b809150509250929050565b600081518084526020808501945080840160005b83811015613e5057815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613e1e565b509495945050505050565b60208152600061376b6020830184613e0a565b600060208284031215613e8057600080fd5b5035919050565b600060208284031215613e9957600080fd5b813567ffffffffffffffff811115613eb057600080fd5b8201610160818503121561376b57600080fd5b805182526020810151613eee602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613f0e60408401826bffffffffffffffffffffffff169052565b506060810151613f36606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613f52608084018267ffffffffffffffff169052565b5060a0810151613f6a60a084018263ffffffff169052565b5060c0810151613f8760c084018268ffffffffffffffffff169052565b5060e0810151613fa460e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161385a8284613ec3565b60008083601f840112613ffd57600080fd5b50813567ffffffffffffffff81111561401557600080fd5b6020830191508360208260051b85010111156139cd57600080fd5b60008060008060008060008060e0898b03121561404c57600080fd5b606089018a81111561405d57600080fd5b8998503567ffffffffffffffff8082111561407757600080fd5b6140838c838d0161398b565b909950975060808b013591508082111561409c57600080fd5b6140a88c838d01613feb565b909750955060a08b01359150808211156140c157600080fd5b506140ce8b828c01613feb565b999c989b50969995989497949560c00135949350505050565b815163ffffffff90811682526020808401518216908301526040808401518216908301526060808401519182169083015261012082019050608083015161413b608084018268ffffffffffffffffff169052565b5060a083015161415460a084018264ffffffffff169052565b5060c083015161416a60c084018261ffff169052565b5060e083015161419a60e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461272257600080fd5b8035611170816141b6565b6000806000806000608086880312156141ef57600080fd5b85356141fa816141b6565b9450602086013567ffffffffffffffff81111561421657600080fd5b6142228882890161398b565b909550935050604086013561423681613ae2565b949793965091946060013592915050565b600067ffffffffffffffff82111561426157614261613a16565b5060051b60200190565b600082601f83011261427c57600080fd5b8135602061429161428c83614247565b613a93565b82815260059290921b840181019181810190868411156142b057600080fd5b8286015b848110156142d45780356142c781613d7f565b83529183019183016142b4565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561430957600080fd5b863567ffffffffffffffff8082111561432157600080fd5b61432d8a838b0161426b565b9750602089013591508082111561434357600080fd5b61434f8a838b0161426b565b965061435d60408a016142df565b9550606089013591508082111561437357600080fd5b61437f8a838b01613cb4565b945061438d60808a016141cc565b935060a08901359150808211156143a357600080fd5b506143b089828a01613cb4565b9150509295509295509295565b6000602082840312156143cf57600080fd5b813561376b81613d7f565b600181811c908216806143ee57607f821691505b602082108103614427577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c810160208610156144545750805b601f850160051c820191505b81811015610a8857828155600101614460565b67ffffffffffffffff83111561448b5761448b613a16565b61449f8361449983546143da565b8361442d565b6000601f8411600181146144f157600085156144bb5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614587565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156145405786850135825560209485019460019092019101614520565b508682101561457b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613aff565b6000602082840312156145ab57600080fd5b815161376b81613aff565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff82811682821603908082111561270a5761270a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361466a5761466a6145b6565b5060010190565b6000610160823603121561468457600080fd5b61468c613a6f565b823567ffffffffffffffff8111156146a357600080fd5b6146af36828601613cb4565b825250602083013560208201526146c860408401613da1565b60408201526146d960608401613dc6565b60608201526146ea60808401613b16565b60808201526146fb60a084016141cc565b60a082015261470c60c084016141cc565b60c082015261471d60e08401613af4565b60e0820152610100614730818501613b3f565b908201526101206147428482016141cc565b90820152610140614754848201613da1565b9082015292915050565b60006020828403121561477057600080fd5b813561376b816141b6565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126147b057600080fd5b83018035915067ffffffffffffffff8211156147cb57600080fd5b6020019150368190038213156139cd57600080fd5b6000602082840312156147f257600080fd5b61376b82613b3f565b60006020828403121561480d57600080fd5b813561376b81613ae2565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061320f60e0830184613ec3565b60ff818116838216019081111561385a5761385a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061491b5761491b6148d9565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761385a5761385a6145b6565b8181038181111561385a5761385a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff81811683821601908082111561270a5761270a6145b6565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152614a238184018a613e0a565b90508281036080840152614a378189613e0a565b905060ff871660a084015282810360c0840152614a548187613c57565b905067ffffffffffffffff851660e0840152828103610100840152614a798185613c57565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a08688031215614abb57600080fd5b614ac486614a89565b9450602086015193506040860151925060608601519150614ae760808701614a89565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614b1257614b126148d9565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561270a5761270a6145b6565b6bffffffffffffffffffffffff8181168382160280821691908281146141ae576141ae6145b6565b8082018082111561385a5761385a6145b6565b67ffffffffffffffff81811683821601908082111561270a5761270a6145b6565b600082601f830112614bb057600080fd5b81356020614bc061428c83614247565b82815260059290921b84018101918181019086841115614bdf57600080fd5b8286015b848110156142d45780358352918301918301614be3565b600082601f830112614c0b57600080fd5b81356020614c1b61428c83614247565b82815260059290921b84018101918181019086841115614c3a57600080fd5b8286015b848110156142d457803567ffffffffffffffff811115614c5e5760008081fd5b614c6c8986838b0101613cb4565b845250918301918301614c3e565b600080600080600060a08688031215614c9257600080fd5b853567ffffffffffffffff80821115614caa57600080fd5b614cb689838a01614b9f565b96506020880135915080821115614ccc57600080fd5b614cd889838a01614bfa565b95506040880135915080821115614cee57600080fd5b614cfa89838a01614bfa565b94506060880135915080821115614d1057600080fd5b614d1c89838a01614bfa565b93506080880135915080821115614d3257600080fd5b50614d3f88828901614bfa565b9150509295509295909350565b600082614d5b57614d5b6148d9565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614da78285018b613e0a565b91508382036080850152614dbb828a613e0a565b915060ff881660a085015283820360c0850152614dd88288613c57565b90861660e08501528381036101008501529050614a798185613c57565b805161117081613d7f565b805161117081613dac565b8051611170816141b6565b805161117081613ae2565b805161117081613b21565b60006101608284031215614e3f57600080fd5b614e47613a6f565b82518152614e5760208401614df5565b6020820152614e6860408401614e00565b6040820152614e7960608401614df5565b6060820152614e8a60808401614e0b565b6080820152614e9b60a08401614e16565b60a0820152614eac60c0840161458e565b60c0820152614ebd60e0840161458e565b60e0820152610100614ed0818501614e21565b90820152610120614ee2848201614e21565b90820152610140613c28848201614e16565b64ffffffffff81811683821601908082111561270a5761270a6145b6565b6000610200808352614f268184018a613c57565b90508281036020840152614f3a8189613c57565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614f83905060a0830184613ec3565b979650505050505050565b60008060408385031215614fa157600080fd5b825160078110614fb057600080fd5b6020840151909250613dff81613dac565b600060208284031215614fd357600080fd5b5051919050565b60008351614fec818460208801613c33565b835190830190615000818360208801613c33565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBillingConfig\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"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\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsBillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"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\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1FeeShareWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"callbackCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestBilled\",\"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\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBillingConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"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\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"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\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"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\":\"report\",\"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\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBillingConfig\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b50604051620056d0380380620056d083398101604081905262000034916200046d565b8282828233806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c28162000139565b5050506001600160a01b038116620000ed57604051632530e88560e11b815260040160405180910390fd5b6001600160a01b03908116608052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200012d82620001e4565b5050505050506200062c565b336001600160a01b03821603620001935760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001ee62000342565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033790839062000576565b60405180910390a150565b6200034c6200034e565b565b6000546001600160a01b031633146200034c5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000086565b80516001600160a01b0381168114620003c257600080fd5b919050565b60405161012081016001600160401b0381118282101715620003f957634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c257600080fd5b80516001600160481b0381168114620003c257600080fd5b805164ffffffffff81168114620003c257600080fd5b805161ffff81168114620003c257600080fd5b80516001600160e01b0381168114620003c257600080fd5b60008060008385036101608112156200048557600080fd5b6200049085620003aa565b935061012080601f1983011215620004a757600080fd5b620004b1620003c7565b9150620004c160208701620003ff565b8252620004d160408701620003ff565b6020830152620004e460608701620003ff565b6040830152620004f760808701620003ff565b60608301526200050a60a0870162000414565b60808301526200051d60c087016200042c565b60a08301526200053060e0870162000442565b60c08301526101006200054581880162000455565b60e084015262000557828801620003ff565b908301525091506200056d6101408501620003aa565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005c960808401826001600160481b03169052565b5060a0830151620005e360a084018264ffffffffff169052565b5060c0830151620005fa60c084018261ffff169052565b5060e08301516200061660e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805161505e6200067260003960008181610845015281816109d301528181610ca601528181610f3a01528181611045015281816117890152613490015261505e6000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a03660046139d4565b61059c565b005b6101a56101b5366004613b7d565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e322e300000000081525081565b6040516102039190613ca1565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613d42565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613dd1565b6108d7565b6101a5610a90565b6101a5610b92565b6101a56102933660046139d4565b610d92565b6102a0610de2565b6040516102039190613e5b565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613e6e565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613e87565b610fd4565b6040516102039190613fdc565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004614030565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b60405161020391906140e7565b61053b6105363660046141d7565b611785565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f66118e5565b6101a561056e3660046142f0565b61193c565b61057b6124b8565b604051908152602001610203565b6101a56105973660046143bd565b612711565b6105a4612725565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec828483614473565b505050565b6105f96127a8565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906108369083906140e7565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d29190614599565b905090565b6108df6127b0565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff166145e5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6127a8565b610ba26127b0565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd261460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c3161460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf561460a565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614639565b9050610bb1565b5050565b610d9a612725565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec828483614473565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e60906143da565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea8906143da565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed4906143da565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a883614671565b61295c565b90506110bf60608301604084016143bd565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a0880161475e565b61111f610160880161014089016143bd565b611129888061477b565b61113b6101208b016101008c016147e0565b60208b01356111516101008d0160e08e016147fb565b8b60405161116799989796959493929190614818565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16111d68a8a8a8a8a8a612dfa565b6003546000906002906111f49060ff808216916101009004166148c0565b6111fe9190614908565b6112099060016148c0565b60ff169050878114611277576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b878614611306576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f7265706f727420727320616e64207373206d757374206265206f66206571756160448201527f6c206c656e6774680000000000000000000000000000000000000000000000006064820152608401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113495761134961492a565b600281111561135a5761135a61492a565b90525090506002816020015160028111156113775761137761492a565b141580156113c057506006816000015160ff168154811061139a5761139a61460a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b15611427576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b5050505061143361396c565b6000808a8a604051611446929190614959565b60405190819003812061145d918e90602001614969565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156117675760006001848984602081106114c6576114c661460a565b6114d391901a601b6148c0565b8e8e868181106114e5576114e561460a565b905060200201358d8d878181106114fe576114fe61460a565b905060200201356040516000815260200160405260405161153b949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa15801561155d573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156115dd576115dd61492a565b60028111156115ee576115ee61492a565b905250925060018360200151600281111561160b5761160b61492a565b14611672576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061168c5761168c61460a565b602002015173ffffffffffffffffffffffffffffffffffffffff161461170e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117285761172861460a565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117536001866148c0565b9450508061176090614639565b90506114a7565b505050611778833383858e8e612eb1565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b15801561182557600080fd5b505afa158015611839573d6000803e3d6000fd5b5050505066038d7ea4c6800082111561187e576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611888610841565b905060006118cb87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b90506118d9858583856130b0565b98975050505050505050565b6060600c80546118f4906143da565b905060000361192f576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea8906143da565b855185518560ff16601f8311156119af576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611a19576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611aa7576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611ab281600361497d565b8311611b1a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611b22612725565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611b69908861321d565b60055415611d1e57600554600090611b8390600190614994565b9050600060058281548110611b9a57611b9a61460a565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611bd457611bd461460a565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611c5457611c546149a7565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611cbd57611cbd6149a7565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611b69915050565b60005b8151518110156122d557815180516000919083908110611d4357611d4361460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611dc8576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7369676e6572206d757374206e6f7420626520656d70747900000000000000006044820152606401610b0d565b600073ffffffffffffffffffffffffffffffffffffffff1682602001518281518110611df657611df661460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611e7b576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7472616e736d6974746572206d757374206e6f7420626520656d7074790000006044820152606401610b0d565b60006004600084600001518481518110611e9757611e9761460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611ee157611ee161492a565b14611f48576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611f7957611f7961460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561201a5761201a61492a565b02179055506000915061202a9050565b60046000846020015184815181106120445761204461460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561208e5761208e61492a565b146120f5576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff8216815260208101600281525060046000846020015184815181106121285761212861460a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156121c9576121c961492a565b0217905550508251805160059250839081106121e7576121e761460a565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106122635761226361460a565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055806122cd81614639565b915050611d21565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161238d918491740100000000000000000000000000000000000000009004166149d6565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123ec4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613236565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986124a3988b9891977401000000000000000000000000000000000000000090920463ffffffff169690959194919391926149f3565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612646573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266a9190614aa3565b50935050925050804261267d9190614994565b836020015163ffffffff1610801561269f57506000836020015163ffffffff16115b156126cd57505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b6000821361270a576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b612719612725565b612722816132e1565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146127a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6127a6612725565b600b546bffffffffffffffffffffffff166000036127ca57565b60006127d4610de2565b80519091506000819003612814576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b546000906128339083906bffffffffffffffffffffffff16614af3565b905060005b828110156128fe5781600a60008684815181106128575761285761460a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128bf9190614b1e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550806128f790614639565b9050612838565b506129098282614b43565b600b80546000906129299084906bffffffffffffffffffffffff166145e5565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612b17576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612b548560e001513a8488608001516130b0565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612bb0576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612bc99190614b6b565b905060003087604001518860a001518960c001516001612be99190614b7e565b8a5180516020918201206101008d015160e08e0151604051612c9d98979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612dac9190613fdc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612e0782602061497d565b612e1285602061497d565b612e1e88610144614b6b565b612e289190614b6b565b612e329190614b6b565b612e3d906000614b6b565b9050368114612ea8576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b600080808080612ec386880188614c7a565b84519499509297509095509350915060ff16801580612ee3575084518114155b80612eef575083518114155b80612efb575082518114155b80612f07575081518114155b15612f6e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4669656c6473206d75737420626520657175616c206c656e67746800000000006044820152606401610b0d565b60005b818110156130a1576000613006888381518110612f9057612f9061460a565b6020026020010151888481518110612faa57612faa61460a565b6020026020010151888581518110612fc457612fc461460a565b6020026020010151888681518110612fde57612fde61460a565b6020026020010151888781518110612ff857612ff861460a565b6020026020010151886133d6565b9050600081600681111561301c5761301c61492a565b1480613039575060018160068111156130375761303761492a565b145b15613090578782815181106130505761305061460a565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b5061309a81614639565b9050612f71565b50505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561310b57600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b600854600090612710906131259063ffffffff168761497d565b61312f9190614d4c565b6131399086614b6b565b60085490915060009087906131729063ffffffff6c010000000000000000000000008204811691680100000000000000009004166149d6565b61317c91906149d6565b63ffffffff16905060006131c66000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136ea92505050565b905060006131e7826131d8858761497d565b6131e29190614b6b565b61382c565b9050600061320368ffffffffffffffffff808916908a16614b1e565b905061320f8183614b1e565b9a9950505050505050505050565b6000613227610de2565b511115610d8e57610d8e6127b0565b6000808a8a8a8a8a8a8a8a8a60405160200161325a99989796959493929190614d60565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613360576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133ed9190614e2c565b905060003a8261012001518361010001516134089190614ef4565b64ffffffffff16613419919061497d565b905060008460ff166134616000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506136ea92505050565b61346b9190614d4c565b9050600061347c6131e28385614b6b565b905060006134893a61382c565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60e0015168ffffffffffffffffff16896134e89190614b1e565b338d6040518763ffffffff1660e01b815260040161350b96959493929190614f12565b60408051808303816000875af1158015613529573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061354d9190614f8e565b909250905060008260068111156135665761356661492a565b1480613583575060018260068111156135815761358161492a565b145b156136d95760008e8152600760205260408120556135a18185614b1e565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0890151600b805468ffffffffffffffffff9092169390929161360d91859116614b1e565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e0468487848b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff16878b61368c9190614b1e565b6136969190614b1e565b6136a09190614b1e565b604080516bffffffffffffffffffffffff9586168152602081019490945291841683830152909216606082015290519081900360800190a25b509c9b505050505050505050505050565b6000466136f681613860565b1561377257606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613747573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061376b9190614fc1565b9392505050565b61377b81613883565b156138235773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e8460405180608001604052806048815260200161500a604891396040516020016137db929190614fda565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016138069190613ca1565b602060405180830381865afa158015613747573d6000803e3d6000fd5b50600092915050565b600061385a6138396124b8565b61384b84670de0b6b3a764000061497d565b6138559190614d4c565b6138ca565b92915050565b600061a4b1821480613874575062066eed82145b8061385a57505062066eee1490565b6000600a82148061389557506101a482145b806138a2575062aa37dc82145b806138ae575061210582145b806138bb575062014a3382145b8061385a57505062014a341490565b60006bffffffffffffffffffffffff821115613968576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f84011261399d57600080fd5b50813567ffffffffffffffff8111156139b557600080fd5b6020830191508360208285010111156139cd57600080fd5b9250929050565b600080602083850312156139e757600080fd5b823567ffffffffffffffff8111156139fe57600080fd5b613a0a8582860161398b565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613a6957613a69613a16565b60405290565b604051610160810167ffffffffffffffff81118282101715613a6957613a69613a16565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613ada57613ada613a16565b604052919050565b63ffffffff8116811461272257600080fd5b803561117081613ae2565b68ffffffffffffffffff8116811461272257600080fd5b803561117081613aff565b64ffffffffff8116811461272257600080fd5b803561117081613b21565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613b9057600080fd5b613b98613a45565b613ba183613af4565b8152613baf60208401613af4565b6020820152613bc060408401613af4565b6040820152613bd160608401613af4565b6060820152613be260808401613b16565b6080820152613bf360a08401613b34565b60a0820152613c0460c08401613b3f565b60c0820152613c1560e08401613b51565b60e0820152610100613c28818501613af4565b908201529392505050565b60005b83811015613c4e578181015183820152602001613c36565b50506000910152565b60008151808452613c6f816020860160208601613c33565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061376b6020830184613c57565b600082601f830112613cc557600080fd5b813567ffffffffffffffff811115613cdf57613cdf613a16565b613d1060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613a93565b818152846020838601011115613d2557600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613d5457600080fd5b813567ffffffffffffffff811115613d6b57600080fd5b613d7784828501613cb4565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461272257600080fd5b803561117081613d7f565b6bffffffffffffffffffffffff8116811461272257600080fd5b803561117081613dac565b60008060408385031215613de457600080fd5b8235613def81613d7f565b91506020830135613dff81613dac565b809150509250929050565b600081518084526020808501945080840160005b83811015613e5057815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613e1e565b509495945050505050565b60208152600061376b6020830184613e0a565b600060208284031215613e8057600080fd5b5035919050565b600060208284031215613e9957600080fd5b813567ffffffffffffffff811115613eb057600080fd5b8201610160818503121561376b57600080fd5b805182526020810151613eee602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613f0e60408401826bffffffffffffffffffffffff169052565b506060810151613f36606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613f52608084018267ffffffffffffffff169052565b5060a0810151613f6a60a084018263ffffffff169052565b5060c0810151613f8760c084018268ffffffffffffffffff169052565b5060e0810151613fa460e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161385a8284613ec3565b60008083601f840112613ffd57600080fd5b50813567ffffffffffffffff81111561401557600080fd5b6020830191508360208260051b85010111156139cd57600080fd5b60008060008060008060008060e0898b03121561404c57600080fd5b606089018a81111561405d57600080fd5b8998503567ffffffffffffffff8082111561407757600080fd5b6140838c838d0161398b565b909950975060808b013591508082111561409c57600080fd5b6140a88c838d01613feb565b909750955060a08b01359150808211156140c157600080fd5b506140ce8b828c01613feb565b999c989b50969995989497949560c00135949350505050565b815163ffffffff90811682526020808401518216908301526040808401518216908301526060808401519182169083015261012082019050608083015161413b608084018268ffffffffffffffffff169052565b5060a083015161415460a084018264ffffffffff169052565b5060c083015161416a60c084018261ffff169052565b5060e083015161419a60e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461272257600080fd5b8035611170816141b6565b6000806000806000608086880312156141ef57600080fd5b85356141fa816141b6565b9450602086013567ffffffffffffffff81111561421657600080fd5b6142228882890161398b565b909550935050604086013561423681613ae2565b949793965091946060013592915050565b600067ffffffffffffffff82111561426157614261613a16565b5060051b60200190565b600082601f83011261427c57600080fd5b8135602061429161428c83614247565b613a93565b82815260059290921b840181019181810190868411156142b057600080fd5b8286015b848110156142d45780356142c781613d7f565b83529183019183016142b4565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561430957600080fd5b863567ffffffffffffffff8082111561432157600080fd5b61432d8a838b0161426b565b9750602089013591508082111561434357600080fd5b61434f8a838b0161426b565b965061435d60408a016142df565b9550606089013591508082111561437357600080fd5b61437f8a838b01613cb4565b945061438d60808a016141cc565b935060a08901359150808211156143a357600080fd5b506143b089828a01613cb4565b9150509295509295509295565b6000602082840312156143cf57600080fd5b813561376b81613d7f565b600181811c908216806143ee57607f821691505b602082108103614427577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c810160208610156144545750805b601f850160051c820191505b81811015610a8857828155600101614460565b67ffffffffffffffff83111561448b5761448b613a16565b61449f8361449983546143da565b8361442d565b6000601f8411600181146144f157600085156144bb5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614587565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156145405786850135825560209485019460019092019101614520565b508682101561457b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613aff565b6000602082840312156145ab57600080fd5b815161376b81613aff565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff82811682821603908082111561270a5761270a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361466a5761466a6145b6565b5060010190565b6000610160823603121561468457600080fd5b61468c613a6f565b823567ffffffffffffffff8111156146a357600080fd5b6146af36828601613cb4565b825250602083013560208201526146c860408401613da1565b60408201526146d960608401613dc6565b60608201526146ea60808401613b16565b60808201526146fb60a084016141cc565b60a082015261470c60c084016141cc565b60c082015261471d60e08401613af4565b60e0820152610100614730818501613b3f565b908201526101206147428482016141cc565b90820152610140614754848201613da1565b9082015292915050565b60006020828403121561477057600080fd5b813561376b816141b6565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126147b057600080fd5b83018035915067ffffffffffffffff8211156147cb57600080fd5b6020019150368190038213156139cd57600080fd5b6000602082840312156147f257600080fd5b61376b82613b3f565b60006020828403121561480d57600080fd5b813561376b81613ae2565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061320f60e0830184613ec3565b60ff818116838216019081111561385a5761385a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061491b5761491b6148d9565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761385a5761385a6145b6565b8181038181111561385a5761385a6145b6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff81811683821601908082111561270a5761270a6145b6565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152614a238184018a613e0a565b90508281036080840152614a378189613e0a565b905060ff871660a084015282810360c0840152614a548187613c57565b905067ffffffffffffffff851660e0840152828103610100840152614a798185613c57565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a08688031215614abb57600080fd5b614ac486614a89565b9450602086015193506040860151925060608601519150614ae760808701614a89565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614b1257614b126148d9565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561270a5761270a6145b6565b6bffffffffffffffffffffffff8181168382160280821691908281146141ae576141ae6145b6565b8082018082111561385a5761385a6145b6565b67ffffffffffffffff81811683821601908082111561270a5761270a6145b6565b600082601f830112614bb057600080fd5b81356020614bc061428c83614247565b82815260059290921b84018101918181019086841115614bdf57600080fd5b8286015b848110156142d45780358352918301918301614be3565b600082601f830112614c0b57600080fd5b81356020614c1b61428c83614247565b82815260059290921b84018101918181019086841115614c3a57600080fd5b8286015b848110156142d457803567ffffffffffffffff811115614c5e5760008081fd5b614c6c8986838b0101613cb4565b845250918301918301614c3e565b600080600080600060a08688031215614c9257600080fd5b853567ffffffffffffffff80821115614caa57600080fd5b614cb689838a01614b9f565b96506020880135915080821115614ccc57600080fd5b614cd889838a01614bfa565b95506040880135915080821115614cee57600080fd5b614cfa89838a01614bfa565b94506060880135915080821115614d1057600080fd5b614d1c89838a01614bfa565b93506080880135915080821115614d3257600080fd5b50614d3f88828901614bfa565b9150509295509295909350565b600082614d5b57614d5b6148d9565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614da78285018b613e0a565b91508382036080850152614dbb828a613e0a565b915060ff881660a085015283820360c0850152614dd88288613c57565b90861660e08501528381036101008501529050614a798185613c57565b805161117081613d7f565b805161117081613dac565b8051611170816141b6565b805161117081613ae2565b805161117081613b21565b60006101608284031215614e3f57600080fd5b614e47613a6f565b82518152614e5760208401614df5565b6020820152614e6860408401614e00565b6040820152614e7960608401614df5565b6060820152614e8a60808401614e0b565b6080820152614e9b60a08401614e16565b60a0820152614eac60c0840161458e565b60c0820152614ebd60e0840161458e565b60e0820152610100614ed0818501614e21565b90820152610120614ee2848201614e21565b90820152610140613c28848201614e16565b64ffffffffff81811683821601908082111561270a5761270a6145b6565b6000610200808352614f268184018a613c57565b90508281036020840152614f3a8189613c57565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614f83905060a0830184613ec3565b979650505050505050565b60008060408385031215614fa157600080fd5b825160078110614fb057600080fd5b6020840151909250613dff81613dac565b600060208284031215614fd357600080fd5b5051919050565b60008351614fec818460208801613c33565b835190830190615000818360208801613c33565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } var FunctionsCoordinatorABI = FunctionsCoordinatorMetaData.ABI diff --git a/core/gethwrappers/functions/generated/functions_router/functions_router.go b/core/gethwrappers/functions/generated/functions_router/functions_router.go index 592f95b568f..368ef65560b 100644 --- a/core/gethwrappers/functions/generated/functions_router/functions_router.go +++ b/core/gethwrappers/functions/generated/functions_router/functions_router.go @@ -70,8 +70,8 @@ type IFunctionsSubscriptionsSubscription struct { } var FunctionsRouterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotRemoveWithPendingRequests\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"DuplicateRequestId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyRequestData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"limit\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"IdentifierIsReserved\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"currentBalanceJuels\",\"type\":\"uint96\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"value\",\"type\":\"uint8\"}],\"name\":\"InvalidGasFlagValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProposal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeProposedOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeSubscriptionOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RouteNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderMustAcceptTermsOfService\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TimeoutNotExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"maximumConsumers\",\"type\":\"uint16\"}],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"indexed\":false,\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"proposedContractSetId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetFromAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetToAddress\",\"type\":\"address\"}],\"name\":\"ContractProposed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"ContractUpdated\",\"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\":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\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"}],\"name\":\"RequestNotProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"callbackReturnData\",\"type\":\"bytes\"}],\"name\":\"RequestProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestStart\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"RequestTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fundsRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fundsAmount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"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\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"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\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_RETURN_BYTES\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"createSubscriptionWithConsumer\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"costWithoutCallback\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getConsumer\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"}],\"internalType\":\"structIFunctionsSubscriptions.Consumer\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getFlags\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getProposedContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProposedContractSet\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSubscriptionCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionIdStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionIdEnd\",\"type\":\"uint64\"}],\"name\":\"getSubscriptionsInRange\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription[]\",\"name\":\"subscriptions\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"isValidCallbackGasLimit\",\"outputs\":[],\"stateMutability\":\"view\",\"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\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"ownerWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"proposedContractSetIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"proposedContractSetAddresses\",\"type\":\"address[]\"}],\"name\":\"proposeContractsUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"proposeSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequestToProposed\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"allowListId\",\"type\":\"bytes32\"}],\"name\":\"setAllowListId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"name\":\"setFlags\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment[]\",\"name\":\"requestsToTimeoutByCommitment\",\"type\":\"tuple[]\"}],\"name\":\"timeoutRequests\",\"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\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"updateContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a06040523480156200001157600080fd5b506040516200673c3803806200673c833981016040819052620000349162000549565b6001600160a01b0382166080526006805460ff191690553380600081620000a25760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600680546001600160a01b0380851661010002610100600160a81b031990921691909117909155811615620000dc57620000dc81620000f8565b505050620000f081620001aa60201b60201c565b50506200071a565b336001600160a01b03821603620001525760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000099565b600780546001600160a01b0319166001600160a01b03838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b620001b4620002c0565b8051600a80546020808501516040860151606087015161ffff908116600160781b0261ffff60781b1960e09390931c6b010000000000000000000000029290921665ffffffffffff60581b196001600160481b0390941662010000026001600160581b031990961691909716179390931716939093171781556080830151805184936200024792600b9291019062000323565b5060a08201516002909101805460c0909301516001600160481b031662010000026001600160581b031990931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e98590620002b590839062000652565b60405180910390a150565b60065461010090046001600160a01b03163314620003215760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000099565b565b82805482825590600052602060002090600701600890048101928215620003c75791602002820160005b838211156200039357835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026200034d565b8015620003c55782816101000a81549063ffffffff021916905560040160208160030104928301926001030262000393565b505b50620003d5929150620003d9565b5090565b5b80821115620003d55760008155600101620003da565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156200042b576200042b620003f0565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200045c576200045c620003f0565b604052919050565b805161ffff811681146200047757600080fd5b919050565b80516001600160481b03811681146200047757600080fd5b80516001600160e01b0319811681146200047757600080fd5b600082601f830112620004bf57600080fd5b815160206001600160401b03821115620004dd57620004dd620003f0565b8160051b620004ee82820162000431565b92835284810182019282810190878511156200050957600080fd5b83870192505b848310156200053e57825163ffffffff811681146200052e5760008081fd5b825291830191908301906200050f565b979650505050505050565b600080604083850312156200055d57600080fd5b82516001600160a01b03811681146200057557600080fd5b60208401519092506001600160401b03808211156200059357600080fd5b9084019060e08287031215620005a857600080fd5b620005b262000406565b620005bd8362000464565b8152620005cd602084016200047c565b6020820152620005e06040840162000494565b6040820152620005f36060840162000464565b60608201526080830151828111156200060b57600080fd5b6200061988828601620004ad565b6080830152506200062d60a0840162000464565b60a08201526200064060c084016200047c565b60c08201528093505050509250929050565b6020808252825161ffff90811683830152838201516001600160481b03166040808501919091528401516001600160e01b0319166060808501919091528401511660808084019190915283015160e060a0840152805161010084018190526000929182019083906101208601905b80831015620006e857835163ffffffff168252928401926001929092019190840190620006c0565b5060a087015161ffff811660c0880152935060c08701516001600160481b03811660e088015293509695505050505050565b608051615fea62000752600039600081816111cd0152818161208c015281816129b801528181612a7c01526135d30152615fea6000f3fe608060405234801561001057600080fd5b50600436106102e95760003560e01c80637341c10c11610191578063b734c0f4116100e3578063e72f6e3011610097578063ea320e0b11610071578063ea320e0b146106dd578063ec2454e5146106f0578063f2fde38b1461071057600080fd5b8063e72f6e30146106a4578063e82622aa146106b7578063e82ad7d4146106ca57600080fd5b8063c3f909d4116100c8578063c3f909d414610669578063cc77470a1461067e578063d7ae1d301461069157600080fd5b8063b734c0f41461064b578063badc3eb61461065357600080fd5b80639f87fad711610145578063a4c0ed361161011f578063a4c0ed361461061d578063a9c9a91814610630578063aab396bd1461064357600080fd5b80639f87fad7146105e2578063a21a23e4146105f5578063a47c7696146105fd57600080fd5b8063823597401161017657806382359740146105a45780638456cb59146105b75780638da5cb5b146105bf57600080fd5b80637341c10c1461058957806379ba50971461059c57600080fd5b806341db4ca31161024a5780635ed6dfba116101fe57806366419970116101d857806366419970146104e1578063674603d0146105085780636a2215de1461055157600080fd5b80635ed6dfba146104a85780636162a323146104bb57806366316d8d146104ce57600080fd5b80634b8832d31161022f5780634b8832d31461045057806355fedefa146104635780635c975abb1461049157600080fd5b806341db4ca31461041c578063461d27621461043d57600080fd5b80631ded3b36116102a1578063330605291161028657806333060529146103e05780633e871e4d146104015780633f4ba83a1461041457600080fd5b80631ded3b361461039f5780632a905ccc146103b257600080fd5b806310fc49c1116102d257806310fc49c11461032357806312b5834914610336578063181f5a771461035657600080fd5b806302bcc5b6146102ee5780630c5d49cb14610303575b600080fd5b6103016102fc366004614ba6565b610723565b005b61030b608481565b60405161ffff90911681526020015b60405180910390f35b610301610331366004614be7565b610783565b6000546040516bffffffffffffffffffffffff909116815260200161031a565b6103926040518060400160405280601781526020017f46756e6374696f6e7320526f757465722076312e302e3000000000000000000081525081565b60405161031a9190614c8e565b6103016103ad366004614ca1565b61087f565b600a5462010000900468ffffffffffffffffff1660405168ffffffffffffffffff909116815260200161031a565b6103f36103ee366004614f8c565b6108b1565b60405161031a929190615074565b61030161040f366004615135565b610c7c565b610301610e91565b61042f61042a366004615249565b610ea3565b60405190815260200161031a565b61042f61044b366004615249565b610f03565b61030161045e3660046152cd565b610f0f565b61042f610471366004614ba6565b67ffffffffffffffff166000908152600360208190526040909120015490565b60065460ff165b604051901515815260200161031a565b6103016104b63660046152fb565b61105d565b6103016104c93660046153bd565b611216565b6103016104dc3660046152fb565b611396565b60025467ffffffffffffffff165b60405167ffffffffffffffff909116815260200161031a565b61051b610516366004615490565b61147f565b6040805182511515815260208084015167ffffffffffffffff90811691830191909152928201519092169082015260600161031a565b61056461055f3660046154be565b61150f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161031a565b6103016105973660046152cd565b6115ce565b610301611781565b6103016105b2366004614ba6565b6118a8565b6103016119ef565b600654610100900473ffffffffffffffffffffffffffffffffffffffff16610564565b6103016105f03660046152cd565b6119ff565b6104ef611daa565b61061061060b366004614ba6565b611f37565b60405161031a91906155a7565b61030161062b3660046155ba565b61206c565b61056461063e3660046154be565b6122b8565b60095461042f565b610301612317565b61065b612463565b60405161031a929190615616565b610671612533565b60405161031a919061566d565b6104ef61068c366004615749565b61269a565b61030161069f3660046152cd565b61291a565b6103016106b2366004615749565b61297f565b6103016106c5366004615766565b612af8565b6104986106d8366004614ba6565b612db7565b6103016106eb3660046154be565b612f06565b6107036106fe3660046157dc565b612f13565b60405161031a91906157fa565b61030161071e366004615749565b6131a8565b61072b6131b9565b610734816131c1565b67ffffffffffffffff81166000908152600360205260408120546107809183916c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690613237565b50565b67ffffffffffffffff8216600090815260036020819052604082200154600b54911a9081106107e8576040517f45c108ce00000000000000000000000000000000000000000000000000000000815260ff821660048201526024015b60405180910390fd5b6000600a6001018260ff16815481106108035761080361587a565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1690508063ffffffff168363ffffffff161115610879576040517f1d70f87a00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526024016107df565b50505050565b6108876131b9565b610890826131c1565b67ffffffffffffffff90911660009081526003602081905260409091200155565b6000806108bc613689565b826020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610925576040517f8bec23e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516000908152600560205260409020548061098a5783516020850151604051600295507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b60405180910390a25060009050610c71565b808460405160200161099c91906158db565b60405160208183030381529060405280519060200120146109f45783516020850151604051600695507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b8361012001518460a0015163ffffffff16610a0f9190615a37565b64ffffffffff165a1015610a5a5783516020850151604051600495507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b506000610a708460a0015163ffffffff16613691565b610a7a9088615a55565b9050600081878660c0015168ffffffffffffffffff16610a9a9190615a7d565b610aa49190615a7d565b9050610ab38560800151611f37565b600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b2b5784516020860151604051600596507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b60405180910390a25060009150610c719050565b84604001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b905784516020860151604051600396507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b505082516000908152600560205260408120819055835160a08501516060860151610bc092918c918c9190613733565b8051909150610bd0576001610bd3565b60005b92506000610c0d8560800151866040015187606001518860c0015168ffffffffffffffffff168c610c078860200151613691565b8d6138f1565b9050846080015167ffffffffffffffff1685600001517f64778f26c70b60a8d7e29e2451b3844302d959448401c0535b768ed88c6b505e836020015189888f8f8960400151604051610c6496959493929190615aa2565b60405180910390a3519150505b965096945050505050565b610c84613c17565b8151815181141580610c965750600881115b15610ccd576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610e47576000848281518110610cec57610cec61587a565b602002602001015190506000848381518110610d0a57610d0a61587a565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610d75575060008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116145b15610dac576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260086020526040908190205490517f8b052f0f4bf82fede7daffea71592b29d5ef86af1f3c7daaa0345dbb2f52f48191610e2c91859173ffffffffffffffffffffffffffffffffffffffff1690859092835273ffffffffffffffffffffffffffffffffffffffff918216602084015216604082015260600190565b60405180910390a1505080610e4090615b25565b9050610cd0565b506040805180820190915283815260208082018490528451600d91610e709183918801906149e6565b506020828101518051610e899260018501920190614a2d565b505050505050565b610e99613c17565b610ea1613c9d565b565b600080610eaf8361150f565b9050610ef783828a8a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92508b9150613d1a9050565b98975050505050505050565b600080610eaf836122b8565b610f17613689565b610f20826140ef565b610f286141b5565b73ffffffffffffffffffffffffffffffffffffffff81161580610f8f575067ffffffffffffffff821660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff8281166c0100000000000000000000000090920416145b15610fc6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff821660008181526003602090815260409182902060010180546bffffffffffffffffffffffff166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8716908102919091179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be910160405180910390a25050565b6110656131b9565b806bffffffffffffffffffffffff1660000361109b5750306000908152600160205260409020546bffffffffffffffffffffffff165b306000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611107576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b30600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550816000808282829054906101000a90046bffffffffffffffffffffffff1661118a9190615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061121183836bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b505050565b61121e613c17565b8051600a80546020808501516040860151606087015161ffff9081166f01000000000000000000000000000000027fffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff60e09390931c6b01000000000000000000000002929092167fffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffff68ffffffffffffffffff90941662010000027fffffffffffffffffffffffffffffffffffffffffff0000000000000000000000909616919097161793909317169390931717815560808301518051849361130592600b92910190614aa7565b5060a08201516002909101805460c09093015168ffffffffffffffffff1662010000027fffffffffffffffffffffffffffffffffffffffffff000000000000000000000090931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e9859061138b90839061566d565b60405180910390a150565b61139e613689565b806bffffffffffffffffffffffff166000036113e6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611452576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b33600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff861681526004835283812067ffffffffffffffff868116835290845290849020845192830185525460ff81161515835261010081048216938301939093526901000000000000000000909204909116918101919091525b92915050565b6000805b600d5460ff8216101561159857600d805460ff83169081106115375761153761587a565b9060005260206000200154830361158857600e805460ff831690811061155f5761155f61587a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169392505050565b61159181615b82565b9050611513565b506040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018390526024016107df565b6115d6613689565b6115df826140ef565b6115e76141b5565b60006115f6600a5461ffff1690565b67ffffffffffffffff841660009081526003602052604090206002015490915061ffff821611611658576040517fb72bc70300000000000000000000000000000000000000000000000000000000815261ffff821660048201526024016107df565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8716845290915290205460ff16156116a057505050565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260046020908152604080832067ffffffffffffffff881680855290835281842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600384528285206002018054918201815585529383902090930180547fffffffffffffffffffffffff000000000000000000000000000000000000000016851790555192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091015b60405180910390a2505050565b60075473ffffffffffffffffffffffffffffffffffffffff163314611802576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107df565b600680547fffffffffffffffffffffff0000000000000000000000000000000000000000ff81166101003381810292909217909355600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040519290910473ffffffffffffffffffffffffffffffffffffffff169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6118b0613689565b6118b86141b5565b67ffffffffffffffff81166000908152600360205260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481169290910416338114611958576040517f4e1d9f1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016107df565b67ffffffffffffffff831660008181526003602090815260409182902080546c01000000000000000000000000339081026bffffffffffffffffffffffff928316178355600190920180549091169055825173ffffffffffffffffffffffffffffffffffffffff87168152918201527f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f09101611774565b6119f7613c17565b610ea161434c565b611a07613689565b611a10826140ef565b611a186141b5565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260046020908152604080832067ffffffffffffffff8087168552908352928190208151606081018352905460ff8116151582526101008104851693820193909352690100000000000000000090920490921691810191909152611a9782846143a7565b806040015167ffffffffffffffff16816020015167ffffffffffffffff1614611aec576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8316600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611b6757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611b3c575b5050505050905060005b8151811015611d0f578373ffffffffffffffffffffffffffffffffffffffff16828281518110611ba357611ba361587a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611cff578160018351611bd59190615ba1565b81518110611be557611be561587a565b6020026020010151600360008767ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018281548110611c2857611c2861587a565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925567ffffffffffffffff87168152600390915260409020600201805480611ca257611ca2615bb4565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055611d0f565b611d0881615b25565b9050611b71565b5073ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832067ffffffffffffffff89168085529083529281902080547fffffffffffffffffffffffffffffff00000000000000000000000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b910160405180910390a250505050565b6000611db4613689565b611dbc6141b5565b60028054600090611dd69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c0810182526000808252336020830152918101829052606081018290529192506080820190604051908082528060200260200182016040528015611e4c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff9384161784559386015160608701519091169093029216919091176001820155608083015180519192611ee792600285019290910190614a2d565b5060a0919091015160039091015560405133815267ffffffffffffffff8216907f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a290565b6040805160c0810182526000808252602082018190529181018290526060808201839052608082015260a0810191909152611f71826131c1565b67ffffffffffffffff8216600090815260036020908152604091829020825160c08101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811684870152600185015491821684880152919004166060820152600282018054855181860281018601909652808652919492936080860193929083018282801561205257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612027575b505050505081526020016003820154815250509050919050565b612074613689565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146120e3576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020811461211d576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061212b82840184614ba6565b67ffffffffffffffff81166000908152600360205260409020549091506c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166121a4576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260036020526040812080546bffffffffffffffffffffffff16918691906121db8385615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550846000808282829054906101000a90046bffffffffffffffffffffffff166122319190615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f88287846122989190615c0a565b6040805192835260208301919091520160405180910390a2505050505050565b60008181526008602052604081205473ffffffffffffffffffffffffffffffffffffffff1680611509576040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018490526024016107df565b61231f613c17565b60005b600d54811015612442576000600d60000182815481106123445761234461587a565b906000526020600020015490506000600d60010183815481106123695761236961587a565b6000918252602080832091909101548483526008825260409283902054835186815273ffffffffffffffffffffffffffffffffffffffff91821693810193909352169181018290529091507ff8a6175bca1ba37d682089187edc5e20a859989727f10ca6bd9a5bc0de8caf949060600160405180910390a160009182526008602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905561243b81615b25565b9050612322565b50600d60006124518282614b51565b61245f600183016000614b51565b5050565b606080600d600001600d600101818054806020026020016040519081016040528092919081815260200182805480156124bb57602002820191906000526020600020905b8154815260200190600101908083116124a7575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561252457602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116124f9575b50505050509050915091509091565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082015260a0810182905260c08101919091526040805160e08082018352600a805461ffff808216855262010000820468ffffffffffffffffff166020808701919091526b010000000000000000000000830490941b7fffffffff0000000000000000000000000000000000000000000000000000000016858701526f01000000000000000000000000000000909104166060840152600b805485518185028101850190965280865293949193608086019383018282801561266557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116126285790505b50505091835250506002919091015461ffff8116602083015262010000900468ffffffffffffffffff16604090910152919050565b60006126a4613689565b6126ac6141b5565b600280546000906126c69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c081018252600080825233602083015291810182905260608101829052919250608082019060405190808252806020026020018201604052801561273c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff93841617845593860151606087015190911690930292169190911760018201556080830151805191926127d792600285019290910190614a2d565b5060a0919091015160039182015567ffffffffffffffff82166000818152602092835260408082206002018054600180820183559184528584200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891690811790915583526004855281832084845285529181902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555133815290917f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf910160405180910390a260405173ffffffffffffffffffffffffffffffffffffffff8316815267ffffffffffffffff8216907f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e09060200160405180910390a2919050565b612922613689565b61292b826140ef565b6129336141b5565b61293c82612db7565b15612973576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61245f82826001613237565b6129876131b9565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612a14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a389190615c1d565b6000549091506bffffffffffffffffffffffff1681811015611211576000612a608284615ba1565b9050612aa373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685836142bf565b6040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b612b00613689565b60005b81811015611211576000838383818110612b1f57612b1f61587a565b90506101600201803603810190612b369190615c36565b80516080820151600082815260056020908152604091829020549151949550929391929091612b67918691016158db565b6040516020818303038152906040528051906020012014612bb4576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015163ffffffff16421015612bf9576040517fa2376fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516040517f85b214cf0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff909116906385b214cf90602401600060405180830381600087803b158015612c6757600080fd5b505af1158015612c7b573d6000803e3d6000fd5b50505060408085015167ffffffffffffffff84166000908152600360205291822060010180549193509190612cbf9084906bffffffffffffffffffffffff16615b5d565b82546bffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260046020908152604080832067ffffffffffffffff808616855292529091208054600192600991612d479185916901000000000000000000900416615c53565b825467ffffffffffffffff9182166101009390930a9283029190920219909116179055506000828152600560205260408082208290555183917ff1ca1e9147be737b04a2b018a79405f687a97de8dd8a2559bbe62357343af41491a250505080612db090615b25565b9050612b03565b67ffffffffffffffff8116600090815260036020908152604080832060020180548251818502810185019093528083528493830182828015612e2f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612e04575b5050505050905060005b8151811015612efc57600060046000848481518110612e5a57612e5a61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff808a168352908452908290208251606081018452905460ff8116151582526101008104831694820185905269010000000000000000009004909116918101829052925014612eeb57506001949350505050565b50612ef581615b25565b9050612e39565b5060009392505050565b612f0e613c17565b600955565b60608167ffffffffffffffff168367ffffffffffffffff161180612f46575060025467ffffffffffffffff908116908316115b80612f5b575060025467ffffffffffffffff16155b15612f92576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612f9c8383615c74565b612fa7906001615c53565b67ffffffffffffffff1667ffffffffffffffff811115612fc957612fc9614ccd565b60405190808252806020026020018201604052801561304657816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083015260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181612fe75790505b50905060005b6130568484615c74565b67ffffffffffffffff1681116131a1576003600061307e8367ffffffffffffffff8816615c0a565b67ffffffffffffffff1681526020808201929092526040908101600020815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561316057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311613135575b505050505081526020016003820154815250508282815181106131855761318561587a565b60200260200101819052508061319a90615b25565b905061304c565b5092915050565b6131b0613c17565b6107808161441b565b610ea1613c17565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16610780576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff83166000908152600360209081526040808320815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561331857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116132ed575b50505091835250506003919091015460209091015280519091506000805b83608001515181101561342e5760008460800151828151811061335b5761335b61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff8116600090815260048352604080822067ffffffffffffffff808e16845294529020549092506133bb9169010000000000000000009091041684615c53565b73ffffffffffffffffffffffffffffffffffffffff909116600090815260046020908152604080832067ffffffffffffffff8c168452909152902080547fffffffffffffffffffffffffffffff0000000000000000000000000000000000169055915061342781615b25565b9050613336565b5067ffffffffffffffff8616600090815260036020526040812081815560018101829055906134606002830182614b51565b50600060039190910155600c5461ffff81169062010000900468ffffffffffffffffff1685801561349e57508161ffff168367ffffffffffffffff16105b1561355a576000846bffffffffffffffffffffffff168268ffffffffffffffffff16116134d6578168ffffffffffffffffff166134d8565b845b90506bffffffffffffffffffffffff81161561355857306000908152600160205260408120805483929061351b9084906bffffffffffffffffffffffff16615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080856135559190615b5d565b94505b505b6bffffffffffffffffffffffff841615613617576000805485919081906135909084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061361787856bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b6040805173ffffffffffffffffffffffffffffffffffffffff891681526bffffffffffffffffffffffff8616602082015267ffffffffffffffff8a16917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050505050565b610ea1614517565b60006bffffffffffffffffffffffff82111561372f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016107df565b5090565b60408051606080820183526000808352602083015291810191909152813b1580156137865750506040805160608101825260008082526020808301829052835191825281018352918101919091526138e8565b600a546040516000916b010000000000000000000000900460e01b906137b4908a908a908a90602401615c95565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009590951694909417909352600a548151608480825260c0820190935292945061ffff6f01000000000000000000000000000000909104169260009283928392820181803683370190505090505a8481101561388257600080fd5b8490036040810481038a1061389657600080fd5b505a60008087516020890160008d8ff193505a900391503d60848111156138bb575060845b808252806000602084013e5060408051606081018252931515845260208401929092529082015293505050505b95945050505050565b604080518082019091526000808252602082015260006139118486615a55565b90506000816139208886615a7d565b61392a9190615a7d565b67ffffffffffffffff8b166000908152600360205260409020549091506bffffffffffffffffffffffff80831691161080613991575067ffffffffffffffff8a166000908152600360205260409020600101546bffffffffffffffffffffffff808b169116105b156139f45767ffffffffffffffff8a16600090815260036020526040908190205490517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff90911660048201526024016107df565b67ffffffffffffffff8a1660009081526003602052604081208054839290613a2b9084906bffffffffffffffffffffffff16615b5d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915567ffffffffffffffff8c16600090815260036020526040812060010180548d94509092613a7f91859116615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508184613ab99190615a7d565b3360009081526001602052604081208054909190613ae69084906bffffffffffffffffffffffff16615a7d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915530600090815260016020526040812080548b94509092613b2d91859116615a7d565b82546bffffffffffffffffffffffff9182166101009390930a92830291909202199091161790555073ffffffffffffffffffffffffffffffffffffffff8816600090815260046020908152604080832067ffffffffffffffff808f16855292529091208054600192600991613bb19185916901000000000000000000900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040518060400160405280836bffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff1681525092505050979650505050505050565b600654610100900473ffffffffffffffffffffffffffffffffffffffff163314610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107df565b613ca5614584565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000613d24613689565b613d2d856131c1565b613d3733866143a7565b613d418583610783565b8351600003613d7b576040517ec1cfc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613d8686611f37565b90506000613d94338861147f565b600a54604080516101608101825289815267ffffffffffffffff8b1660009081526003602081815293822001549495506201000090930468ffffffffffffffffff169373ffffffffffffffffffffffffffffffffffffffff8d169263a631571e929190820190815233602082015260408881015189519190920191613e1891615b5d565b6bffffffffffffffffffffffff1681526020018568ffffffffffffffffff1681526020018c67ffffffffffffffff168152602001866020015167ffffffffffffffff1681526020018963ffffffff1681526020018a61ffff168152602001866040015167ffffffffffffffff168152602001876020015173ffffffffffffffffffffffffffffffffffffffff168152506040518263ffffffff1660e01b8152600401613ec49190615cc0565b610160604051808303816000875af1158015613ee4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f089190615e25565b805160009081526005602052604090205490915015613f595780516040517f304f32e800000000000000000000000000000000000000000000000000000000815260048101919091526024016107df565b604051806101600160405280826000015181526020018b73ffffffffffffffffffffffffffffffffffffffff16815260200182604001516bffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018a67ffffffffffffffff1681526020018763ffffffff1681526020018368ffffffffffffffffff1681526020018260e0015168ffffffffffffffffff16815260200182610100015164ffffffffff16815260200182610120015164ffffffffff16815260200182610140015163ffffffff1681525060405160200161404491906158db565b60405160208183030381529060405280519060200120600560008360000151815260200190815260200160002081905550614084338a83604001516145f0565b8867ffffffffffffffff168b82600001517ff67aec45c9a7ede407974a3e0c3a743dffeab99ee3f2d4c9a8144c2ebf2c7ec9876020015133328e8e8e8a604001516040516140d89796959493929190615ef8565b60405180910390a4519a9950505050505050505050565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1680614166576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82161461245f576040517f5a68151d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095460009081526008602052604090205473ffffffffffffffffffffffffffffffffffffffff16806141e55750565b604080516000815260208101918290527f6b14daf80000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff821690636b14daf89061424690339060248101615f70565b602060405180830381865afa158015614263573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142879190615f9f565b610780576040517f229062630000000000000000000000000000000000000000000000000000000081523360048201526024016107df565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526112119084906146cb565b614354614517565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613cf03390565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8516845290915290205460ff1661245f576040517f71e8313700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82160361449a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107df565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60065460ff1615610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016107df565b60065460ff16610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016107df565b67ffffffffffffffff82166000908152600360205260408120600101805483929061462a9084906bffffffffffffffffffffffff16615a7d565b82546bffffffffffffffffffffffff91821661010093840a908102920219161790915573ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832067ffffffffffffffff80891685529252909120805460019450909284926146a0928492900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050565b600061472d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166147d79092919063ffffffff16565b805190915015611211578080602001905181019061474b9190615f9f565b611211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107df565b60606147e684846000856147ee565b949350505050565b606082471015614880576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107df565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516148a99190615fc1565b60006040518083038185875af1925050503d80600081146148e6576040519150601f19603f3d011682016040523d82523d6000602084013e6148eb565b606091505b50915091506148fc87838387614907565b979650505050505050565b6060831561499d5782516000036149965773ffffffffffffffffffffffffffffffffffffffff85163b614996576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107df565b50816147e6565b6147e683838151156149b25781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107df9190614c8e565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a21578251825591602001919060010190614a06565b5061372f929150614b6b565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a2157825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614a4d565b82805482825590600052602060002090600701600890048101928215614a215791602002820160005b83821115614b1457835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614ad0565b8015614b445782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614b14565b505061372f929150614b6b565b508054600082559060005260206000209081019061078091905b5b8082111561372f5760008155600101614b6c565b67ffffffffffffffff8116811461078057600080fd5b8035614ba181614b80565b919050565b600060208284031215614bb857600080fd5b8135614bc381614b80565b9392505050565b63ffffffff8116811461078057600080fd5b8035614ba181614bca565b60008060408385031215614bfa57600080fd5b8235614c0581614b80565b91506020830135614c1581614bca565b809150509250929050565b60005b83811015614c3b578181015183820152602001614c23565b50506000910152565b60008151808452614c5c816020860160208601614c20565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000614bc36020830184614c44565b60008060408385031215614cb457600080fd5b8235614cbf81614b80565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715614d2057614d20614ccd565b60405290565b60405160e0810167ffffffffffffffff81118282101715614d2057614d20614ccd565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614d9057614d90614ccd565b604052919050565b600082601f830112614da957600080fd5b813567ffffffffffffffff811115614dc357614dc3614ccd565b614df460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614d49565b818152846020838601011115614e0957600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e26565b73ffffffffffffffffffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e4b565b68ffffffffffffffffff8116811461078057600080fd5b8035614ba181614e78565b64ffffffffff8116811461078057600080fd5b8035614ba181614e9a565b60006101608284031215614ecb57600080fd5b614ed3614cfc565b905081358152614ee560208301614e6d565b6020820152614ef660408301614e40565b6040820152614f0760608301614e6d565b6060820152614f1860808301614b96565b6080820152614f2960a08301614bdc565b60a0820152614f3a60c08301614e8f565b60c0820152614f4b60e08301614e8f565b60e0820152610100614f5e818401614ead565b90820152610120614f70838201614ead565b90820152610140614f82838201614bdc565b9082015292915050565b6000806000806000806102008789031215614fa657600080fd5b863567ffffffffffffffff80821115614fbe57600080fd5b614fca8a838b01614d98565b97506020890135915080821115614fe057600080fd5b50614fed89828a01614d98565b9550506040870135614ffe81614e26565b9350606087013561500e81614e26565b9250608087013561501e81614e4b565b915061502d8860a08901614eb8565b90509295509295509295565b60078110615070577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b604081016150828285615039565b6bffffffffffffffffffffffff831660208301529392505050565b600067ffffffffffffffff8211156150b7576150b7614ccd565b5060051b60200190565b600082601f8301126150d257600080fd5b813560206150e76150e28361509d565b614d49565b82815260059290921b8401810191818101908684111561510657600080fd5b8286015b8481101561512a57803561511d81614e4b565b835291830191830161510a565b509695505050505050565b6000806040838503121561514857600080fd5b823567ffffffffffffffff8082111561516057600080fd5b818501915085601f83011261517457600080fd5b813560206151846150e28361509d565b82815260059290921b840181019181810190898411156151a357600080fd5b948201945b838610156151c1578535825294820194908201906151a8565b965050860135925050808211156151d757600080fd5b506151e4858286016150c1565b9150509250929050565b60008083601f84011261520057600080fd5b50813567ffffffffffffffff81111561521857600080fd5b60208301915083602082850101111561523057600080fd5b9250929050565b803561ffff81168114614ba157600080fd5b60008060008060008060a0878903121561526257600080fd5b863561526d81614b80565b9550602087013567ffffffffffffffff81111561528957600080fd5b61529589828a016151ee565b90965094506152a8905060408801615237565b925060608701356152b881614bca565b80925050608087013590509295509295509295565b600080604083850312156152e057600080fd5b82356152eb81614b80565b91506020830135614c1581614e4b565b6000806040838503121561530e57600080fd5b823561531981614e4b565b91506020830135614c1581614e26565b80357fffffffff0000000000000000000000000000000000000000000000000000000081168114614ba157600080fd5b600082601f83011261536a57600080fd5b8135602061537a6150e28361509d565b82815260059290921b8401810191818101908684111561539957600080fd5b8286015b8481101561512a5780356153b081614bca565b835291830191830161539d565b6000602082840312156153cf57600080fd5b813567ffffffffffffffff808211156153e757600080fd5b9083019060e082860312156153fb57600080fd5b615403614d26565b61540c83615237565b815261541a60208401614e8f565b602082015261542b60408401615329565b604082015261543c60608401615237565b606082015260808301358281111561545357600080fd5b61545f87828601615359565b60808301525061547160a08401615237565b60a082015261548260c08401614e8f565b60c082015295945050505050565b600080604083850312156154a357600080fd5b82356154ae81614e4b565b91506020830135614c1581614b80565b6000602082840312156154d057600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561551d57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016154eb565b509495945050505050565b60006bffffffffffffffffffffffff808351168452602083015173ffffffffffffffffffffffffffffffffffffffff8082166020870152826040860151166040870152806060860151166060870152505050608082015160c0608085015261559360c08501826154d7565b60a093840151949093019390935250919050565b602081526000614bc36020830184615528565b600080600080606085870312156155d057600080fd5b84356155db81614e4b565b935060208501359250604085013567ffffffffffffffff8111156155fe57600080fd5b61560a878288016151ee565b95989497509550505050565b604080825283519082018190526000906020906060840190828701845b8281101561564f57815184529284019290840190600101615633565b5050508381038285015261566381866154d7565b9695505050505050565b60006020808352610100830161ffff808651168386015268ffffffffffffffffff838701511660408601527fffffffff00000000000000000000000000000000000000000000000000000000604087015116606086015280606087015116608086015250608085015160e060a0860152818151808452610120870191508483019350600092505b8083101561571a57835163ffffffff1682529284019260019290920191908401906156f4565b5060a087015161ffff811660c0880152935060c087015168ffffffffffffffffff811660e08801529350615663565b60006020828403121561575b57600080fd5b8135614bc381614e4b565b6000806020838503121561577957600080fd5b823567ffffffffffffffff8082111561579157600080fd5b818501915085601f8301126157a557600080fd5b8135818111156157b457600080fd5b866020610160830285010111156157ca57600080fd5b60209290920196919550909350505050565b600080604083850312156157ef57600080fd5b82356154ae81614b80565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561586d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261585b858351615528565b94509285019290850190600101615821565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff848116825283166020820152606081016147e66040830184615039565b8151815260208083015161016083019161590c9084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604083015161592c60408401826bffffffffffffffffffffffff169052565b506060830151615954606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151615970608084018267ffffffffffffffff169052565b5060a083015161598860a084018263ffffffff169052565b5060c08301516159a560c084018268ffffffffffffffffff169052565b5060e08301516159c260e084018268ffffffffffffffffff169052565b506101008381015164ffffffffff81168483015250506101208381015164ffffffffff81168483015250506101408381015163ffffffff8116848301525b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b64ffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff818116838216028082169190828114615a0057615a00615a08565b6bffffffffffffffffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff8716815273ffffffffffffffffffffffffffffffffffffffff86166020820152615adc6040820186615039565b60c060608201526000615af260c0830186614c44565b8281036080840152615b048186614c44565b905082810360a0840152615b188185614c44565b9998505050505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615b5657615b56615a08565b5060010190565b6bffffffffffffffffffffffff8281168282160390808211156131a1576131a1615a08565b600060ff821660ff8103615b9857615b98615a08565b60010192915050565b8181038181111561150957611509615a08565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600067ffffffffffffffff808316818103615c0057615c00615a08565b6001019392505050565b8082018082111561150957611509615a08565b600060208284031215615c2f57600080fd5b5051919050565b60006101608284031215615c4957600080fd5b614bc38383614eb8565b67ffffffffffffffff8181168382160190808211156131a1576131a1615a08565b67ffffffffffffffff8281168282160390808211156131a1576131a1615a08565b838152606060208201526000615cae6060830185614c44565b82810360408401526156638185614c44565b6020815260008251610160806020850152615cdf610180850183614c44565b9150602085015160408501526040850151615d12606086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060608501516bffffffffffffffffffffffff8116608086015250608085015168ffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015167ffffffffffffffff811660e08601525060e0850151610100615d898187018363ffffffff169052565b8601519050610120615da08682018361ffff169052565b8601519050610140615dbd8682018367ffffffffffffffff169052565b9095015173ffffffffffffffffffffffffffffffffffffffff1693019290925250919050565b8051614ba181614e4b565b8051614ba181614e26565b8051614ba181614b80565b8051614ba181614bca565b8051614ba181614e78565b8051614ba181614e9a565b60006101608284031215615e3857600080fd5b615e40614cfc565b82518152615e5060208401615de3565b6020820152615e6160408401615dee565b6040820152615e7260608401615de3565b6060820152615e8360808401615df9565b6080820152615e9460a08401615e04565b60a0820152615ea560c08401615e0f565b60c0820152615eb660e08401615e0f565b60e0820152610100615ec9818501615e1a565b90820152610120615edb848201615e1a565b90820152610140615eed848201615e04565b908201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525060e06060830152615f3960e0830187614c44565b61ffff9590951660808301525063ffffffff9290921660a08301526bffffffffffffffffffffffff1660c090910152949350505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006147e66040830184614c44565b600060208284031215615fb157600080fd5b81518015158114614bc357600080fd5b60008251615fd3818460208701614c20565b919091019291505056fea164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotRemoveWithPendingRequests\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"DuplicateRequestId\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyRequestData\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"limit\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"IdentifierIsReserved\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint96\",\"name\":\"currentBalanceJuels\",\"type\":\"uint96\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"value\",\"type\":\"uint8\"}],\"name\":\"InvalidGasFlagValue\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidProposal\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"}],\"name\":\"MustBeProposedOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeSubscriptionOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromCoordinator\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableFromLink\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"RouteNotFound\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"SenderMustAcceptTermsOfService\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TimeoutNotExceeded\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"maximumConsumers\",\"type\":\"uint16\"}],\"name\":\"TooManyConsumers\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"indexed\":false,\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"proposedContractSetId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetFromAddress\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"proposedContractSetToAddress\",\"type\":\"address\"}],\"name\":\"ContractProposed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"ContractUpdated\",\"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\":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\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"}],\"name\":\"RequestNotProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"callbackReturnData\",\"type\":\"bytes\"}],\"name\":\"RequestProcessed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestStart\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"RequestTimedOut\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"fundsRecipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"fundsAmount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"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\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"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\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"SubscriptionOwnerTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"MAX_CALLBACK_RETURN_BYTES\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"\",\"type\":\"uint16\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"createSubscriptionWithConsumer\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"response\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"err\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"internalType\":\"uint96\",\"name\":\"costWithoutFulfillment\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"fulfill\",\"outputs\":[{\"internalType\":\"enumFunctionsResponse.FulfillResult\",\"name\":\"resultCode\",\"type\":\"uint8\"},{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllowListId\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getConsumer\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"}],\"internalType\":\"structIFunctionsSubscriptions.Consumer\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getFlags\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"id\",\"type\":\"bytes32\"}],\"name\":\"getProposedContractById\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getProposedContractSet\",\"outputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSubscriptionCount\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionIdStart\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionIdEnd\",\"type\":\"uint64\"}],\"name\":\"getSubscriptionsInRange\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"blockedBalance\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"proposedOwner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"internalType\":\"structIFunctionsSubscriptions.Subscription[]\",\"name\":\"subscriptions\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"}],\"name\":\"isValidCallbackGasLimit\",\"outputs\":[],\"stateMutability\":\"view\",\"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\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"ownerWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"}],\"name\":\"pendingRequestExists\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[]\",\"name\":\"proposedContractSetIds\",\"type\":\"bytes32[]\"},{\"internalType\":\"address[]\",\"name\":\"proposedContractSetAddresses\",\"type\":\"address[]\"}],\"name\":\"proposeContractsUpdate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"proposeSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"recoverFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"donId\",\"type\":\"bytes32\"}],\"name\":\"sendRequestToProposed\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"allowListId\",\"type\":\"bytes32\"}],\"name\":\"setAllowListId\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"}],\"name\":\"setFlags\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment[]\",\"name\":\"requestsToTimeoutByCommitment\",\"type\":\"tuple[]\"}],\"name\":\"timeoutRequests\",\"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\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint16\",\"name\":\"maxConsumersPerSubscription\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"bytes4\",\"name\":\"handleOracleFulfillmentSelector\",\"type\":\"bytes4\"},{\"internalType\":\"uint16\",\"name\":\"gasForCallExactCheck\",\"type\":\"uint16\"},{\"internalType\":\"uint32[]\",\"name\":\"maxCallbackGasLimits\",\"type\":\"uint32[]\"},{\"internalType\":\"uint16\",\"name\":\"subscriptionDepositMinimumRequests\",\"type\":\"uint16\"},{\"internalType\":\"uint72\",\"name\":\"subscriptionDepositJuels\",\"type\":\"uint72\"}],\"internalType\":\"structFunctionsRouter.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"updateContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b506040516200673c3803806200673c833981016040819052620000349162000549565b6001600160a01b0382166080526006805460ff191690553380600081620000a25760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600680546001600160a01b0380851661010002610100600160a81b031990921691909117909155811615620000dc57620000dc81620000f8565b505050620000f081620001aa60201b60201c565b50506200071a565b336001600160a01b03821603620001525760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000099565b600780546001600160a01b0319166001600160a01b03838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b620001b4620002c0565b8051600a80546020808501516040860151606087015161ffff908116600160781b0261ffff60781b1960e09390931c6b010000000000000000000000029290921665ffffffffffff60581b196001600160481b0390941662010000026001600160581b031990961691909716179390931716939093171781556080830151805184936200024792600b9291019062000323565b5060a08201516002909101805460c0909301516001600160481b031662010000026001600160581b031990931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e98590620002b590839062000652565b60405180910390a150565b60065461010090046001600160a01b03163314620003215760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000099565b565b82805482825590600052602060002090600701600890048101928215620003c75791602002820160005b838211156200039357835183826101000a81548163ffffffff021916908363ffffffff16021790555092602001926004016020816003010492830192600103026200034d565b8015620003c55782816101000a81549063ffffffff021916905560040160208160030104928301926001030262000393565b505b50620003d5929150620003d9565b5090565b5b80821115620003d55760008155600101620003da565b634e487b7160e01b600052604160045260246000fd5b60405160e081016001600160401b03811182821017156200042b576200042b620003f0565b60405290565b604051601f8201601f191681016001600160401b03811182821017156200045c576200045c620003f0565b604052919050565b805161ffff811681146200047757600080fd5b919050565b80516001600160481b03811681146200047757600080fd5b80516001600160e01b0319811681146200047757600080fd5b600082601f830112620004bf57600080fd5b815160206001600160401b03821115620004dd57620004dd620003f0565b8160051b620004ee82820162000431565b92835284810182019282810190878511156200050957600080fd5b83870192505b848310156200053e57825163ffffffff811681146200052e5760008081fd5b825291830191908301906200050f565b979650505050505050565b600080604083850312156200055d57600080fd5b82516001600160a01b03811681146200057557600080fd5b60208401519092506001600160401b03808211156200059357600080fd5b9084019060e08287031215620005a857600080fd5b620005b262000406565b620005bd8362000464565b8152620005cd602084016200047c565b6020820152620005e06040840162000494565b6040820152620005f36060840162000464565b60608201526080830151828111156200060b57600080fd5b6200061988828601620004ad565b6080830152506200062d60a0840162000464565b60a08201526200064060c084016200047c565b60c08201528093505050509250929050565b6020808252825161ffff90811683830152838201516001600160481b03166040808501919091528401516001600160e01b0319166060808501919091528401511660808084019190915283015160e060a0840152805161010084018190526000929182019083906101208601905b80831015620006e857835163ffffffff168252928401926001929092019190840190620006c0565b5060a087015161ffff811660c0880152935060c08701516001600160481b03811660e088015293509695505050505050565b608051615fea62000752600039600081816111cd0152818161208c015281816129b801528181612a7c01526135d30152615fea6000f3fe608060405234801561001057600080fd5b50600436106102e95760003560e01c80637341c10c11610191578063b734c0f4116100e3578063e72f6e3011610097578063ea320e0b11610071578063ea320e0b146106dd578063ec2454e5146106f0578063f2fde38b1461071057600080fd5b8063e72f6e30146106a4578063e82622aa146106b7578063e82ad7d4146106ca57600080fd5b8063c3f909d4116100c8578063c3f909d414610669578063cc77470a1461067e578063d7ae1d301461069157600080fd5b8063b734c0f41461064b578063badc3eb61461065357600080fd5b80639f87fad711610145578063a4c0ed361161011f578063a4c0ed361461061d578063a9c9a91814610630578063aab396bd1461064357600080fd5b80639f87fad7146105e2578063a21a23e4146105f5578063a47c7696146105fd57600080fd5b8063823597401161017657806382359740146105a45780638456cb59146105b75780638da5cb5b146105bf57600080fd5b80637341c10c1461058957806379ba50971461059c57600080fd5b806341db4ca31161024a5780635ed6dfba116101fe57806366419970116101d857806366419970146104e1578063674603d0146105085780636a2215de1461055157600080fd5b80635ed6dfba146104a85780636162a323146104bb57806366316d8d146104ce57600080fd5b80634b8832d31161022f5780634b8832d31461045057806355fedefa146104635780635c975abb1461049157600080fd5b806341db4ca31461041c578063461d27621461043d57600080fd5b80631ded3b36116102a1578063330605291161028657806333060529146103e05780633e871e4d146104015780633f4ba83a1461041457600080fd5b80631ded3b361461039f5780632a905ccc146103b257600080fd5b806310fc49c1116102d257806310fc49c11461032357806312b5834914610336578063181f5a771461035657600080fd5b806302bcc5b6146102ee5780630c5d49cb14610303575b600080fd5b6103016102fc366004614ba6565b610723565b005b61030b608481565b60405161ffff90911681526020015b60405180910390f35b610301610331366004614be7565b610783565b6000546040516bffffffffffffffffffffffff909116815260200161031a565b6103926040518060400160405280601781526020017f46756e6374696f6e7320526f757465722076322e302e3000000000000000000081525081565b60405161031a9190614c8e565b6103016103ad366004614ca1565b61087f565b600a5462010000900468ffffffffffffffffff1660405168ffffffffffffffffff909116815260200161031a565b6103f36103ee366004614f8c565b6108b1565b60405161031a929190615074565b61030161040f366004615135565b610c7c565b610301610e91565b61042f61042a366004615249565b610ea3565b60405190815260200161031a565b61042f61044b366004615249565b610f03565b61030161045e3660046152cd565b610f0f565b61042f610471366004614ba6565b67ffffffffffffffff166000908152600360208190526040909120015490565b60065460ff165b604051901515815260200161031a565b6103016104b63660046152fb565b61105d565b6103016104c93660046153bd565b611216565b6103016104dc3660046152fb565b611396565b60025467ffffffffffffffff165b60405167ffffffffffffffff909116815260200161031a565b61051b610516366004615490565b61147f565b6040805182511515815260208084015167ffffffffffffffff90811691830191909152928201519092169082015260600161031a565b61056461055f3660046154be565b61150f565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161031a565b6103016105973660046152cd565b6115ce565b610301611781565b6103016105b2366004614ba6565b6118a8565b6103016119ef565b600654610100900473ffffffffffffffffffffffffffffffffffffffff16610564565b6103016105f03660046152cd565b6119ff565b6104ef611daa565b61061061060b366004614ba6565b611f37565b60405161031a91906155a7565b61030161062b3660046155ba565b61206c565b61056461063e3660046154be565b6122b8565b60095461042f565b610301612317565b61065b612463565b60405161031a929190615616565b610671612533565b60405161031a919061566d565b6104ef61068c366004615749565b61269a565b61030161069f3660046152cd565b61291a565b6103016106b2366004615749565b61297f565b6103016106c5366004615766565b612af8565b6104986106d8366004614ba6565b612db7565b6103016106eb3660046154be565b612f06565b6107036106fe3660046157dc565b612f13565b60405161031a91906157fa565b61030161071e366004615749565b6131a8565b61072b6131b9565b610734816131c1565b67ffffffffffffffff81166000908152600360205260408120546107809183916c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690613237565b50565b67ffffffffffffffff8216600090815260036020819052604082200154600b54911a9081106107e8576040517f45c108ce00000000000000000000000000000000000000000000000000000000815260ff821660048201526024015b60405180910390fd5b6000600a6001018260ff16815481106108035761080361587a565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1690508063ffffffff168363ffffffff161115610879576040517f1d70f87a00000000000000000000000000000000000000000000000000000000815263ffffffff821660048201526024016107df565b50505050565b6108876131b9565b610890826131c1565b67ffffffffffffffff90911660009081526003602081905260409091200155565b6000806108bc613689565b826020015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610925576040517f8bec23e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82516000908152600560205260409020548061098a5783516020850151604051600295507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b60405180910390a25060009050610c71565b808460405160200161099c91906158db565b60405160208183030381529060405280519060200120146109f45783516020850151604051600695507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b8361012001518460a0015163ffffffff16610a0f9190615a37565b64ffffffffff165a1015610a5a5783516020850151604051600495507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee19161097891899088906158a9565b506000610a708460a0015163ffffffff16613691565b610a7a9088615a55565b9050600081878660c0015168ffffffffffffffffff16610a9a9190615a7d565b610aa49190615a7d565b9050610ab38560800151611f37565b600001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b2b5784516020860151604051600596507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b60405180910390a25060009150610c719050565b84604001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff161115610b905784516020860151604051600396507f1a90e9a50793db2e394cf581e7c522e10c358a81e70acf6b5a0edd620c08dee191610b17918a9089906158a9565b505082516000908152600560205260408120819055835160a08501516060860151610bc092918c918c9190613733565b8051909150610bd0576001610bd3565b60005b92506000610c0d8560800151866040015187606001518860c0015168ffffffffffffffffff168c610c078860200151613691565b8d6138f1565b9050846080015167ffffffffffffffff1685600001517f64778f26c70b60a8d7e29e2451b3844302d959448401c0535b768ed88c6b505e836020015189888f8f8960400151604051610c6496959493929190615aa2565b60405180910390a3519150505b965096945050505050565b610c84613c17565b8151815181141580610c965750600881115b15610ccd576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610e47576000848281518110610cec57610cec61587a565b602002602001015190506000848381518110610d0a57610d0a61587a565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161480610d75575060008281526008602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116145b15610dac576040517fee03280800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260086020526040908190205490517f8b052f0f4bf82fede7daffea71592b29d5ef86af1f3c7daaa0345dbb2f52f48191610e2c91859173ffffffffffffffffffffffffffffffffffffffff1690859092835273ffffffffffffffffffffffffffffffffffffffff918216602084015216604082015260600190565b60405180910390a1505080610e4090615b25565b9050610cd0565b506040805180820190915283815260208082018490528451600d91610e709183918801906149e6565b506020828101518051610e899260018501920190614a2d565b505050505050565b610e99613c17565b610ea1613c9d565b565b600080610eaf8361150f565b9050610ef783828a8a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508c92508b9150613d1a9050565b98975050505050505050565b600080610eaf836122b8565b610f17613689565b610f20826140ef565b610f286141b5565b73ffffffffffffffffffffffffffffffffffffffff81161580610f8f575067ffffffffffffffff821660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff8281166c0100000000000000000000000090920416145b15610fc6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff821660008181526003602090815260409182902060010180546bffffffffffffffffffffffff166c0100000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8716908102919091179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be910160405180910390a25050565b6110656131b9565b806bffffffffffffffffffffffff1660000361109b5750306000908152600160205260409020546bffffffffffffffffffffffff165b306000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611107576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b30600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550816000808282829054906101000a90046bffffffffffffffffffffffff1661118a9190615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061121183836bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b505050565b61121e613c17565b8051600a80546020808501516040860151606087015161ffff9081166f01000000000000000000000000000000027fffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffff60e09390931c6b01000000000000000000000002929092167fffffffffffffffffffffffffffffff000000000000ffffffffffffffffffffff68ffffffffffffffffff90941662010000027fffffffffffffffffffffffffffffffffffffffffff0000000000000000000000909616919097161793909317169390931717815560808301518051849361130592600b92910190614aa7565b5060a08201516002909101805460c09093015168ffffffffffffffffff1662010000027fffffffffffffffffffffffffffffffffffffffffff000000000000000000000090931661ffff909216919091179190911790556040517ea5832bf95f66c7814294cc4db681f20ee79608bfb8912a5321d66cfed5e9859061138b90839061566d565b60405180910390a150565b61139e613689565b806bffffffffffffffffffffffff166000036113e6576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600160205260409020546bffffffffffffffffffffffff908116908216811015611452576040517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff821660048201526024016107df565b33600090815260016020526040812080548492906111349084906bffffffffffffffffffffffff16615b5d565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff861681526004835283812067ffffffffffffffff868116835290845290849020845192830185525460ff81161515835261010081048216938301939093526901000000000000000000909204909116918101919091525b92915050565b6000805b600d5460ff8216101561159857600d805460ff83169081106115375761153761587a565b9060005260206000200154830361158857600e805460ff831690811061155f5761155f61587a565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff169392505050565b61159181615b82565b9050611513565b506040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018390526024016107df565b6115d6613689565b6115df826140ef565b6115e76141b5565b60006115f6600a5461ffff1690565b67ffffffffffffffff841660009081526003602052604090206002015490915061ffff821611611658576040517fb72bc70300000000000000000000000000000000000000000000000000000000815261ffff821660048201526024016107df565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8716845290915290205460ff16156116a057505050565b73ffffffffffffffffffffffffffffffffffffffff8216600081815260046020908152604080832067ffffffffffffffff881680855290835281842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600384528285206002018054918201815585529383902090930180547fffffffffffffffffffffffff000000000000000000000000000000000000000016851790555192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091015b60405180910390a2505050565b60075473ffffffffffffffffffffffffffffffffffffffff163314611802576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016107df565b600680547fffffffffffffffffffffff0000000000000000000000000000000000000000ff81166101003381810292909217909355600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556040519290910473ffffffffffffffffffffffffffffffffffffffff169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6118b0613689565b6118b86141b5565b67ffffffffffffffff81166000908152600360205260409020805460019091015473ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481169290910416338114611958576040517f4e1d9f1800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016107df565b67ffffffffffffffff831660008181526003602090815260409182902080546c01000000000000000000000000339081026bffffffffffffffffffffffff928316178355600190920180549091169055825173ffffffffffffffffffffffffffffffffffffffff87168152918201527f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f09101611774565b6119f7613c17565b610ea161434c565b611a07613689565b611a10826140ef565b611a186141b5565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260046020908152604080832067ffffffffffffffff8087168552908352928190208151606081018352905460ff8116151582526101008104851693820193909352690100000000000000000090920490921691810191909152611a9782846143a7565b806040015167ffffffffffffffff16816020015167ffffffffffffffff1614611aec576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8316600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611b6757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611b3c575b5050505050905060005b8151811015611d0f578373ffffffffffffffffffffffffffffffffffffffff16828281518110611ba357611ba361587a565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611cff578160018351611bd59190615ba1565b81518110611be557611be561587a565b6020026020010151600360008767ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018281548110611c2857611c2861587a565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925567ffffffffffffffff87168152600390915260409020600201805480611ca257611ca2615bb4565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055611d0f565b611d0881615b25565b9050611b71565b5073ffffffffffffffffffffffffffffffffffffffff8316600081815260046020908152604080832067ffffffffffffffff89168085529083529281902080547fffffffffffffffffffffffffffffff00000000000000000000000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b910160405180910390a250505050565b6000611db4613689565b611dbc6141b5565b60028054600090611dd69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c0810182526000808252336020830152918101829052606081018290529192506080820190604051908082528060200260200182016040528015611e4c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff9384161784559386015160608701519091169093029216919091176001820155608083015180519192611ee792600285019290910190614a2d565b5060a0919091015160039091015560405133815267ffffffffffffffff8216907f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a290565b6040805160c0810182526000808252602082018190529181018290526060808201839052608082015260a0810191909152611f71826131c1565b67ffffffffffffffff8216600090815260036020908152604091829020825160c08101845281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c0100000000000000000000000092839004811684870152600185015491821684880152919004166060820152600282018054855181860281018601909652808652919492936080860193929083018282801561205257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612027575b505050505081526020016003820154815250509050919050565b612074613689565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146120e3576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020811461211d576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061212b82840184614ba6565b67ffffffffffffffff81166000908152600360205260409020549091506c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff166121a4576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260036020526040812080546bffffffffffffffffffffffff16918691906121db8385615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550846000808282829054906101000a90046bffffffffffffffffffffffff166122319190615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f88287846122989190615c0a565b6040805192835260208301919091520160405180910390a2505050505050565b60008181526008602052604081205473ffffffffffffffffffffffffffffffffffffffff1680611509576040517f80833e33000000000000000000000000000000000000000000000000000000008152600481018490526024016107df565b61231f613c17565b60005b600d54811015612442576000600d60000182815481106123445761234461587a565b906000526020600020015490506000600d60010183815481106123695761236961587a565b6000918252602080832091909101548483526008825260409283902054835186815273ffffffffffffffffffffffffffffffffffffffff91821693810193909352169181018290529091507ff8a6175bca1ba37d682089187edc5e20a859989727f10ca6bd9a5bc0de8caf949060600160405180910390a160009182526008602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905561243b81615b25565b9050612322565b50600d60006124518282614b51565b61245f600183016000614b51565b5050565b606080600d600001600d600101818054806020026020016040519081016040528092919081815260200182805480156124bb57602002820191906000526020600020905b8154815260200190600101908083116124a7575b505050505091508080548060200260200160405190810160405280929190818152602001828054801561252457602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116124f9575b50505050509050915091509091565b6040805160e0810182526000808252602082018190529181018290526060808201839052608082015260a0810182905260c08101919091526040805160e08082018352600a805461ffff808216855262010000820468ffffffffffffffffff166020808701919091526b010000000000000000000000830490941b7fffffffff0000000000000000000000000000000000000000000000000000000016858701526f01000000000000000000000000000000909104166060840152600b805485518185028101850190965280865293949193608086019383018282801561266557602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff16815260200190600401906020826003010492830192600103820291508084116126285790505b50505091835250506002919091015461ffff8116602083015262010000900468ffffffffffffffffff16604090910152919050565b60006126a4613689565b6126ac6141b5565b600280546000906126c69067ffffffffffffffff16615be3565b825467ffffffffffffffff8083166101009490940a93840293021916919091179091556040805160c081018252600080825233602083015291810182905260608101829052919250608082019060405190808252806020026020018201604052801561273c578160200160208202803683370190505b5081526000602091820181905267ffffffffffffffff841681526003825260409081902083518484015173ffffffffffffffffffffffffffffffffffffffff9081166c010000000000000000000000009081026bffffffffffffffffffffffff93841617845593860151606087015190911690930292169190911760018201556080830151805191926127d792600285019290910190614a2d565b5060a0919091015160039182015567ffffffffffffffff82166000818152602092835260408082206002018054600180820183559184528584200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff891690811790915583526004855281832084845285529181902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169092179091555133815290917f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf910160405180910390a260405173ffffffffffffffffffffffffffffffffffffffff8316815267ffffffffffffffff8216907f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e09060200160405180910390a2919050565b612922613689565b61292b826140ef565b6129336141b5565b61293c82612db7565b15612973576040517f06eb10c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61245f82826001613237565b6129876131b9565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612a14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a389190615c1d565b6000549091506bffffffffffffffffffffffff1681811015611211576000612a608284615ba1565b9050612aa373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001685836142bf565b6040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a150505050565b612b00613689565b60005b81811015611211576000838383818110612b1f57612b1f61587a565b90506101600201803603810190612b369190615c36565b80516080820151600082815260056020908152604091829020549151949550929391929091612b67918691016158db565b6040516020818303038152906040528051906020012014612bb4576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82610140015163ffffffff16421015612bf9576040517fa2376fe800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208301516040517f85b214cf0000000000000000000000000000000000000000000000000000000081526004810184905273ffffffffffffffffffffffffffffffffffffffff909116906385b214cf90602401600060405180830381600087803b158015612c6757600080fd5b505af1158015612c7b573d6000803e3d6000fd5b50505060408085015167ffffffffffffffff84166000908152600360205291822060010180549193509190612cbf9084906bffffffffffffffffffffffff16615b5d565b82546bffffffffffffffffffffffff9182166101009390930a928302919092021990911617905550606083015173ffffffffffffffffffffffffffffffffffffffff16600090815260046020908152604080832067ffffffffffffffff808616855292529091208054600192600991612d479185916901000000000000000000900416615c53565b825467ffffffffffffffff9182166101009390930a9283029190920219909116179055506000828152600560205260408082208290555183917ff1ca1e9147be737b04a2b018a79405f687a97de8dd8a2559bbe62357343af41491a250505080612db090615b25565b9050612b03565b67ffffffffffffffff8116600090815260036020908152604080832060020180548251818502810185019093528083528493830182828015612e2f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311612e04575b5050505050905060005b8151811015612efc57600060046000848481518110612e5a57612e5a61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff808a168352908452908290208251606081018452905460ff8116151582526101008104831694820185905269010000000000000000009004909116918101829052925014612eeb57506001949350505050565b50612ef581615b25565b9050612e39565b5060009392505050565b612f0e613c17565b600955565b60608167ffffffffffffffff168367ffffffffffffffff161180612f46575060025467ffffffffffffffff908116908316115b80612f5b575060025467ffffffffffffffff16155b15612f92576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612f9c8383615c74565b612fa7906001615c53565b67ffffffffffffffff1667ffffffffffffffff811115612fc957612fc9614ccd565b60405190808252806020026020018201604052801561304657816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083015260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181612fe75790505b50905060005b6130568484615c74565b67ffffffffffffffff1681116131a1576003600061307e8367ffffffffffffffff8816615c0a565b67ffffffffffffffff1681526020808201929092526040908101600020815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561316057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311613135575b505050505081526020016003820154815250508282815181106131855761318561587a565b60200260200101819052508061319a90615b25565b905061304c565b5092915050565b6131b0613c17565b6107808161441b565b610ea1613c17565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16610780576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff83166000908152600360209081526040808320815160c08101835281546bffffffffffffffffffffffff808216835273ffffffffffffffffffffffffffffffffffffffff6c010000000000000000000000009283900481168488015260018501549182168487015291900416606082015260028201805484518187028101870190955280855291949293608086019390929083018282801561331857602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116132ed575b50505091835250506003919091015460209091015280519091506000805b83608001515181101561342e5760008460800151828151811061335b5761335b61587a565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff8116600090815260048352604080822067ffffffffffffffff808e16845294529020549092506133bb9169010000000000000000009091041684615c53565b73ffffffffffffffffffffffffffffffffffffffff909116600090815260046020908152604080832067ffffffffffffffff8c168452909152902080547fffffffffffffffffffffffffffffff0000000000000000000000000000000000169055915061342781615b25565b9050613336565b5067ffffffffffffffff8616600090815260036020526040812081815560018101829055906134606002830182614b51565b50600060039190910155600c5461ffff81169062010000900468ffffffffffffffffff1685801561349e57508161ffff168367ffffffffffffffff16105b1561355a576000846bffffffffffffffffffffffff168268ffffffffffffffffff16116134d6578168ffffffffffffffffff166134d8565b845b90506bffffffffffffffffffffffff81161561355857306000908152600160205260408120805483929061351b9084906bffffffffffffffffffffffff16615a7d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080856135559190615b5d565b94505b505b6bffffffffffffffffffffffff841615613617576000805485919081906135909084906bffffffffffffffffffffffff16615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555061361787856bffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166142bf9092919063ffffffff16565b6040805173ffffffffffffffffffffffffffffffffffffffff891681526bffffffffffffffffffffffff8616602082015267ffffffffffffffff8a16917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050505050565b610ea1614517565b60006bffffffffffffffffffffffff82111561372f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f362062697473000000000000000000000000000000000000000000000000000060648201526084016107df565b5090565b60408051606080820183526000808352602083015291810191909152813b1580156137865750506040805160608101825260008082526020808301829052835191825281018352918101919091526138e8565b600a546040516000916b010000000000000000000000900460e01b906137b4908a908a908a90602401615c95565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009590951694909417909352600a548151608480825260c0820190935292945061ffff6f01000000000000000000000000000000909104169260009283928392820181803683370190505090505a8481101561388257600080fd5b8490036040810481038a1061389657600080fd5b505a60008087516020890160008d8ff193505a900391503d60848111156138bb575060845b808252806000602084013e5060408051606081018252931515845260208401929092529082015293505050505b95945050505050565b604080518082019091526000808252602082015260006139118486615a55565b90506000816139208886615a7d565b61392a9190615a7d565b67ffffffffffffffff8b166000908152600360205260409020549091506bffffffffffffffffffffffff80831691161080613991575067ffffffffffffffff8a166000908152600360205260409020600101546bffffffffffffffffffffffff808b169116105b156139f45767ffffffffffffffff8a16600090815260036020526040908190205490517f6b0fe56f0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff90911660048201526024016107df565b67ffffffffffffffff8a1660009081526003602052604081208054839290613a2b9084906bffffffffffffffffffffffff16615b5d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915567ffffffffffffffff8c16600090815260036020526040812060010180548d94509092613a7f91859116615b5d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508184613ab99190615a7d565b3360009081526001602052604081208054909190613ae69084906bffffffffffffffffffffffff16615a7d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915530600090815260016020526040812080548b94509092613b2d91859116615a7d565b82546bffffffffffffffffffffffff9182166101009390930a92830291909202199091161790555073ffffffffffffffffffffffffffffffffffffffff8816600090815260046020908152604080832067ffffffffffffffff808f16855292529091208054600192600991613bb19185916901000000000000000000900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040518060400160405280836bffffffffffffffffffffffff168152602001826bffffffffffffffffffffffff1681525092505050979650505050505050565b600654610100900473ffffffffffffffffffffffffffffffffffffffff163314610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107df565b613ca5614584565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000613d24613689565b613d2d856131c1565b613d3733866143a7565b613d418583610783565b8351600003613d7b576040517ec1cfc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000613d8686611f37565b90506000613d94338861147f565b600a54604080516101608101825289815267ffffffffffffffff8b1660009081526003602081815293822001549495506201000090930468ffffffffffffffffff169373ffffffffffffffffffffffffffffffffffffffff8d169263a631571e929190820190815233602082015260408881015189519190920191613e1891615b5d565b6bffffffffffffffffffffffff1681526020018568ffffffffffffffffff1681526020018c67ffffffffffffffff168152602001866020015167ffffffffffffffff1681526020018963ffffffff1681526020018a61ffff168152602001866040015167ffffffffffffffff168152602001876020015173ffffffffffffffffffffffffffffffffffffffff168152506040518263ffffffff1660e01b8152600401613ec49190615cc0565b610160604051808303816000875af1158015613ee4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f089190615e25565b805160009081526005602052604090205490915015613f595780516040517f304f32e800000000000000000000000000000000000000000000000000000000815260048101919091526024016107df565b604051806101600160405280826000015181526020018b73ffffffffffffffffffffffffffffffffffffffff16815260200182604001516bffffffffffffffffffffffff1681526020013373ffffffffffffffffffffffffffffffffffffffff1681526020018a67ffffffffffffffff1681526020018763ffffffff1681526020018368ffffffffffffffffff1681526020018260e0015168ffffffffffffffffff16815260200182610100015164ffffffffff16815260200182610120015164ffffffffff16815260200182610140015163ffffffff1681525060405160200161404491906158db565b60405160208183030381529060405280519060200120600560008360000151815260200190815260200160002081905550614084338a83604001516145f0565b8867ffffffffffffffff168b82600001517ff67aec45c9a7ede407974a3e0c3a743dffeab99ee3f2d4c9a8144c2ebf2c7ec9876020015133328e8e8e8a604001516040516140d89796959493929190615ef8565b60405180910390a4519a9950505050505050505050565b67ffffffffffffffff81166000908152600360205260409020546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1680614166576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82161461245f576040517f5a68151d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60095460009081526008602052604090205473ffffffffffffffffffffffffffffffffffffffff16806141e55750565b604080516000815260208101918290527f6b14daf80000000000000000000000000000000000000000000000000000000090915273ffffffffffffffffffffffffffffffffffffffff821690636b14daf89061424690339060248101615f70565b602060405180830381865afa158015614263573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142879190615f9f565b610780576040517f229062630000000000000000000000000000000000000000000000000000000081523360048201526024016107df565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790526112119084906146cb565b614354614517565b600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258613cf03390565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260046020908152604080832067ffffffffffffffff8516845290915290205460ff1661245f576040517f71e8313700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff82160361449a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107df565b600780547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600654604051919261010090910416907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b60065460ff1615610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016107df565b60065460ff16610ea1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016107df565b67ffffffffffffffff82166000908152600360205260408120600101805483929061462a9084906bffffffffffffffffffffffff16615a7d565b82546bffffffffffffffffffffffff91821661010093840a908102920219161790915573ffffffffffffffffffffffffffffffffffffffff8516600090815260046020908152604080832067ffffffffffffffff80891685529252909120805460019450909284926146a0928492900416615c53565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505050565b600061472d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166147d79092919063ffffffff16565b805190915015611211578080602001905181019061474b9190615f9f565b611211576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016107df565b60606147e684846000856147ee565b949350505050565b606082471015614880576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016107df565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516148a99190615fc1565b60006040518083038185875af1925050503d80600081146148e6576040519150601f19603f3d011682016040523d82523d6000602084013e6148eb565b606091505b50915091506148fc87838387614907565b979650505050505050565b6060831561499d5782516000036149965773ffffffffffffffffffffffffffffffffffffffff85163b614996576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107df565b50816147e6565b6147e683838151156149b25781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107df9190614c8e565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a21578251825591602001919060010190614a06565b5061372f929150614b6b565b828054828255906000526020600020908101928215614a21579160200282015b82811115614a2157825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190614a4d565b82805482825590600052602060002090600701600890048101928215614a215791602002820160005b83821115614b1457835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614ad0565b8015614b445782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614b14565b505061372f929150614b6b565b508054600082559060005260206000209081019061078091905b5b8082111561372f5760008155600101614b6c565b67ffffffffffffffff8116811461078057600080fd5b8035614ba181614b80565b919050565b600060208284031215614bb857600080fd5b8135614bc381614b80565b9392505050565b63ffffffff8116811461078057600080fd5b8035614ba181614bca565b60008060408385031215614bfa57600080fd5b8235614c0581614b80565b91506020830135614c1581614bca565b809150509250929050565b60005b83811015614c3b578181015183820152602001614c23565b50506000910152565b60008151808452614c5c816020860160208601614c20565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000614bc36020830184614c44565b60008060408385031215614cb457600080fd5b8235614cbf81614b80565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610160810167ffffffffffffffff81118282101715614d2057614d20614ccd565b60405290565b60405160e0810167ffffffffffffffff81118282101715614d2057614d20614ccd565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614d9057614d90614ccd565b604052919050565b600082601f830112614da957600080fd5b813567ffffffffffffffff811115614dc357614dc3614ccd565b614df460207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601614d49565b818152846020838601011115614e0957600080fd5b816020850160208301376000918101602001919091529392505050565b6bffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e26565b73ffffffffffffffffffffffffffffffffffffffff8116811461078057600080fd5b8035614ba181614e4b565b68ffffffffffffffffff8116811461078057600080fd5b8035614ba181614e78565b64ffffffffff8116811461078057600080fd5b8035614ba181614e9a565b60006101608284031215614ecb57600080fd5b614ed3614cfc565b905081358152614ee560208301614e6d565b6020820152614ef660408301614e40565b6040820152614f0760608301614e6d565b6060820152614f1860808301614b96565b6080820152614f2960a08301614bdc565b60a0820152614f3a60c08301614e8f565b60c0820152614f4b60e08301614e8f565b60e0820152610100614f5e818401614ead565b90820152610120614f70838201614ead565b90820152610140614f82838201614bdc565b9082015292915050565b6000806000806000806102008789031215614fa657600080fd5b863567ffffffffffffffff80821115614fbe57600080fd5b614fca8a838b01614d98565b97506020890135915080821115614fe057600080fd5b50614fed89828a01614d98565b9550506040870135614ffe81614e26565b9350606087013561500e81614e26565b9250608087013561501e81614e4b565b915061502d8860a08901614eb8565b90509295509295509295565b60078110615070577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b604081016150828285615039565b6bffffffffffffffffffffffff831660208301529392505050565b600067ffffffffffffffff8211156150b7576150b7614ccd565b5060051b60200190565b600082601f8301126150d257600080fd5b813560206150e76150e28361509d565b614d49565b82815260059290921b8401810191818101908684111561510657600080fd5b8286015b8481101561512a57803561511d81614e4b565b835291830191830161510a565b509695505050505050565b6000806040838503121561514857600080fd5b823567ffffffffffffffff8082111561516057600080fd5b818501915085601f83011261517457600080fd5b813560206151846150e28361509d565b82815260059290921b840181019181810190898411156151a357600080fd5b948201945b838610156151c1578535825294820194908201906151a8565b965050860135925050808211156151d757600080fd5b506151e4858286016150c1565b9150509250929050565b60008083601f84011261520057600080fd5b50813567ffffffffffffffff81111561521857600080fd5b60208301915083602082850101111561523057600080fd5b9250929050565b803561ffff81168114614ba157600080fd5b60008060008060008060a0878903121561526257600080fd5b863561526d81614b80565b9550602087013567ffffffffffffffff81111561528957600080fd5b61529589828a016151ee565b90965094506152a8905060408801615237565b925060608701356152b881614bca565b80925050608087013590509295509295509295565b600080604083850312156152e057600080fd5b82356152eb81614b80565b91506020830135614c1581614e4b565b6000806040838503121561530e57600080fd5b823561531981614e4b565b91506020830135614c1581614e26565b80357fffffffff0000000000000000000000000000000000000000000000000000000081168114614ba157600080fd5b600082601f83011261536a57600080fd5b8135602061537a6150e28361509d565b82815260059290921b8401810191818101908684111561539957600080fd5b8286015b8481101561512a5780356153b081614bca565b835291830191830161539d565b6000602082840312156153cf57600080fd5b813567ffffffffffffffff808211156153e757600080fd5b9083019060e082860312156153fb57600080fd5b615403614d26565b61540c83615237565b815261541a60208401614e8f565b602082015261542b60408401615329565b604082015261543c60608401615237565b606082015260808301358281111561545357600080fd5b61545f87828601615359565b60808301525061547160a08401615237565b60a082015261548260c08401614e8f565b60c082015295945050505050565b600080604083850312156154a357600080fd5b82356154ae81614e4b565b91506020830135614c1581614b80565b6000602082840312156154d057600080fd5b5035919050565b600081518084526020808501945080840160005b8381101561551d57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016154eb565b509495945050505050565b60006bffffffffffffffffffffffff808351168452602083015173ffffffffffffffffffffffffffffffffffffffff8082166020870152826040860151166040870152806060860151166060870152505050608082015160c0608085015261559360c08501826154d7565b60a093840151949093019390935250919050565b602081526000614bc36020830184615528565b600080600080606085870312156155d057600080fd5b84356155db81614e4b565b935060208501359250604085013567ffffffffffffffff8111156155fe57600080fd5b61560a878288016151ee565b95989497509550505050565b604080825283519082018190526000906020906060840190828701845b8281101561564f57815184529284019290840190600101615633565b5050508381038285015261566381866154d7565b9695505050505050565b60006020808352610100830161ffff808651168386015268ffffffffffffffffff838701511660408601527fffffffff00000000000000000000000000000000000000000000000000000000604087015116606086015280606087015116608086015250608085015160e060a0860152818151808452610120870191508483019350600092505b8083101561571a57835163ffffffff1682529284019260019290920191908401906156f4565b5060a087015161ffff811660c0880152935060c087015168ffffffffffffffffff811660e08801529350615663565b60006020828403121561575b57600080fd5b8135614bc381614e4b565b6000806020838503121561577957600080fd5b823567ffffffffffffffff8082111561579157600080fd5b818501915085601f8301126157a557600080fd5b8135818111156157b457600080fd5b866020610160830285010111156157ca57600080fd5b60209290920196919550909350505050565b600080604083850312156157ef57600080fd5b82356154ae81614b80565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561586d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845261585b858351615528565b94509285019290850190600101615821565b5092979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff848116825283166020820152606081016147e66040830184615039565b8151815260208083015161016083019161590c9084018273ffffffffffffffffffffffffffffffffffffffff169052565b50604083015161592c60408401826bffffffffffffffffffffffff169052565b506060830151615954606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080830151615970608084018267ffffffffffffffff169052565b5060a083015161598860a084018263ffffffff169052565b5060c08301516159a560c084018268ffffffffffffffffff169052565b5060e08301516159c260e084018268ffffffffffffffffff169052565b506101008381015164ffffffffff81168483015250506101208381015164ffffffffff81168483015250506101408381015163ffffffff8116848301525b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b64ffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff818116838216028082169190828114615a0057615a00615a08565b6bffffffffffffffffffffffff8181168382160190808211156131a1576131a1615a08565b6bffffffffffffffffffffffff8716815273ffffffffffffffffffffffffffffffffffffffff86166020820152615adc6040820186615039565b60c060608201526000615af260c0830186614c44565b8281036080840152615b048186614c44565b905082810360a0840152615b188185614c44565b9998505050505050505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203615b5657615b56615a08565b5060010190565b6bffffffffffffffffffffffff8281168282160390808211156131a1576131a1615a08565b600060ff821660ff8103615b9857615b98615a08565b60010192915050565b8181038181111561150957611509615a08565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600067ffffffffffffffff808316818103615c0057615c00615a08565b6001019392505050565b8082018082111561150957611509615a08565b600060208284031215615c2f57600080fd5b5051919050565b60006101608284031215615c4957600080fd5b614bc38383614eb8565b67ffffffffffffffff8181168382160190808211156131a1576131a1615a08565b67ffffffffffffffff8281168282160390808211156131a1576131a1615a08565b838152606060208201526000615cae6060830185614c44565b82810360408401526156638185614c44565b6020815260008251610160806020850152615cdf610180850183614c44565b9150602085015160408501526040850151615d12606086018273ffffffffffffffffffffffffffffffffffffffff169052565b5060608501516bffffffffffffffffffffffff8116608086015250608085015168ffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015167ffffffffffffffff811660e08601525060e0850151610100615d898187018363ffffffff169052565b8601519050610120615da08682018361ffff169052565b8601519050610140615dbd8682018367ffffffffffffffff169052565b9095015173ffffffffffffffffffffffffffffffffffffffff1693019290925250919050565b8051614ba181614e4b565b8051614ba181614e26565b8051614ba181614b80565b8051614ba181614bca565b8051614ba181614e78565b8051614ba181614e9a565b60006101608284031215615e3857600080fd5b615e40614cfc565b82518152615e5060208401615de3565b6020820152615e6160408401615dee565b6040820152615e7260608401615de3565b6060820152615e8360808401615df9565b6080820152615e9460a08401615e04565b60a0820152615ea560c08401615e0f565b60c0820152615eb660e08401615e0f565b60e0820152610100615ec9818501615e1a565b90820152610120615edb848201615e1a565b90820152610140615eed848201615e04565b908201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808a168352808916602084015280881660408401525060e06060830152615f3960e0830187614c44565b61ffff9590951660808301525063ffffffff9290921660a08301526bffffffffffffffffffffffff1660c090910152949350505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040602082015260006147e66040830184614c44565b600060208284031215615fb157600080fd5b81518015158114614bc357600080fd5b60008251615fd3818460208701614c20565b919091019291505056fea164736f6c6343000813000a", } var FunctionsRouterABI = FunctionsRouterMetaData.ABI @@ -677,16 +677,16 @@ func (_FunctionsRouter *FunctionsRouterTransactorSession) CreateSubscriptionWith return _FunctionsRouter.Contract.CreateSubscriptionWithConsumer(&_FunctionsRouter.TransactOpts, consumer) } -func (_FunctionsRouter *FunctionsRouterTransactor) Fulfill(opts *bind.TransactOpts, response []byte, err []byte, juelsPerGas *big.Int, costWithoutCallback *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { - return _FunctionsRouter.contract.Transact(opts, "fulfill", response, err, juelsPerGas, costWithoutCallback, transmitter, commitment) +func (_FunctionsRouter *FunctionsRouterTransactor) Fulfill(opts *bind.TransactOpts, response []byte, err []byte, juelsPerGas *big.Int, costWithoutFulfillment *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { + return _FunctionsRouter.contract.Transact(opts, "fulfill", response, err, juelsPerGas, costWithoutFulfillment, transmitter, commitment) } -func (_FunctionsRouter *FunctionsRouterSession) Fulfill(response []byte, err []byte, juelsPerGas *big.Int, costWithoutCallback *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { - return _FunctionsRouter.Contract.Fulfill(&_FunctionsRouter.TransactOpts, response, err, juelsPerGas, costWithoutCallback, transmitter, commitment) +func (_FunctionsRouter *FunctionsRouterSession) Fulfill(response []byte, err []byte, juelsPerGas *big.Int, costWithoutFulfillment *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { + return _FunctionsRouter.Contract.Fulfill(&_FunctionsRouter.TransactOpts, response, err, juelsPerGas, costWithoutFulfillment, transmitter, commitment) } -func (_FunctionsRouter *FunctionsRouterTransactorSession) Fulfill(response []byte, err []byte, juelsPerGas *big.Int, costWithoutCallback *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { - return _FunctionsRouter.Contract.Fulfill(&_FunctionsRouter.TransactOpts, response, err, juelsPerGas, costWithoutCallback, transmitter, commitment) +func (_FunctionsRouter *FunctionsRouterTransactorSession) Fulfill(response []byte, err []byte, juelsPerGas *big.Int, costWithoutFulfillment *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) { + return _FunctionsRouter.Contract.Fulfill(&_FunctionsRouter.TransactOpts, response, err, juelsPerGas, costWithoutFulfillment, transmitter, commitment) } func (_FunctionsRouter *FunctionsRouterTransactor) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { @@ -3510,7 +3510,7 @@ type FunctionsRouterInterface interface { CreateSubscriptionWithConsumer(opts *bind.TransactOpts, consumer common.Address) (*types.Transaction, error) - Fulfill(opts *bind.TransactOpts, response []byte, err []byte, juelsPerGas *big.Int, costWithoutCallback *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) + Fulfill(opts *bind.TransactOpts, response []byte, err []byte, juelsPerGas *big.Int, costWithoutFulfillment *big.Int, transmitter common.Address, commitment FunctionsResponseCommitment) (*types.Transaction, error) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) diff --git a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt index ac1fc4e83d6..16bb718e7c1 100644 --- a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,13 +1,13 @@ -GETH_VERSION: 1.12.0 +GETH_VERSION: 1.13.8 functions: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRequest.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRequest.bin 3c972870b0afeb6d73a29ebb182f24956a2cebb127b21c4f867d1ecf19a762db -functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.bin b2697ad4dfece903a1d34028826a017fa445eb3cd984006f1734fa9d47836ca0 +functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.abi ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServiceAllowList.bin 586696a0cacc0e5112bdd6c99535748a3fbf08c9319360aee868831d38a96d7b functions_billing_registry_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 functions_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.bin 2368f537a04489c720a46733f8596c4fc88a31062ecfa966d05f25dd98608aca functions_client_example: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.bin abf32e69f268f40e8530eb8d8e96bf310b798a4c0049a58022d9d2fb527b601b -functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 97aa7c56d78c703056990eff102279af86b97b11b5855b059e8dd658dc15da8a +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 7e8a63d56d81fe16a51d4196f5ca3e9623eaa04b56a6e8d7dee1eb0c266944ab functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.bin c8dbbd5ebb34435800d6674700068837c3a252db60046a14b0e61e829db517de functions_oracle_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c -functions_router: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.bin 9dedd3a36043605fd9bedf821e7ec5b4281a5c7ae2e4a1955f37aff8ba13519f +functions_router: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.bin 1f6d18f9e0846ad74b37a0a6acef5942ab73ace1e84307f201899f69e732e776 functions_v1_events_mock: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsV1EventsMock.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsV1EventsMock.bin 0f0ba42e0cc33c7abc8b8fd4fdfce903748a169886dd5f16cfdd56e75bcf708d ocr2dr: ../../../contracts/solc/v0.8.6/functions/v0_0_0/Functions.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/Functions.bin d9a794b33f47cc57563d216f7cf3a612309fc3062356a27e30005cf1d59e449d ocr2dr_client: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClient.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsClient.bin 84aa63f9dbc5c7eac240db699b09e613ca4c6cd56dab10bdc25b02461b717e21 diff --git a/core/gethwrappers/generated/automation_registrar_wrapper2_2/automation_registrar_wrapper2_2.go b/core/gethwrappers/generated/automation_registrar_wrapper2_2/automation_registrar_wrapper2_2.go new file mode 100644 index 00000000000..c8a84800447 --- /dev/null +++ b/core/gethwrappers/generated/automation_registrar_wrapper2_2/automation_registrar_wrapper2_2.go @@ -0,0 +1,1685 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package automation_registrar_wrapper2_2 + +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 AutomationRegistrar22InitialTriggerConfig struct { + TriggerType uint8 + AutoApproveType uint8 + AutoApproveMaxAllowed uint32 +} + +type AutomationRegistrar22RegistrationParams struct { + Name string + EncryptedEmail []byte + UpkeepContract common.Address + GasLimit uint32 + AdminAddress common.Address + TriggerType uint8 + CheckData []byte + TriggerConfig []byte + OffchainConfig []byte + Amount *big.Int +} + +type AutomationRegistrar22TriggerRegistrationStorage struct { + AutoApproveType uint8 + AutoApproveMaxAllowed uint32 + ApprovedCount uint32 +} + +var AutomationRegistrarMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"LINKAddress\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"minLINKJuels\",\"type\":\"uint96\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_2.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_2.InitialTriggerConfig[]\",\"name\":\"triggerConfigs\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"AmountMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FunctionNotPermitted\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"HashMismatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientPayment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidAdminAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"LinkTransferFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyAdminOrOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyLink\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RegistrationRequestFailed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RequestNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"SenderMismatch\",\"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\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"minLINKJuels\",\"type\":\"uint96\"}],\"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_2.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"}],\"name\":\"TriggerConfigSet\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"LINK\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"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\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"minLINKJuels\",\"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\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"}],\"name\":\"getTriggerRegistrationDetails\",\"outputs\":[{\"components\":[{\"internalType\":\"enumAutomationRegistrar2_2.AutoApproveType\",\"name\":\"autoApproveType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"autoApproveMaxAllowed\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"approvedCount\",\"type\":\"uint32\"}],\"internalType\":\"structAutomationRegistrar2_2.TriggerRegistrationStorage\",\"name\":\"\",\"type\":\"tuple\"}],\"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\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"bytes\",\"name\":\"encryptedEmail\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"upkeepContract\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"adminAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"internalType\":\"structAutomationRegistrar2_2.RegistrationParams\",\"name\":\"requestParams\",\"type\":\"tuple\"}],\"name\":\"registerUpkeep\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"senderAddress\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowed\",\"type\":\"bool\"}],\"name\":\"setAutoApproveAllowedSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"AutomationRegistry\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"minLINKJuels\",\"type\":\"uint96\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"enumAutomationRegistrar2_2.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: "0x60a06040523480156200001157600080fd5b5060405162002d8238038062002d8283398101604081905262000034916200043b565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be816200017a565b5050506001600160a01b038416608052620000da838362000225565b60005b81518110156200016f576200015a82828151811062000100576200010062000598565b60200260200101516000015183838151811062000121576200012162000598565b60200260200101516020015184848151811062000142576200014262000598565b6020026020010151604001516200029e60201b60201c565b806200016681620005ae565b915050620000dd565b50505050506200062f565b336001600160a01b03821603620001d45760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6200022f6200034c565b6040805180820182526001600160a01b0384168082526001600160601b0384166020928301819052600160a01b810282176004558351918252918101919091527f39ce5d867555f0b0183e358fce5b158e7ca4fecd7c01cb7e0e19f1e23285838a910160405180910390a15050565b620002a86200034c565b60ff83166000908152600360205260409020805483919060ff19166001836002811115620002da57620002da620005d6565b021790555060ff831660009081526003602052604090819020805464ffffffff00191661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a3906200033f90859085908590620005ec565b60405180910390a1505050565b6000546001600160a01b03163314620003a85760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000082565b565b80516001600160a01b0381168114620003c257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715620004025762000402620003c7565b60405290565b604051601f8201601f191681016001600160401b0381118282101715620004335762000433620003c7565b604052919050565b600080600080608085870312156200045257600080fd5b6200045d85620003aa565b935060206200046e818701620003aa565b604087810151919550906001600160601b03811681146200048e57600080fd5b606088810151919550906001600160401b0380821115620004ae57600080fd5b818a0191508a601f830112620004c357600080fd5b815181811115620004d857620004d8620003c7565b620004e8868260051b0162000408565b818152868101925090840283018601908c8211156200050657600080fd5b928601925b81841015620005875784848e031215620005255760008081fd5b6200052f620003dd565b845160ff81168114620005425760008081fd5b81528488015160038110620005575760008081fd5b818901528487015163ffffffff81168114620005735760008081fd5b81880152835292840192918601916200050b565b999c989b5096995050505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201620005cf57634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052602160045260246000fd5b60ff8416815260608101600384106200061557634e487b7160e01b600052602160045260246000fd5b83602083015263ffffffff83166040830152949350505050565b6080516127146200066e60003960008181610177015281816105d601528181610887015281816109bd01528181610f0e015261171b01526127146000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c8063856853e6116100b2578063b5ff5b4111610081578063c4d252f511610066578063c4d252f5146103e3578063e8d4070d146103f6578063f2fde38b1461040957600080fd5b8063b5ff5b4114610369578063c3f909d41461037c57600080fd5b8063856853e61461027857806388b12d551461028b5780638da5cb5b14610338578063a4c0ed361461035657600080fd5b80633f678e11116100ee5780633f678e11146101f35780636c4cdfc31461021457806379ba5097146102275780637e776f7f1461022f57600080fd5b8063181f5a77146101205780631b6b6d2314610172578063212d0884146101be578063367b9b4f146101de575b600080fd5b61015c6040518060400160405280601981526020017f4175746f6d6174696f6e52656769737472617220322e312e300000000000000081525081565b6040516101699190611a74565b60405180910390f35b6101997f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610169565b6101d16101cc366004611aa4565b61041c565b6040516101699190611b29565b6101f16101ec366004611b9d565b6104a9565b005b610206610201366004611bd6565b61053b565b604051908152602001610169565b6101f1610222366004611c2e565b6106d3565b6101f161076d565b61026861023d366004611c63565b73ffffffffffffffffffffffffffffffffffffffff1660009081526005602052604090205460ff1690565b6040519015158152602001610169565b6101f1610286366004611de1565b61086f565b6102ff610299366004611f40565b60009081526002602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169290910182905291565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff909116602083015201610169565b60005473ffffffffffffffffffffffffffffffffffffffff16610199565b6101f1610364366004611f59565b6109a5565b6101f1610377366004611fb5565b610ce3565b60408051808201825260045473ffffffffffffffffffffffffffffffffffffffff8116808352740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff16602092830181905283519182529181019190915201610169565b6101f16103f1366004611f40565b610dc2565b6101f1610404366004611ffe565b61104c565b6101f1610417366004611c63565b6112d9565b60408051606080820183526000808352602080840182905283850182905260ff86811683526003909152908490208451928301909452835492939192839116600281111561046c5761046c611abf565b600281111561047d5761047d611abf565b8152905463ffffffff610100820481166020840152650100000000009091041660409091015292915050565b6104b16112ed565b73ffffffffffffffffffffffffffffffffffffffff821660008181526005602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001685151590811790915591519182527f20c6237dac83526a849285a9f79d08a483291bdd3a056a0ef9ae94ecee1ad356910160405180910390a25050565b6004546000907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1661057961014084016101208501612109565b6bffffffffffffffffffffffff1610156105bf576040517fcd1c886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166323b872dd333061060f61014087016101208801612109565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301526bffffffffffffffffffffffff1660448201526064016020604051808303816000875af1158015610696573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106ba9190612124565b506106cd6106c783612141565b33611370565b92915050565b6106db6112ed565b60408051808201825273ffffffffffffffffffffffffffffffffffffffff84168082526bffffffffffffffffffffffff8416602092830181905274010000000000000000000000000000000000000000810282176004558351918252918101919091527f39ce5d867555f0b0183e358fce5b158e7ca4fecd7c01cb7e0e19f1e23285838a910160405180910390a15050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146107f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146108de576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109966040518061014001604052808e81526020018d8d8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525073ffffffffffffffffffffffffffffffffffffffff808d16602083015263ffffffff8c1660408301528a16606082015260ff8916608082015260a0810188905260c0810187905260e081018690526bffffffffffffffffffffffff85166101009091015282611370565b50505050505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a14576040517f018d10be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81818080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050505060208101517fffffffff0000000000000000000000000000000000000000000000000000000081167f856853e60000000000000000000000000000000000000000000000000000000014610aca576040517fe3d6792100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8484846000610adc8260048186612276565b810190610ae991906122a0565b509950505050505050505050806bffffffffffffffffffffffff168414610b3c576040517f55e97b0d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8988886000610b4e8260048186612276565b810190610b5b91906122a0565b9a50505050505050505050508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610bcc576040517ff8c5638e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff168d1015610c2e576040517fcd1c886700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003073ffffffffffffffffffffffffffffffffffffffff168d8d604051610c579291906123dd565b600060405180830381855af49150503d8060008114610c92576040519150601f19603f3d011682016040523d82523d6000602084013e610c97565b606091505b5050905080610cd2576040517f649bf81000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050505050565b610ceb6112ed565b60ff8316600090815260036020526040902080548391907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836002811115610d3857610d38611abf565b021790555060ff83166000908152600360205260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1661010063ffffffff851602179055517f830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a390610db5908590859085906123ed565b60405180910390a1505050565b60008181526002602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff1691830191909152331480610e49575060005473ffffffffffffffffffffffffffffffffffffffff1633145b610e7f576040517f61685c2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805173ffffffffffffffffffffffffffffffffffffffff16610ecd576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260026020908152604080832083905583519184015190517fa9059cbb0000000000000000000000000000000000000000000000000000000081527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169263a9059cbb92610f859260040173ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b6020604051808303816000875af1158015610fa4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fc89190612124565b90508061101c5781516040517fc2e4dce800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90911660048201526024016107ea565b60405183907f3663fb28ebc87645eb972c9dad8521bf665c623f287e79f1c56f1eb374b82a2290600090a2505050565b6110546112ed565b60008181526002602090815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116808452740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff16918301919091526110ed576040517f4b13b31e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008b8b8b8b8b8b8b8b8b60405160200161111099989796959493929190612461565b604051602081830303815290604052805190602001209050808314611161576040517f3f4d605300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60026000848152602001908152602001600020600080820160006101000a81549073ffffffffffffffffffffffffffffffffffffffff02191690556000820160146101000a8154906bffffffffffffffffffffffff021916905550506112c96040518061014001604052808f81526020016040518060200160405280600081525081526020018e73ffffffffffffffffffffffffffffffffffffffff1681526020018d63ffffffff1681526020018c73ffffffffffffffffffffffffffffffffffffffff1681526020018b60ff1681526020018a8a8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060208082018a905260408051601f8a0183900483028101830182528981529201919089908990819084018382808284376000920191909152505050908252506020858101516bffffffffffffffffffffffff1691015282611647565b5050505050505050505050505050565b6112e16112ed565b6112ea81611876565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461136e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016107ea565b565b608082015160009073ffffffffffffffffffffffffffffffffffffffff166113c4576040517f05bb467c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008360400151846060015185608001518660a001518760c001518860e0015189610100015160405160200161140097969594939291906124e7565b604051602081830303815290604052805190602001209050836040015173ffffffffffffffffffffffffffffffffffffffff16817f7684390ebb103102f7f48c71439c2408713f8d437782a6fab2756acc0e42c1b786600001518760200151886060015189608001518a60a001518b60e001518c61010001518d60c001518e610120015160405161149999989796959493929190612569565b60405180910390a360a084015160ff9081166000908152600360205260408082208151606081019092528054929361151c9383911660028111156114df576114df611abf565b60028111156114f0576114f0611abf565b8152905463ffffffff61010082048116602084015265010000000000909104166040909101528561196b565b156115845760a085015160ff166000908152600360205260409020805465010000000000900463ffffffff1690600561155483612653565b91906101000a81548163ffffffff021916908363ffffffff1602179055505061157d8583611647565b905061163f565b61012085015160008381526002602052604081205490916115ca917401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16612676565b604080518082018252608089015173ffffffffffffffffffffffffffffffffffffffff90811682526bffffffffffffffffffffffff9384166020808401918252600089815260029091529390932091519251909316740100000000000000000000000000000000000000000291909216179055505b949350505050565b600480546040808501516060860151608087015160a088015160c089015160e08a01516101008b015196517f28f32f3800000000000000000000000000000000000000000000000000000000815260009973ffffffffffffffffffffffffffffffffffffffff909916988a988a986328f32f38986116d29891979096919590949193909291016124e7565b6020604051808303816000875af11580156116f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171591906126a2565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634000aea0848861012001518560405160200161176f91815260200190565b6040516020818303038152906040526040518463ffffffff1660e01b815260040161179c939291906126bb565b6020604051808303816000875af11580156117bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117df9190612124565b905080611830576040517fc2e4dce800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201526024016107ea565b81857fb9a292fb7e3edd920cd2d2829a3615a640c43fd7de0a0820aa0668feb4c37d4b88600001516040516118659190611a74565b60405180910390a350949350505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036118f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016107ea565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000808351600281111561198157611981611abf565b0361198e575060006106cd565b6001835160028111156119a3576119a3611abf565b1480156119d6575073ffffffffffffffffffffffffffffffffffffffff821660009081526005602052604090205460ff16155b156119e3575060006106cd565b826020015163ffffffff16836040015163ffffffff161015611a07575060016106cd565b50600092915050565b6000815180845260005b81811015611a3657602081850181015186830182015201611a1a565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000611a876020830184611a10565b9392505050565b803560ff81168114611a9f57600080fd5b919050565b600060208284031215611ab657600080fd5b611a8782611a8e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110611b25577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b6000606082019050611b3c828451611aee565b602083015163ffffffff8082166020850152806040860151166040850152505092915050565b73ffffffffffffffffffffffffffffffffffffffff811681146112ea57600080fd5b8035611a9f81611b62565b80151581146112ea57600080fd5b60008060408385031215611bb057600080fd5b8235611bbb81611b62565b91506020830135611bcb81611b8f565b809150509250929050565b600060208284031215611be857600080fd5b813567ffffffffffffffff811115611bff57600080fd5b82016101408185031215611a8757600080fd5b80356bffffffffffffffffffffffff81168114611a9f57600080fd5b60008060408385031215611c4157600080fd5b8235611c4c81611b62565b9150611c5a60208401611c12565b90509250929050565b600060208284031215611c7557600080fd5b8135611a8781611b62565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610140810167ffffffffffffffff81118282101715611cd357611cd3611c80565b60405290565b600082601f830112611cea57600080fd5b813567ffffffffffffffff80821115611d0557611d05611c80565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611d4b57611d4b611c80565b81604052838152866020858801011115611d6457600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008083601f840112611d9657600080fd5b50813567ffffffffffffffff811115611dae57600080fd5b602083019150836020828501011115611dc657600080fd5b9250929050565b803563ffffffff81168114611a9f57600080fd5b6000806000806000806000806000806000806101608d8f031215611e0457600080fd5b67ffffffffffffffff8d351115611e1a57600080fd5b611e278e8e358f01611cd9565b9b5067ffffffffffffffff60208e01351115611e4257600080fd5b611e528e60208f01358f01611d84565b909b509950611e6360408e01611b84565b9850611e7160608e01611dcd565b9750611e7f60808e01611b84565b9650611e8d60a08e01611a8e565b955067ffffffffffffffff60c08e01351115611ea857600080fd5b611eb88e60c08f01358f01611cd9565b945067ffffffffffffffff60e08e01351115611ed357600080fd5b611ee38e60e08f01358f01611cd9565b935067ffffffffffffffff6101008e01351115611eff57600080fd5b611f108e6101008f01358f01611cd9565b9250611f1f6101208e01611c12565b9150611f2e6101408e01611b84565b90509295989b509295989b509295989b565b600060208284031215611f5257600080fd5b5035919050565b60008060008060608587031215611f6f57600080fd5b8435611f7a81611b62565b935060208501359250604085013567ffffffffffffffff811115611f9d57600080fd5b611fa987828801611d84565b95989497509550505050565b600080600060608486031215611fca57600080fd5b611fd384611a8e565b9250602084013560038110611fe757600080fd5b9150611ff560408501611dcd565b90509250925092565b60008060008060008060008060008060006101208c8e03121561202057600080fd5b67ffffffffffffffff808d35111561203757600080fd5b6120448e8e358f01611cd9565b9b5061205260208e01611b84565b9a5061206060408e01611dcd565b995061206e60608e01611b84565b985061207c60808e01611a8e565b97508060a08e0135111561208f57600080fd5b61209f8e60a08f01358f01611d84565b909750955060c08d01358110156120b557600080fd5b6120c58e60c08f01358f01611cd9565b94508060e08e013511156120d857600080fd5b506120e98d60e08e01358e01611d84565b81945080935050506101008c013590509295989b509295989b9093969950565b60006020828403121561211b57600080fd5b611a8782611c12565b60006020828403121561213657600080fd5b8151611a8781611b8f565b6000610140823603121561215457600080fd5b61215c611caf565b823567ffffffffffffffff8082111561217457600080fd5b61218036838701611cd9565b8352602085013591508082111561219657600080fd5b6121a236838701611cd9565b60208401526121b360408601611b84565b60408401526121c460608601611dcd565b60608401526121d560808601611b84565b60808401526121e660a08601611a8e565b60a084015260c08501359150808211156121ff57600080fd5b61220b36838701611cd9565b60c084015260e085013591508082111561222457600080fd5b61223036838701611cd9565b60e08401526101009150818501358181111561224b57600080fd5b61225736828801611cd9565b8385015250505061012061226c818501611c12565b9082015292915050565b6000808585111561228657600080fd5b8386111561229357600080fd5b5050820193919092039150565b60008060008060008060008060008060006101608c8e0312156122c257600080fd5b67ffffffffffffffff808d3511156122d957600080fd5b6122e68e8e358f01611cd9565b9b508060208e013511156122f957600080fd5b6123098e60208f01358f01611cd9565b9a5061231760408e01611b84565b995061232560608e01611dcd565b985061233360808e01611b84565b975061234160a08e01611a8e565b96508060c08e0135111561235457600080fd5b6123648e60c08f01358f01611cd9565b95508060e08e0135111561237757600080fd5b6123878e60e08f01358f01611cd9565b9450806101008e0135111561239b57600080fd5b506123ad8d6101008e01358e01611cd9565b92506123bc6101208d01611c12565b91506123cb6101408d01611b84565b90509295989b509295989b9093969950565b8183823760009101908152919050565b60ff84168152606081016124046020830185611aee565b63ffffffff83166040830152949350505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600073ffffffffffffffffffffffffffffffffffffffff808c16835263ffffffff8b166020840152808a1660408401525060ff8816606083015260e060808301526124b060e083018789612418565b82810360a08401526124c28187611a10565b905082810360c08401526124d7818587612418565b9c9b505050505050505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808a16835263ffffffff8916602084015280881660408401525060ff8616606083015260e0608083015261253560e0830186611a10565b82810360a08401526125478186611a10565b905082810360c084015261255b8185611a10565b9a9950505050505050505050565b600061012080835261257d8184018d611a10565b90508281036020840152612591818c611a10565b905063ffffffff8a16604084015273ffffffffffffffffffffffffffffffffffffffff8916606084015260ff8816608084015282810360a08401526125d68188611a10565b905082810360c08401526125ea8187611a10565b905082810360e08401526125fe8186611a10565b9150506bffffffffffffffffffffffff83166101008301529a9950505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff80831681810361266c5761266c612624565b6001019392505050565b6bffffffffffffffffffffffff81811683821601908082111561269b5761269b612624565b5092915050565b6000602082840312156126b457600080fd5b5051919050565b73ffffffffffffffffffffffffffffffffffffffff841681526bffffffffffffffffffffffff831660208201526060604082015260006126fe6060830184611a10565b9594505050505056fea164736f6c6343000810000a", +} + +var AutomationRegistrarABI = AutomationRegistrarMetaData.ABI + +var AutomationRegistrarBin = AutomationRegistrarMetaData.Bin + +func DeployAutomationRegistrar(auth *bind.TransactOpts, backend bind.ContractBackend, LINKAddress common.Address, AutomationRegistry common.Address, minLINKJuels *big.Int, triggerConfigs []AutomationRegistrar22InitialTriggerConfig) (common.Address, *types.Transaction, *AutomationRegistrar, error) { + parsed, err := AutomationRegistrarMetaData.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(AutomationRegistrarBin), backend, LINKAddress, AutomationRegistry, minLINKJuels, triggerConfigs) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationRegistrar{address: address, abi: *parsed, AutomationRegistrarCaller: AutomationRegistrarCaller{contract: contract}, AutomationRegistrarTransactor: AutomationRegistrarTransactor{contract: contract}, AutomationRegistrarFilterer: AutomationRegistrarFilterer{contract: contract}}, nil +} + +type AutomationRegistrar struct { + address common.Address + abi abi.ABI + AutomationRegistrarCaller + AutomationRegistrarTransactor + AutomationRegistrarFilterer +} + +type AutomationRegistrarCaller struct { + contract *bind.BoundContract +} + +type AutomationRegistrarTransactor struct { + contract *bind.BoundContract +} + +type AutomationRegistrarFilterer struct { + contract *bind.BoundContract +} + +type AutomationRegistrarSession struct { + Contract *AutomationRegistrar + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationRegistrarCallerSession struct { + Contract *AutomationRegistrarCaller + CallOpts bind.CallOpts +} + +type AutomationRegistrarTransactorSession struct { + Contract *AutomationRegistrarTransactor + TransactOpts bind.TransactOpts +} + +type AutomationRegistrarRaw struct { + Contract *AutomationRegistrar +} + +type AutomationRegistrarCallerRaw struct { + Contract *AutomationRegistrarCaller +} + +type AutomationRegistrarTransactorRaw struct { + Contract *AutomationRegistrarTransactor +} + +func NewAutomationRegistrar(address common.Address, backend bind.ContractBackend) (*AutomationRegistrar, error) { + abi, err := abi.JSON(strings.NewReader(AutomationRegistrarABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationRegistrar(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationRegistrar{address: address, abi: abi, AutomationRegistrarCaller: AutomationRegistrarCaller{contract: contract}, AutomationRegistrarTransactor: AutomationRegistrarTransactor{contract: contract}, AutomationRegistrarFilterer: AutomationRegistrarFilterer{contract: contract}}, nil +} + +func NewAutomationRegistrarCaller(address common.Address, caller bind.ContractCaller) (*AutomationRegistrarCaller, error) { + contract, err := bindAutomationRegistrar(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationRegistrarCaller{contract: contract}, nil +} + +func NewAutomationRegistrarTransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationRegistrarTransactor, error) { + contract, err := bindAutomationRegistrar(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationRegistrarTransactor{contract: contract}, nil +} + +func NewAutomationRegistrarFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationRegistrarFilterer, error) { + contract, err := bindAutomationRegistrar(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationRegistrarFilterer{contract: contract}, nil +} + +func bindAutomationRegistrar(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationRegistrarMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationRegistrar *AutomationRegistrarRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistrar.Contract.AutomationRegistrarCaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistrar *AutomationRegistrarRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.AutomationRegistrarTransactor.contract.Transfer(opts) +} + +func (_AutomationRegistrar *AutomationRegistrarRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.AutomationRegistrarTransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistrar.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.contract.Transfer(opts) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) LINK(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "LINK") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) LINK() (common.Address, error) { + return _AutomationRegistrar.Contract.LINK(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) LINK() (common.Address, error) { + return _AutomationRegistrar.Contract.LINK(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) GetAutoApproveAllowedSender(opts *bind.CallOpts, senderAddress common.Address) (bool, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "getAutoApproveAllowedSender", senderAddress) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) GetAutoApproveAllowedSender(senderAddress common.Address) (bool, error) { + return _AutomationRegistrar.Contract.GetAutoApproveAllowedSender(&_AutomationRegistrar.CallOpts, senderAddress) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetAutoApproveAllowedSender(senderAddress common.Address) (bool, error) { + return _AutomationRegistrar.Contract.GetAutoApproveAllowedSender(&_AutomationRegistrar.CallOpts, senderAddress) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) GetConfig(opts *bind.CallOpts) (GetConfig, + + error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "getConfig") + + outstruct := new(GetConfig) + if err != nil { + return *outstruct, err + } + + outstruct.AutomationRegistry = *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + outstruct.MinLINKJuels = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) GetConfig() (GetConfig, + + error) { + return _AutomationRegistrar.Contract.GetConfig(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetConfig() (GetConfig, + + error) { + return _AutomationRegistrar.Contract.GetConfig(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) GetPendingRequest(opts *bind.CallOpts, hash [32]byte) (common.Address, *big.Int, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "getPendingRequest", hash) + + if err != nil { + return *new(common.Address), *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + out1 := *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return out0, out1, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) GetPendingRequest(hash [32]byte) (common.Address, *big.Int, error) { + return _AutomationRegistrar.Contract.GetPendingRequest(&_AutomationRegistrar.CallOpts, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetPendingRequest(hash [32]byte) (common.Address, *big.Int, error) { + return _AutomationRegistrar.Contract.GetPendingRequest(&_AutomationRegistrar.CallOpts, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) GetTriggerRegistrationDetails(opts *bind.CallOpts, triggerType uint8) (AutomationRegistrar22TriggerRegistrationStorage, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "getTriggerRegistrationDetails", triggerType) + + if err != nil { + return *new(AutomationRegistrar22TriggerRegistrationStorage), err + } + + out0 := *abi.ConvertType(out[0], new(AutomationRegistrar22TriggerRegistrationStorage)).(*AutomationRegistrar22TriggerRegistrationStorage) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) GetTriggerRegistrationDetails(triggerType uint8) (AutomationRegistrar22TriggerRegistrationStorage, error) { + return _AutomationRegistrar.Contract.GetTriggerRegistrationDetails(&_AutomationRegistrar.CallOpts, triggerType) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) GetTriggerRegistrationDetails(triggerType uint8) (AutomationRegistrar22TriggerRegistrationStorage, error) { + return _AutomationRegistrar.Contract.GetTriggerRegistrationDetails(&_AutomationRegistrar.CallOpts, triggerType) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistrar.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 (_AutomationRegistrar *AutomationRegistrarSession) Owner() (common.Address, error) { + return _AutomationRegistrar.Contract.Owner(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) Owner() (common.Address, error) { + return _AutomationRegistrar.Contract.Owner(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _AutomationRegistrar.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_AutomationRegistrar *AutomationRegistrarSession) TypeAndVersion() (string, error) { + return _AutomationRegistrar.Contract.TypeAndVersion(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarCallerSession) TypeAndVersion() (string, error) { + return _AutomationRegistrar.Contract.TypeAndVersion(&_AutomationRegistrar.CallOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "acceptOwnership") +} + +func (_AutomationRegistrar *AutomationRegistrarSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistrar.Contract.AcceptOwnership(&_AutomationRegistrar.TransactOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistrar.Contract.AcceptOwnership(&_AutomationRegistrar.TransactOpts) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) Approve(opts *bind.TransactOpts, name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "approve", name, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) Approve(name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Approve(&_AutomationRegistrar.TransactOpts, name, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) Approve(name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Approve(&_AutomationRegistrar.TransactOpts, name, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) Cancel(opts *bind.TransactOpts, hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "cancel", hash) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) Cancel(hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Cancel(&_AutomationRegistrar.TransactOpts, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) Cancel(hash [32]byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Cancel(&_AutomationRegistrar.TransactOpts, hash) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "onTokenTransfer", sender, amount, data) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.OnTokenTransfer(&_AutomationRegistrar.TransactOpts, sender, amount, data) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.OnTokenTransfer(&_AutomationRegistrar.TransactOpts, sender, amount, data) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) Register(opts *bind.TransactOpts, name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "register", name, encryptedEmail, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, amount, sender) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) Register(name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Register(&_AutomationRegistrar.TransactOpts, name, encryptedEmail, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, amount, sender) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) Register(name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.Register(&_AutomationRegistrar.TransactOpts, name, encryptedEmail, upkeepContract, gasLimit, adminAddress, triggerType, checkData, triggerConfig, offchainConfig, amount, sender) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) RegisterUpkeep(opts *bind.TransactOpts, requestParams AutomationRegistrar22RegistrationParams) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "registerUpkeep", requestParams) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) RegisterUpkeep(requestParams AutomationRegistrar22RegistrationParams) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.RegisterUpkeep(&_AutomationRegistrar.TransactOpts, requestParams) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) RegisterUpkeep(requestParams AutomationRegistrar22RegistrationParams) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.RegisterUpkeep(&_AutomationRegistrar.TransactOpts, requestParams) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) SetAutoApproveAllowedSender(opts *bind.TransactOpts, senderAddress common.Address, allowed bool) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "setAutoApproveAllowedSender", senderAddress, allowed) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) SetAutoApproveAllowedSender(senderAddress common.Address, allowed bool) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetAutoApproveAllowedSender(&_AutomationRegistrar.TransactOpts, senderAddress, allowed) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) SetAutoApproveAllowedSender(senderAddress common.Address, allowed bool) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetAutoApproveAllowedSender(&_AutomationRegistrar.TransactOpts, senderAddress, allowed) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) SetConfig(opts *bind.TransactOpts, AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "setConfig", AutomationRegistry, minLINKJuels) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) SetConfig(AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetConfig(&_AutomationRegistrar.TransactOpts, AutomationRegistry, minLINKJuels) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) SetConfig(AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetConfig(&_AutomationRegistrar.TransactOpts, AutomationRegistry, minLINKJuels) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) SetTriggerConfig(opts *bind.TransactOpts, triggerType uint8, autoApproveType uint8, autoApproveMaxAllowed uint32) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "setTriggerConfig", triggerType, autoApproveType, autoApproveMaxAllowed) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) SetTriggerConfig(triggerType uint8, autoApproveType uint8, autoApproveMaxAllowed uint32) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetTriggerConfig(&_AutomationRegistrar.TransactOpts, triggerType, autoApproveType, autoApproveMaxAllowed) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) SetTriggerConfig(triggerType uint8, autoApproveType uint8, autoApproveMaxAllowed uint32) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.SetTriggerConfig(&_AutomationRegistrar.TransactOpts, triggerType, autoApproveType, autoApproveMaxAllowed) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.contract.Transact(opts, "transferOwnership", to) +} + +func (_AutomationRegistrar *AutomationRegistrarSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.TransferOwnership(&_AutomationRegistrar.TransactOpts, to) +} + +func (_AutomationRegistrar *AutomationRegistrarTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistrar.Contract.TransferOwnership(&_AutomationRegistrar.TransactOpts, to) +} + +type AutomationRegistrarAutoApproveAllowedSenderSetIterator struct { + Event *AutomationRegistrarAutoApproveAllowedSenderSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarAutoApproveAllowedSenderSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarAutoApproveAllowedSenderSet) + 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(AutomationRegistrarAutoApproveAllowedSenderSet) + 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 *AutomationRegistrarAutoApproveAllowedSenderSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarAutoApproveAllowedSenderSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarAutoApproveAllowedSenderSet struct { + SenderAddress common.Address + Allowed bool + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterAutoApproveAllowedSenderSet(opts *bind.FilterOpts, senderAddress []common.Address) (*AutomationRegistrarAutoApproveAllowedSenderSetIterator, error) { + + var senderAddressRule []interface{} + for _, senderAddressItem := range senderAddress { + senderAddressRule = append(senderAddressRule, senderAddressItem) + } + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "AutoApproveAllowedSenderSet", senderAddressRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarAutoApproveAllowedSenderSetIterator{contract: _AutomationRegistrar.contract, event: "AutoApproveAllowedSenderSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchAutoApproveAllowedSenderSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarAutoApproveAllowedSenderSet, senderAddress []common.Address) (event.Subscription, error) { + + var senderAddressRule []interface{} + for _, senderAddressItem := range senderAddress { + senderAddressRule = append(senderAddressRule, senderAddressItem) + } + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "AutoApproveAllowedSenderSet", senderAddressRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarAutoApproveAllowedSenderSet) + if err := _AutomationRegistrar.contract.UnpackLog(event, "AutoApproveAllowedSenderSet", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseAutoApproveAllowedSenderSet(log types.Log) (*AutomationRegistrarAutoApproveAllowedSenderSet, error) { + event := new(AutomationRegistrarAutoApproveAllowedSenderSet) + if err := _AutomationRegistrar.contract.UnpackLog(event, "AutoApproveAllowedSenderSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarConfigChangedIterator struct { + Event *AutomationRegistrarConfigChanged + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarConfigChangedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarConfigChanged) + 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(AutomationRegistrarConfigChanged) + 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 *AutomationRegistrarConfigChangedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarConfigChangedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarConfigChanged struct { + AutomationRegistry common.Address + MinLINKJuels *big.Int + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterConfigChanged(opts *bind.FilterOpts) (*AutomationRegistrarConfigChangedIterator, error) { + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "ConfigChanged") + if err != nil { + return nil, err + } + return &AutomationRegistrarConfigChangedIterator{contract: _AutomationRegistrar.contract, event: "ConfigChanged", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarConfigChanged) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "ConfigChanged") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarConfigChanged) + if err := _AutomationRegistrar.contract.UnpackLog(event, "ConfigChanged", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseConfigChanged(log types.Log) (*AutomationRegistrarConfigChanged, error) { + event := new(AutomationRegistrarConfigChanged) + if err := _AutomationRegistrar.contract.UnpackLog(event, "ConfigChanged", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarOwnershipTransferRequestedIterator struct { + Event *AutomationRegistrarOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarOwnershipTransferRequested) + 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(AutomationRegistrarOwnershipTransferRequested) + 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 *AutomationRegistrarOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistrarOwnershipTransferRequestedIterator, 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 := _AutomationRegistrar.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarOwnershipTransferRequestedIterator{contract: _AutomationRegistrar.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarOwnershipTransferRequested, 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 := _AutomationRegistrar.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(AutomationRegistrarOwnershipTransferRequested) + if err := _AutomationRegistrar.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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistrarOwnershipTransferRequested, error) { + event := new(AutomationRegistrarOwnershipTransferRequested) + if err := _AutomationRegistrar.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarOwnershipTransferredIterator struct { + Event *AutomationRegistrarOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarOwnershipTransferred) + 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(AutomationRegistrarOwnershipTransferred) + 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 *AutomationRegistrarOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistrarOwnershipTransferredIterator, 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 := _AutomationRegistrar.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarOwnershipTransferredIterator{contract: _AutomationRegistrar.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarOwnershipTransferred, 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 := _AutomationRegistrar.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(AutomationRegistrarOwnershipTransferred) + if err := _AutomationRegistrar.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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseOwnershipTransferred(log types.Log) (*AutomationRegistrarOwnershipTransferred, error) { + event := new(AutomationRegistrarOwnershipTransferred) + if err := _AutomationRegistrar.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarRegistrationApprovedIterator struct { + Event *AutomationRegistrarRegistrationApproved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarRegistrationApprovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarRegistrationApproved) + 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(AutomationRegistrarRegistrationApproved) + 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 *AutomationRegistrarRegistrationApprovedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarRegistrationApprovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarRegistrationApproved struct { + Hash [32]byte + DisplayName string + UpkeepId *big.Int + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterRegistrationApproved(opts *bind.FilterOpts, hash [][32]byte, upkeepId []*big.Int) (*AutomationRegistrarRegistrationApprovedIterator, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + var upkeepIdRule []interface{} + for _, upkeepIdItem := range upkeepId { + upkeepIdRule = append(upkeepIdRule, upkeepIdItem) + } + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "RegistrationApproved", hashRule, upkeepIdRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarRegistrationApprovedIterator{contract: _AutomationRegistrar.contract, event: "RegistrationApproved", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchRegistrationApproved(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationApproved, hash [][32]byte, upkeepId []*big.Int) (event.Subscription, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + var upkeepIdRule []interface{} + for _, upkeepIdItem := range upkeepId { + upkeepIdRule = append(upkeepIdRule, upkeepIdItem) + } + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "RegistrationApproved", hashRule, upkeepIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarRegistrationApproved) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationApproved", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseRegistrationApproved(log types.Log) (*AutomationRegistrarRegistrationApproved, error) { + event := new(AutomationRegistrarRegistrationApproved) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationApproved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarRegistrationRejectedIterator struct { + Event *AutomationRegistrarRegistrationRejected + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarRegistrationRejectedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarRegistrationRejected) + 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(AutomationRegistrarRegistrationRejected) + 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 *AutomationRegistrarRegistrationRejectedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarRegistrationRejectedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarRegistrationRejected struct { + Hash [32]byte + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterRegistrationRejected(opts *bind.FilterOpts, hash [][32]byte) (*AutomationRegistrarRegistrationRejectedIterator, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "RegistrationRejected", hashRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarRegistrationRejectedIterator{contract: _AutomationRegistrar.contract, event: "RegistrationRejected", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchRegistrationRejected(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationRejected, hash [][32]byte) (event.Subscription, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "RegistrationRejected", hashRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarRegistrationRejected) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationRejected", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseRegistrationRejected(log types.Log) (*AutomationRegistrarRegistrationRejected, error) { + event := new(AutomationRegistrarRegistrationRejected) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationRejected", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarRegistrationRequestedIterator struct { + Event *AutomationRegistrarRegistrationRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarRegistrationRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarRegistrationRequested) + 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(AutomationRegistrarRegistrationRequested) + 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 *AutomationRegistrarRegistrationRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarRegistrationRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarRegistrationRequested struct { + Hash [32]byte + Name string + EncryptedEmail []byte + UpkeepContract common.Address + GasLimit uint32 + AdminAddress common.Address + TriggerType uint8 + TriggerConfig []byte + OffchainConfig []byte + CheckData []byte + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterRegistrationRequested(opts *bind.FilterOpts, hash [][32]byte, upkeepContract []common.Address) (*AutomationRegistrarRegistrationRequestedIterator, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + var upkeepContractRule []interface{} + for _, upkeepContractItem := range upkeepContract { + upkeepContractRule = append(upkeepContractRule, upkeepContractItem) + } + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "RegistrationRequested", hashRule, upkeepContractRule) + if err != nil { + return nil, err + } + return &AutomationRegistrarRegistrationRequestedIterator{contract: _AutomationRegistrar.contract, event: "RegistrationRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchRegistrationRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationRequested, hash [][32]byte, upkeepContract []common.Address) (event.Subscription, error) { + + var hashRule []interface{} + for _, hashItem := range hash { + hashRule = append(hashRule, hashItem) + } + + var upkeepContractRule []interface{} + for _, upkeepContractItem := range upkeepContract { + upkeepContractRule = append(upkeepContractRule, upkeepContractItem) + } + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "RegistrationRequested", hashRule, upkeepContractRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarRegistrationRequested) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationRequested", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseRegistrationRequested(log types.Log) (*AutomationRegistrarRegistrationRequested, error) { + event := new(AutomationRegistrarRegistrationRequested) + if err := _AutomationRegistrar.contract.UnpackLog(event, "RegistrationRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistrarTriggerConfigSetIterator struct { + Event *AutomationRegistrarTriggerConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistrarTriggerConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistrarTriggerConfigSet) + 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(AutomationRegistrarTriggerConfigSet) + 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 *AutomationRegistrarTriggerConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistrarTriggerConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistrarTriggerConfigSet struct { + TriggerType uint8 + AutoApproveType uint8 + AutoApproveMaxAllowed uint32 + Raw types.Log +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) FilterTriggerConfigSet(opts *bind.FilterOpts) (*AutomationRegistrarTriggerConfigSetIterator, error) { + + logs, sub, err := _AutomationRegistrar.contract.FilterLogs(opts, "TriggerConfigSet") + if err != nil { + return nil, err + } + return &AutomationRegistrarTriggerConfigSetIterator{contract: _AutomationRegistrar.contract, event: "TriggerConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistrar *AutomationRegistrarFilterer) WatchTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarTriggerConfigSet) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistrar.contract.WatchLogs(opts, "TriggerConfigSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistrarTriggerConfigSet) + if err := _AutomationRegistrar.contract.UnpackLog(event, "TriggerConfigSet", 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 (_AutomationRegistrar *AutomationRegistrarFilterer) ParseTriggerConfigSet(log types.Log) (*AutomationRegistrarTriggerConfigSet, error) { + event := new(AutomationRegistrarTriggerConfigSet) + if err := _AutomationRegistrar.contract.UnpackLog(event, "TriggerConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type GetConfig struct { + AutomationRegistry common.Address + MinLINKJuels *big.Int +} + +func (_AutomationRegistrar *AutomationRegistrar) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _AutomationRegistrar.abi.Events["AutoApproveAllowedSenderSet"].ID: + return _AutomationRegistrar.ParseAutoApproveAllowedSenderSet(log) + case _AutomationRegistrar.abi.Events["ConfigChanged"].ID: + return _AutomationRegistrar.ParseConfigChanged(log) + case _AutomationRegistrar.abi.Events["OwnershipTransferRequested"].ID: + return _AutomationRegistrar.ParseOwnershipTransferRequested(log) + case _AutomationRegistrar.abi.Events["OwnershipTransferred"].ID: + return _AutomationRegistrar.ParseOwnershipTransferred(log) + case _AutomationRegistrar.abi.Events["RegistrationApproved"].ID: + return _AutomationRegistrar.ParseRegistrationApproved(log) + case _AutomationRegistrar.abi.Events["RegistrationRejected"].ID: + return _AutomationRegistrar.ParseRegistrationRejected(log) + case _AutomationRegistrar.abi.Events["RegistrationRequested"].ID: + return _AutomationRegistrar.ParseRegistrationRequested(log) + case _AutomationRegistrar.abi.Events["TriggerConfigSet"].ID: + return _AutomationRegistrar.ParseTriggerConfigSet(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (AutomationRegistrarAutoApproveAllowedSenderSet) Topic() common.Hash { + return common.HexToHash("0x20c6237dac83526a849285a9f79d08a483291bdd3a056a0ef9ae94ecee1ad356") +} + +func (AutomationRegistrarConfigChanged) Topic() common.Hash { + return common.HexToHash("0x39ce5d867555f0b0183e358fce5b158e7ca4fecd7c01cb7e0e19f1e23285838a") +} + +func (AutomationRegistrarOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (AutomationRegistrarOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (AutomationRegistrarRegistrationApproved) Topic() common.Hash { + return common.HexToHash("0xb9a292fb7e3edd920cd2d2829a3615a640c43fd7de0a0820aa0668feb4c37d4b") +} + +func (AutomationRegistrarRegistrationRejected) Topic() common.Hash { + return common.HexToHash("0x3663fb28ebc87645eb972c9dad8521bf665c623f287e79f1c56f1eb374b82a22") +} + +func (AutomationRegistrarRegistrationRequested) Topic() common.Hash { + return common.HexToHash("0x7684390ebb103102f7f48c71439c2408713f8d437782a6fab2756acc0e42c1b7") +} + +func (AutomationRegistrarTriggerConfigSet) Topic() common.Hash { + return common.HexToHash("0x830a6d06a4e2caac67eba04323de22bdb04f032dd8b3d6a0c52b503d9a7036a3") +} + +func (_AutomationRegistrar *AutomationRegistrar) Address() common.Address { + return _AutomationRegistrar.address +} + +type AutomationRegistrarInterface interface { + LINK(opts *bind.CallOpts) (common.Address, error) + + GetAutoApproveAllowedSender(opts *bind.CallOpts, senderAddress common.Address) (bool, error) + + GetConfig(opts *bind.CallOpts) (GetConfig, + + error) + + GetPendingRequest(opts *bind.CallOpts, hash [32]byte) (common.Address, *big.Int, error) + + GetTriggerRegistrationDetails(opts *bind.CallOpts, triggerType uint8) (AutomationRegistrar22TriggerRegistrationStorage, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + TypeAndVersion(opts *bind.CallOpts) (string, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + Approve(opts *bind.TransactOpts, name string, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, hash [32]byte) (*types.Transaction, error) + + Cancel(opts *bind.TransactOpts, hash [32]byte) (*types.Transaction, error) + + OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) + + Register(opts *bind.TransactOpts, name string, encryptedEmail []byte, upkeepContract common.Address, gasLimit uint32, adminAddress common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte, amount *big.Int, sender common.Address) (*types.Transaction, error) + + RegisterUpkeep(opts *bind.TransactOpts, requestParams AutomationRegistrar22RegistrationParams) (*types.Transaction, error) + + SetAutoApproveAllowedSender(opts *bind.TransactOpts, senderAddress common.Address, allowed bool) (*types.Transaction, error) + + SetConfig(opts *bind.TransactOpts, AutomationRegistry common.Address, minLINKJuels *big.Int) (*types.Transaction, error) + + SetTriggerConfig(opts *bind.TransactOpts, triggerType uint8, autoApproveType uint8, autoApproveMaxAllowed uint32) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + FilterAutoApproveAllowedSenderSet(opts *bind.FilterOpts, senderAddress []common.Address) (*AutomationRegistrarAutoApproveAllowedSenderSetIterator, error) + + WatchAutoApproveAllowedSenderSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarAutoApproveAllowedSenderSet, senderAddress []common.Address) (event.Subscription, error) + + ParseAutoApproveAllowedSenderSet(log types.Log) (*AutomationRegistrarAutoApproveAllowedSenderSet, error) + + FilterConfigChanged(opts *bind.FilterOpts) (*AutomationRegistrarConfigChangedIterator, error) + + WatchConfigChanged(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarConfigChanged) (event.Subscription, error) + + ParseConfigChanged(log types.Log) (*AutomationRegistrarConfigChanged, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistrarOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistrarOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistrarOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*AutomationRegistrarOwnershipTransferred, error) + + FilterRegistrationApproved(opts *bind.FilterOpts, hash [][32]byte, upkeepId []*big.Int) (*AutomationRegistrarRegistrationApprovedIterator, error) + + WatchRegistrationApproved(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationApproved, hash [][32]byte, upkeepId []*big.Int) (event.Subscription, error) + + ParseRegistrationApproved(log types.Log) (*AutomationRegistrarRegistrationApproved, error) + + FilterRegistrationRejected(opts *bind.FilterOpts, hash [][32]byte) (*AutomationRegistrarRegistrationRejectedIterator, error) + + WatchRegistrationRejected(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationRejected, hash [][32]byte) (event.Subscription, error) + + ParseRegistrationRejected(log types.Log) (*AutomationRegistrarRegistrationRejected, error) + + FilterRegistrationRequested(opts *bind.FilterOpts, hash [][32]byte, upkeepContract []common.Address) (*AutomationRegistrarRegistrationRequestedIterator, error) + + WatchRegistrationRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarRegistrationRequested, hash [][32]byte, upkeepContract []common.Address) (event.Subscription, error) + + ParseRegistrationRequested(log types.Log) (*AutomationRegistrarRegistrationRequested, error) + + FilterTriggerConfigSet(opts *bind.FilterOpts) (*AutomationRegistrarTriggerConfigSetIterator, error) + + WatchTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistrarTriggerConfigSet) (event.Subscription, error) + + ParseTriggerConfigSet(log types.Log) (*AutomationRegistrarTriggerConfigSet, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/automation_utils_2_2/automation_utils_2_2.go b/core/gethwrappers/generated/automation_utils_2_2/automation_utils_2_2.go new file mode 100644 index 00000000000..1239d6baf7a --- /dev/null +++ b/core/gethwrappers/generated/automation_utils_2_2/automation_utils_2_2.go @@ -0,0 +1,323 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package automation_utils_2_2 + +import ( + "errors" + "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" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +type AutomationRegistryBase22ConditionalTrigger struct { + BlockNum uint32 + BlockHash [32]byte +} + +type AutomationRegistryBase22LogTrigger struct { + LogBlockHash [32]byte + TxHash [32]byte + LogIndex uint32 + BlockNum uint32 + BlockHash [32]byte +} + +type AutomationRegistryBase22OnchainConfig struct { + PaymentPremiumPPB uint32 + FlatFeeMicroLink uint32 + CheckGasLimit uint32 + StalenessSeconds *big.Int + GasCeilingMultiplier uint16 + MinUpkeepSpend *big.Int + MaxPerformGas uint32 + MaxCheckDataSize uint32 + MaxPerformDataSize uint32 + MaxRevertDataSize uint32 + FallbackGasPrice *big.Int + FallbackLinkPrice *big.Int + Transcoder common.Address + Registrars []common.Address + UpkeepPrivilegeManager common.Address + ReorgProtectionEnabled bool +} + +type AutomationRegistryBase22Report struct { + FastGasWei *big.Int + LinkNative *big.Int + UpkeepIds []*big.Int + GasLimits []*big.Int + Triggers [][]byte + PerformDatas [][]byte +} + +type Log struct { + Index *big.Int + Timestamp *big.Int + TxHash [32]byte + BlockNumber *big.Int + BlockHash [32]byte + Source common.Address + Topics [][32]byte + Data []byte +} + +type LogTriggerConfig struct { + ContractAddress common.Address + FilterSelector uint8 + Topic0 [32]byte + Topic1 [32]byte + Topic2 [32]byte + Topic3 [32]byte +} + +var AutomationUtilsMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"blockNum\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structAutomationRegistryBase2_2.ConditionalTrigger\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_conditionalTrigger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_log\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"logBlockHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"logIndex\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNum\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structAutomationRegistryBase2_2.LogTrigger\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_logTrigger\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"filterSelector\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"topic0\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic1\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic2\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"topic3\",\"type\":\"bytes32\"}],\"internalType\":\"structLogTriggerConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_logTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"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\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"internalType\":\"structAutomationRegistryBase2_2.OnchainConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_onChainConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"fastGasWei\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"linkNative\",\"type\":\"uint256\"},{\"internalType\":\"uint256[]\",\"name\":\"upkeepIds\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"gasLimits\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes[]\",\"name\":\"triggers\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes[]\",\"name\":\"performDatas\",\"type\":\"bytes[]\"}],\"internalType\":\"structAutomationRegistryBase2_2.Report\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_report\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b506108ee806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063e32442c911610050578063e32442c9146100a6578063e65d6546146100b4578063e9720a49146100c257600080fd5b806321f373d7146100775780634b6df2941461008a578063776f306114610098575b600080fd5b6100886100853660046101e8565b50565b005b61008861008536600461028c565b6100886100853660046102e3565b610088610085366004610448565b61008861008536600461071f565b61008861008536600461080c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff81118282101715610123576101236100d0565b60405290565b60405160c0810167ffffffffffffffff81118282101715610123576101236100d0565b604051610100810167ffffffffffffffff81118282101715610123576101236100d0565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156101b7576101b76100d0565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146101e357600080fd5b919050565b600060c082840312156101fa57600080fd5b60405160c0810181811067ffffffffffffffff8211171561021d5761021d6100d0565b604052610229836101bf565b8152602083013560ff8116811461023f57600080fd5b8060208301525060408301356040820152606083013560608201526080830135608082015260a083013560a08201528091505092915050565b803563ffffffff811681146101e357600080fd5b60006040828403121561029e57600080fd5b6040516040810181811067ffffffffffffffff821117156102c1576102c16100d0565b6040526102cd83610278565b8152602083013560208201528091505092915050565b600060a082840312156102f557600080fd5b60405160a0810181811067ffffffffffffffff82111715610318576103186100d0565b8060405250823581526020830135602082015261033760408401610278565b604082015261034860608401610278565b6060820152608083013560808201528091505092915050565b803562ffffff811681146101e357600080fd5b803561ffff811681146101e357600080fd5b80356bffffffffffffffffffffffff811681146101e357600080fd5b600067ffffffffffffffff8211156103bc576103bc6100d0565b5060051b60200190565b600082601f8301126103d757600080fd5b813560206103ec6103e7836103a2565b610170565b82815260059290921b8401810191818101908684111561040b57600080fd5b8286015b8481101561042d57610420816101bf565b835291830191830161040f565b509695505050505050565b803580151581146101e357600080fd5b60006020828403121561045a57600080fd5b813567ffffffffffffffff8082111561047257600080fd5b90830190610200828603121561048757600080fd5b61048f6100ff565b61049883610278565b81526104a660208401610278565b60208201526104b760408401610278565b60408201526104c860608401610361565b60608201526104d960808401610374565b60808201526104ea60a08401610386565b60a08201526104fb60c08401610278565b60c082015261050c60e08401610278565b60e082015261010061051f818501610278565b90820152610120610531848201610278565b90820152610140838101359082015261016080840135908201526101806105598185016101bf565b908201526101a0838101358381111561057157600080fd5b61057d888287016103c6565b8284015250506101c091506105938284016101bf565b828201526101e091506105a7828401610438565b91810191909152949350505050565b600082601f8301126105c757600080fd5b813560206105d76103e7836103a2565b82815260059290921b840181019181810190868411156105f657600080fd5b8286015b8481101561042d57803583529183019183016105fa565b600082601f83011261062257600080fd5b813567ffffffffffffffff81111561063c5761063c6100d0565b61066d60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610170565b81815284602083860101111561068257600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f8301126106b057600080fd5b813560206106c06103e7836103a2565b82815260059290921b840181019181810190868411156106df57600080fd5b8286015b8481101561042d57803567ffffffffffffffff8111156107035760008081fd5b6107118986838b0101610611565b8452509183019183016106e3565b60006020828403121561073157600080fd5b813567ffffffffffffffff8082111561074957600080fd5b9083019060c0828603121561075d57600080fd5b610765610129565b823581526020830135602082015260408301358281111561078557600080fd5b610791878286016105b6565b6040830152506060830135828111156107a957600080fd5b6107b5878286016105b6565b6060830152506080830135828111156107cd57600080fd5b6107d98782860161069f565b60808301525060a0830135828111156107f157600080fd5b6107fd8782860161069f565b60a08301525095945050505050565b60006020828403121561081e57600080fd5b813567ffffffffffffffff8082111561083657600080fd5b90830190610100828603121561084b57600080fd5b61085361014c565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015261088b60a084016101bf565b60a082015260c0830135828111156108a257600080fd5b6108ae878286016105b6565b60c08301525060e0830135828111156108c657600080fd5b6108d287828601610611565b60e0830152509594505050505056fea164736f6c6343000810000a", +} + +var AutomationUtilsABI = AutomationUtilsMetaData.ABI + +var AutomationUtilsBin = AutomationUtilsMetaData.Bin + +func DeployAutomationUtils(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *AutomationUtils, error) { + parsed, err := AutomationUtilsMetaData.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(AutomationUtilsBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationUtils{address: address, abi: *parsed, AutomationUtilsCaller: AutomationUtilsCaller{contract: contract}, AutomationUtilsTransactor: AutomationUtilsTransactor{contract: contract}, AutomationUtilsFilterer: AutomationUtilsFilterer{contract: contract}}, nil +} + +type AutomationUtils struct { + address common.Address + abi abi.ABI + AutomationUtilsCaller + AutomationUtilsTransactor + AutomationUtilsFilterer +} + +type AutomationUtilsCaller struct { + contract *bind.BoundContract +} + +type AutomationUtilsTransactor struct { + contract *bind.BoundContract +} + +type AutomationUtilsFilterer struct { + contract *bind.BoundContract +} + +type AutomationUtilsSession struct { + Contract *AutomationUtils + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationUtilsCallerSession struct { + Contract *AutomationUtilsCaller + CallOpts bind.CallOpts +} + +type AutomationUtilsTransactorSession struct { + Contract *AutomationUtilsTransactor + TransactOpts bind.TransactOpts +} + +type AutomationUtilsRaw struct { + Contract *AutomationUtils +} + +type AutomationUtilsCallerRaw struct { + Contract *AutomationUtilsCaller +} + +type AutomationUtilsTransactorRaw struct { + Contract *AutomationUtilsTransactor +} + +func NewAutomationUtils(address common.Address, backend bind.ContractBackend) (*AutomationUtils, error) { + abi, err := abi.JSON(strings.NewReader(AutomationUtilsABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationUtils(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationUtils{address: address, abi: abi, AutomationUtilsCaller: AutomationUtilsCaller{contract: contract}, AutomationUtilsTransactor: AutomationUtilsTransactor{contract: contract}, AutomationUtilsFilterer: AutomationUtilsFilterer{contract: contract}}, nil +} + +func NewAutomationUtilsCaller(address common.Address, caller bind.ContractCaller) (*AutomationUtilsCaller, error) { + contract, err := bindAutomationUtils(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationUtilsCaller{contract: contract}, nil +} + +func NewAutomationUtilsTransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationUtilsTransactor, error) { + contract, err := bindAutomationUtils(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationUtilsTransactor{contract: contract}, nil +} + +func NewAutomationUtilsFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationUtilsFilterer, error) { + contract, err := bindAutomationUtils(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationUtilsFilterer{contract: contract}, nil +} + +func bindAutomationUtils(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationUtilsMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationUtils *AutomationUtilsRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationUtils.Contract.AutomationUtilsCaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationUtils *AutomationUtilsRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationUtils.Contract.AutomationUtilsTransactor.contract.Transfer(opts) +} + +func (_AutomationUtils *AutomationUtilsRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationUtils.Contract.AutomationUtilsTransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationUtils *AutomationUtilsCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationUtils.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationUtils *AutomationUtilsTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationUtils.Contract.contract.Transfer(opts) +} + +func (_AutomationUtils *AutomationUtilsTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationUtils.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationUtils *AutomationUtilsTransactor) ConditionalTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase22ConditionalTrigger) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_conditionalTrigger", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) ConditionalTrigger(arg0 AutomationRegistryBase22ConditionalTrigger) (*types.Transaction, error) { + return _AutomationUtils.Contract.ConditionalTrigger(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) ConditionalTrigger(arg0 AutomationRegistryBase22ConditionalTrigger) (*types.Transaction, error) { + return _AutomationUtils.Contract.ConditionalTrigger(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactor) Log(opts *bind.TransactOpts, arg0 Log) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_log", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) Log(arg0 Log) (*types.Transaction, error) { + return _AutomationUtils.Contract.Log(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) Log(arg0 Log) (*types.Transaction, error) { + return _AutomationUtils.Contract.Log(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactor) LogTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase22LogTrigger) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_logTrigger", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) LogTrigger(arg0 AutomationRegistryBase22LogTrigger) (*types.Transaction, error) { + return _AutomationUtils.Contract.LogTrigger(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) LogTrigger(arg0 AutomationRegistryBase22LogTrigger) (*types.Transaction, error) { + return _AutomationUtils.Contract.LogTrigger(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactor) LogTriggerConfig(opts *bind.TransactOpts, arg0 LogTriggerConfig) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_logTriggerConfig", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) LogTriggerConfig(arg0 LogTriggerConfig) (*types.Transaction, error) { + return _AutomationUtils.Contract.LogTriggerConfig(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) LogTriggerConfig(arg0 LogTriggerConfig) (*types.Transaction, error) { + return _AutomationUtils.Contract.LogTriggerConfig(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactor) OnChainConfig(opts *bind.TransactOpts, arg0 AutomationRegistryBase22OnchainConfig) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_onChainConfig", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) OnChainConfig(arg0 AutomationRegistryBase22OnchainConfig) (*types.Transaction, error) { + return _AutomationUtils.Contract.OnChainConfig(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) OnChainConfig(arg0 AutomationRegistryBase22OnchainConfig) (*types.Transaction, error) { + return _AutomationUtils.Contract.OnChainConfig(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactor) Report(opts *bind.TransactOpts, arg0 AutomationRegistryBase22Report) (*types.Transaction, error) { + return _AutomationUtils.contract.Transact(opts, "_report", arg0) +} + +func (_AutomationUtils *AutomationUtilsSession) Report(arg0 AutomationRegistryBase22Report) (*types.Transaction, error) { + return _AutomationUtils.Contract.Report(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtilsTransactorSession) Report(arg0 AutomationRegistryBase22Report) (*types.Transaction, error) { + return _AutomationUtils.Contract.Report(&_AutomationUtils.TransactOpts, arg0) +} + +func (_AutomationUtils *AutomationUtils) Address() common.Address { + return _AutomationUtils.address +} + +type AutomationUtilsInterface interface { + ConditionalTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase22ConditionalTrigger) (*types.Transaction, error) + + Log(opts *bind.TransactOpts, arg0 Log) (*types.Transaction, error) + + LogTrigger(opts *bind.TransactOpts, arg0 AutomationRegistryBase22LogTrigger) (*types.Transaction, error) + + LogTriggerConfig(opts *bind.TransactOpts, arg0 LogTriggerConfig) (*types.Transaction, error) + + OnChainConfig(opts *bind.TransactOpts, arg0 AutomationRegistryBase22OnchainConfig) (*types.Transaction, error) + + Report(opts *bind.TransactOpts, arg0 AutomationRegistryBase22Report) (*types.Transaction, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/chain_reader_example/chain_reader_example.go b/core/gethwrappers/generated/chain_reader_example/chain_reader_example.go new file mode 100644 index 00000000000..f6dce0bb6c3 --- /dev/null +++ b/core/gethwrappers/generated/chain_reader_example/chain_reader_example.go @@ -0,0 +1,830 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package chain_reader_example + +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 InnerTestStruct struct { + IntVal int64 + S string +} + +type MidLevelTestStruct struct { + FixedBytes [2]byte + Inner InnerTestStruct +} + +type TestStruct struct { + Field int32 + DifferentField string + OracleId uint8 + OracleIds [32]uint8 + Account common.Address + Accounts []common.Address + BigField *big.Int + NestedStruct MidLevelTestStruct +} + +var LatestValueHolderMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"indexed\":false,\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"Triggered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"fieldHash\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"TriggeredEventWithDynamicTopic\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"TriggeredWithFourTopics\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"addTestStruct\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDifferentPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"i\",\"type\":\"uint256\"}],\"name\":\"getElementAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"NestedStruct\",\"type\":\"tuple\"}],\"internalType\":\"structTestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSliceValue\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"returnSeen\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"NestedStruct\",\"type\":\"tuple\"}],\"internalType\":\"structTestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"structInnerTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"structMidLevelTestStruct\",\"name\":\"nestedStruct\",\"type\":\"tuple\"}],\"name\":\"triggerEvent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"triggerEventWithDynamicTopic\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"triggerWithFourTopics\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50600180548082018255600082905260048082047fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6908101805460086003958616810261010090810a8088026001600160401b0391820219909416939093179093558654808801909755848704909301805496909516909202900a91820291021990921691909117905561176c806100a96000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80637f002d6711610076578063dbfd73321161005b578063dbfd73321461013e578063ef4e1ced14610151578063f6f871c81461015857600080fd5b80637f002d671461010e578063ab5e0b381461012157600080fd5b80632c45576f146100a85780633272b66c146100d157806349eac2ac146100e6578063679004a4146100f9575b600080fd5b6100bb6100b6366004610baa565b61016b565b6040516100c89190610d09565b60405180910390f35b6100e46100df366004610e48565b610446565b005b6100e46100f4366004610f5d565b61049b565b61010161079e565b6040516100c8919061104f565b6100e461011c366004610f5d565b61082a565b6107c65b60405167ffffffffffffffff90911681526020016100c8565b6100e461014c36600461109d565b610881565b6003610125565b6100bb610166366004610f5d565b6108be565b6101736109c7565b60006101806001846110e0565b815481106101905761019061111a565b6000918252602091829020604080516101008101909152600a90920201805460030b825260018101805492939192918401916101cb90611149565b80601f01602080910402602001604051908101604052809291908181526020018280546101f790611149565b80156102445780601f1061021957610100808354040283529160200191610244565b820191906000526020600020905b81548152906001019060200180831161022757829003601f168201915b5050509183525050600282015460ff166020808301919091526040805161040081018083529190930192916003850191826000855b825461010083900a900460ff1681526020600192830181810494850194909303909202910180841161027957505050928452505050600482015473ffffffffffffffffffffffffffffffffffffffff16602080830191909152600583018054604080518285028101850182528281529401939283018282801561033257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610307575b5050509183525050600682015460170b6020808301919091526040805180820182526007808601805460f01b7fffff0000000000000000000000000000000000000000000000000000000000001683528351808501855260088801805490930b815260098801805495909701969395919486830194919392840191906103b790611149565b80601f01602080910402602001604051908101604052809291908181526020018280546103e390611149565b80156104305780601f1061040557610100808354040283529160200191610430565b820191906000526020600020905b81548152906001019060200180831161041357829003601f168201915b5050509190925250505090525090525092915050565b8181604051610456929190611196565b60405180910390207f3d969732b1bbbb9f1d7eb9f3f14e4cb50a74d950b3ef916a397b85dfbab93c67838360405161048f9291906111ef565b60405180910390a25050565b60006040518061010001604052808c60030b81526020018b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060ff8a166020808301919091526040805161040081810183529190930192918b9183908390808284376000920191909152505050815273ffffffffffffffffffffffffffffffffffffffff8816602080830191909152604080518883028181018401835289825291909301929189918991829190850190849080828437600092019190915250505090825250601785900b602082015260400161058d846112ec565b905281546001808201845560009384526020938490208351600a9093020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff9093169290921782559282015191929091908201906105f39082611446565b5060408201516002820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff90921691909117905560608201516106419060038301906020610a16565b5060808201516004820180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905560a082015180516106a8916005840191602090910190610aa9565b5060c08201516006820180547fffffffffffffffff0000000000000000000000000000000000000000000000001677ffffffffffffffffffffffffffffffffffffffffffffffff90921691909117905560e082015180516007830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660f09290921c91909117815560208083015180516008860180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff90921691909117815591810151909190600986019061078b9082611446565b5050505050505050505050505050505050565b6060600180548060200260200160405190810160405280929190818152602001828054801561082057602002820191906000526020600020906000905b82829054906101000a900467ffffffffffffffff1667ffffffffffffffff16815260200190600801906020826007010492830192600103820291508084116107db5790505b5050505050905090565b8960030b7f7188419dcd8b51877b71766f075f3626586c0ff190e7d056aa65ce9acb649a3d8a8a8a8a8a8a8a8a8a60405161086d999897969594939291906116a5565b60405180910390a250505050505050505050565b8060030b8260030b8460030b7f91c80dc390f3d041b3a04b0099b19634499541ea26972250986ee4b24a12fac560405160405180910390a4505050565b6108c66109c7565b6040518061010001604052808c60030b81526020018b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060ff8a166020808301919091526040805161040081810183529190930192918b9183908390808284376000920191909152505050815273ffffffffffffffffffffffffffffffffffffffff8816602080830191909152604080518883028181018401835289825291909301929189918991829190850190849080828437600092019190915250505090825250601785900b60208201526040016109b6846112ec565b90529b9a5050505050505050505050565b60408051610100810182526000808252606060208301819052928201529081016109ef610b23565b8152600060208201819052606060408301819052820152608001610a11610b42565b905290565b600183019183908215610a995791602002820160005b83821115610a6a57835183826101000a81548160ff021916908360ff1602179055509260200192600101602081600001049283019260010302610a2c565b8015610a975782816101000a81549060ff0219169055600101602081600001049283019260010302610a6a565b505b50610aa5929150610b95565b5090565b828054828255906000526020600020908101928215610a99579160200282015b82811115610a9957825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190610ac9565b6040518061040001604052806020906020820280368337509192915050565b604051806040016040528060007dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168152602001610a116040518060400160405280600060070b8152602001606081525090565b5b80821115610aa55760008155600101610b96565b600060208284031215610bbc57600080fd5b5035919050565b6000815180845260005b81811015610be957602081850181015186830182015201610bcd565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b8060005b6020808210610c3a5750610c51565b825160ff1685529384019390910190600101610c2b565b50505050565b600081518084526020808501945080840160005b83811015610c9d57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101610c6b565b509495945050505050565b7fffff00000000000000000000000000000000000000000000000000000000000081511682526000602082015160406020850152805160070b60408501526020810151905060406060850152610d016080850182610bc3565b949350505050565b60208152610d1d60208201835160030b9052565b600060208301516104e0806040850152610d3b610500850183610bc3565b91506040850151610d51606086018260ff169052565b506060850151610d646080860182610c27565b50608085015173ffffffffffffffffffffffffffffffffffffffff1661048085015260a08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe085840381016104a0870152610dc18483610c57565b935060c08701519150610dda6104c087018360170b9052565b60e0870151915080868503018387015250610df58382610ca8565b9695505050505050565b60008083601f840112610e1157600080fd5b50813567ffffffffffffffff811115610e2957600080fd5b602083019150836020828501011115610e4157600080fd5b9250929050565b60008060208385031215610e5b57600080fd5b823567ffffffffffffffff811115610e7257600080fd5b610e7e85828601610dff565b90969095509350505050565b8035600381900b8114610e9c57600080fd5b919050565b803560ff81168114610e9c57600080fd5b806104008101831015610ec457600080fd5b92915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e9c57600080fd5b60008083601f840112610f0057600080fd5b50813567ffffffffffffffff811115610f1857600080fd5b6020830191508360208260051b8501011115610e4157600080fd5b8035601781900b8114610e9c57600080fd5b600060408284031215610f5757600080fd5b50919050565b6000806000806000806000806000806104e08b8d031215610f7d57600080fd5b610f868b610e8a565b995060208b013567ffffffffffffffff80821115610fa357600080fd5b610faf8e838f01610dff565b909b509950899150610fc360408e01610ea1565b9850610fd28e60608f01610eb2565b9750610fe16104608e01610eca565b96506104808d0135915080821115610ff857600080fd5b6110048e838f01610eee565b90965094508491506110196104a08e01610f33565b93506104c08d013591508082111561103057600080fd5b5061103d8d828e01610f45565b9150509295989b9194979a5092959850565b6020808252825182820181905260009190848201906040850190845b8181101561109157835167ffffffffffffffff168352928401929184019160010161106b565b50909695505050505050565b6000806000606084860312156110b257600080fd5b6110bb84610e8a565b92506110c960208501610e8a565b91506110d760408501610e8a565b90509250925092565b81810381811115610ec4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c9082168061115d57607f821691505b602082108103610f57577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b602081526000610d016020830184866111a6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff8111828210171561125557611255611203565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156112a2576112a2611203565b604052919050565b80357fffff00000000000000000000000000000000000000000000000000000000000081168114610e9c57600080fd5b8035600781900b8114610e9c57600080fd5b6000604082360312156112fe57600080fd5b611306611232565b61130f836112aa565b815260208084013567ffffffffffffffff8082111561132d57600080fd5b81860191506040823603121561134257600080fd5b61134a611232565b611353836112da565b8152838301358281111561136657600080fd5b929092019136601f84011261137a57600080fd5b82358281111561138c5761138c611203565b6113bc857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160161125b565b925080835236858286010111156113d257600080fd5b8085850186850137600090830185015280840191909152918301919091525092915050565b601f82111561144157600081815260208120601f850160051c8101602086101561141e5750805b601f850160051c820191505b8181101561143d5782815560010161142a565b5050505b505050565b815167ffffffffffffffff81111561146057611460611203565b6114748161146e8454611149565b846113f7565b602080601f8311600181146114c757600084156114915750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855561143d565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015611514578886015182559484019460019091019084016114f5565b508582101561155057878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b8183526000602080850194508260005b85811015610c9d5773ffffffffffffffffffffffffffffffffffffffff61159683610eca565b1687529582019590820190600101611570565b7fffff0000000000000000000000000000000000000000000000000000000000006115d3826112aa565b168252600060208201357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261160d57600080fd5b60406020850152820161161f816112da565b60070b604085015260208101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe182360301811261165c57600080fd5b0160208101903567ffffffffffffffff81111561167857600080fd5b80360382131561168757600080fd5b6040606086015261169c6080860182846111a6565b95945050505050565b60006104c08083526116ba8184018c8e6111a6565b9050602060ff808c1682860152604085018b60005b848110156116f457836116e183610ea1565b16835291840191908401906001016116cf565b505050505073ffffffffffffffffffffffffffffffffffffffff881661044084015282810361046084015261172a818789611560565b905061173c61048084018660170b9052565b8281036104a084015261174f81856115a9565b9c9b50505050505050505050505056fea164736f6c6343000813000a", +} + +var LatestValueHolderABI = LatestValueHolderMetaData.ABI + +var LatestValueHolderBin = LatestValueHolderMetaData.Bin + +func DeployLatestValueHolder(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *LatestValueHolder, error) { + parsed, err := LatestValueHolderMetaData.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(LatestValueHolderBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &LatestValueHolder{address: address, abi: *parsed, LatestValueHolderCaller: LatestValueHolderCaller{contract: contract}, LatestValueHolderTransactor: LatestValueHolderTransactor{contract: contract}, LatestValueHolderFilterer: LatestValueHolderFilterer{contract: contract}}, nil +} + +type LatestValueHolder struct { + address common.Address + abi abi.ABI + LatestValueHolderCaller + LatestValueHolderTransactor + LatestValueHolderFilterer +} + +type LatestValueHolderCaller struct { + contract *bind.BoundContract +} + +type LatestValueHolderTransactor struct { + contract *bind.BoundContract +} + +type LatestValueHolderFilterer struct { + contract *bind.BoundContract +} + +type LatestValueHolderSession struct { + Contract *LatestValueHolder + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type LatestValueHolderCallerSession struct { + Contract *LatestValueHolderCaller + CallOpts bind.CallOpts +} + +type LatestValueHolderTransactorSession struct { + Contract *LatestValueHolderTransactor + TransactOpts bind.TransactOpts +} + +type LatestValueHolderRaw struct { + Contract *LatestValueHolder +} + +type LatestValueHolderCallerRaw struct { + Contract *LatestValueHolderCaller +} + +type LatestValueHolderTransactorRaw struct { + Contract *LatestValueHolderTransactor +} + +func NewLatestValueHolder(address common.Address, backend bind.ContractBackend) (*LatestValueHolder, error) { + abi, err := abi.JSON(strings.NewReader(LatestValueHolderABI)) + if err != nil { + return nil, err + } + contract, err := bindLatestValueHolder(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &LatestValueHolder{address: address, abi: abi, LatestValueHolderCaller: LatestValueHolderCaller{contract: contract}, LatestValueHolderTransactor: LatestValueHolderTransactor{contract: contract}, LatestValueHolderFilterer: LatestValueHolderFilterer{contract: contract}}, nil +} + +func NewLatestValueHolderCaller(address common.Address, caller bind.ContractCaller) (*LatestValueHolderCaller, error) { + contract, err := bindLatestValueHolder(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &LatestValueHolderCaller{contract: contract}, nil +} + +func NewLatestValueHolderTransactor(address common.Address, transactor bind.ContractTransactor) (*LatestValueHolderTransactor, error) { + contract, err := bindLatestValueHolder(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &LatestValueHolderTransactor{contract: contract}, nil +} + +func NewLatestValueHolderFilterer(address common.Address, filterer bind.ContractFilterer) (*LatestValueHolderFilterer, error) { + contract, err := bindLatestValueHolder(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &LatestValueHolderFilterer{contract: contract}, nil +} + +func bindLatestValueHolder(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := LatestValueHolderMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_LatestValueHolder *LatestValueHolderRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _LatestValueHolder.Contract.LatestValueHolderCaller.contract.Call(opts, result, method, params...) +} + +func (_LatestValueHolder *LatestValueHolderRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _LatestValueHolder.Contract.LatestValueHolderTransactor.contract.Transfer(opts) +} + +func (_LatestValueHolder *LatestValueHolderRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _LatestValueHolder.Contract.LatestValueHolderTransactor.contract.Transact(opts, method, params...) +} + +func (_LatestValueHolder *LatestValueHolderCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _LatestValueHolder.Contract.contract.Call(opts, result, method, params...) +} + +func (_LatestValueHolder *LatestValueHolderTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _LatestValueHolder.Contract.contract.Transfer(opts) +} + +func (_LatestValueHolder *LatestValueHolderTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _LatestValueHolder.Contract.contract.Transact(opts, method, params...) +} + +func (_LatestValueHolder *LatestValueHolderCaller) GetDifferentPrimitiveValue(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _LatestValueHolder.contract.Call(opts, &out, "getDifferentPrimitiveValue") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +func (_LatestValueHolder *LatestValueHolderSession) GetDifferentPrimitiveValue() (uint64, error) { + return _LatestValueHolder.Contract.GetDifferentPrimitiveValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCallerSession) GetDifferentPrimitiveValue() (uint64, error) { + return _LatestValueHolder.Contract.GetDifferentPrimitiveValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCaller) GetElementAtIndex(opts *bind.CallOpts, i *big.Int) (TestStruct, error) { + var out []interface{} + err := _LatestValueHolder.contract.Call(opts, &out, "getElementAtIndex", i) + + if err != nil { + return *new(TestStruct), err + } + + out0 := *abi.ConvertType(out[0], new(TestStruct)).(*TestStruct) + + return out0, err + +} + +func (_LatestValueHolder *LatestValueHolderSession) GetElementAtIndex(i *big.Int) (TestStruct, error) { + return _LatestValueHolder.Contract.GetElementAtIndex(&_LatestValueHolder.CallOpts, i) +} + +func (_LatestValueHolder *LatestValueHolderCallerSession) GetElementAtIndex(i *big.Int) (TestStruct, error) { + return _LatestValueHolder.Contract.GetElementAtIndex(&_LatestValueHolder.CallOpts, i) +} + +func (_LatestValueHolder *LatestValueHolderCaller) GetPrimitiveValue(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _LatestValueHolder.contract.Call(opts, &out, "getPrimitiveValue") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +func (_LatestValueHolder *LatestValueHolderSession) GetPrimitiveValue() (uint64, error) { + return _LatestValueHolder.Contract.GetPrimitiveValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCallerSession) GetPrimitiveValue() (uint64, error) { + return _LatestValueHolder.Contract.GetPrimitiveValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCaller) GetSliceValue(opts *bind.CallOpts) ([]uint64, error) { + var out []interface{} + err := _LatestValueHolder.contract.Call(opts, &out, "getSliceValue") + + if err != nil { + return *new([]uint64), err + } + + out0 := *abi.ConvertType(out[0], new([]uint64)).(*[]uint64) + + return out0, err + +} + +func (_LatestValueHolder *LatestValueHolderSession) GetSliceValue() ([]uint64, error) { + return _LatestValueHolder.Contract.GetSliceValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCallerSession) GetSliceValue() ([]uint64, error) { + return _LatestValueHolder.Contract.GetSliceValue(&_LatestValueHolder.CallOpts) +} + +func (_LatestValueHolder *LatestValueHolderCaller) ReturnSeen(opts *bind.CallOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (TestStruct, error) { + var out []interface{} + err := _LatestValueHolder.contract.Call(opts, &out, "returnSeen", field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) + + if err != nil { + return *new(TestStruct), err + } + + out0 := *abi.ConvertType(out[0], new(TestStruct)).(*TestStruct) + + return out0, err + +} + +func (_LatestValueHolder *LatestValueHolderSession) ReturnSeen(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (TestStruct, error) { + return _LatestValueHolder.Contract.ReturnSeen(&_LatestValueHolder.CallOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderCallerSession) ReturnSeen(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (TestStruct, error) { + return _LatestValueHolder.Contract.ReturnSeen(&_LatestValueHolder.CallOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderTransactor) AddTestStruct(opts *bind.TransactOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.contract.Transact(opts, "addTestStruct", field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderSession) AddTestStruct(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.Contract.AddTestStruct(&_LatestValueHolder.TransactOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderTransactorSession) AddTestStruct(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.Contract.AddTestStruct(&_LatestValueHolder.TransactOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderTransactor) TriggerEvent(opts *bind.TransactOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.contract.Transact(opts, "triggerEvent", field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderSession) TriggerEvent(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerEvent(&_LatestValueHolder.TransactOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderTransactorSession) TriggerEvent(field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerEvent(&_LatestValueHolder.TransactOpts, field, differentField, oracleId, oracleIds, account, accounts, bigField, nestedStruct) +} + +func (_LatestValueHolder *LatestValueHolderTransactor) TriggerEventWithDynamicTopic(opts *bind.TransactOpts, field string) (*types.Transaction, error) { + return _LatestValueHolder.contract.Transact(opts, "triggerEventWithDynamicTopic", field) +} + +func (_LatestValueHolder *LatestValueHolderSession) TriggerEventWithDynamicTopic(field string) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerEventWithDynamicTopic(&_LatestValueHolder.TransactOpts, field) +} + +func (_LatestValueHolder *LatestValueHolderTransactorSession) TriggerEventWithDynamicTopic(field string) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerEventWithDynamicTopic(&_LatestValueHolder.TransactOpts, field) +} + +func (_LatestValueHolder *LatestValueHolderTransactor) TriggerWithFourTopics(opts *bind.TransactOpts, field1 int32, field2 int32, field3 int32) (*types.Transaction, error) { + return _LatestValueHolder.contract.Transact(opts, "triggerWithFourTopics", field1, field2, field3) +} + +func (_LatestValueHolder *LatestValueHolderSession) TriggerWithFourTopics(field1 int32, field2 int32, field3 int32) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerWithFourTopics(&_LatestValueHolder.TransactOpts, field1, field2, field3) +} + +func (_LatestValueHolder *LatestValueHolderTransactorSession) TriggerWithFourTopics(field1 int32, field2 int32, field3 int32) (*types.Transaction, error) { + return _LatestValueHolder.Contract.TriggerWithFourTopics(&_LatestValueHolder.TransactOpts, field1, field2, field3) +} + +type LatestValueHolderTriggeredIterator struct { + Event *LatestValueHolderTriggered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *LatestValueHolderTriggeredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(LatestValueHolderTriggered) + 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(LatestValueHolderTriggered) + 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 *LatestValueHolderTriggeredIterator) Error() error { + return it.fail +} + +func (it *LatestValueHolderTriggeredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type LatestValueHolderTriggered struct { + Field int32 + DifferentField string + OracleId uint8 + OracleIds [32]uint8 + Account common.Address + Accounts []common.Address + BigField *big.Int + NestedStruct MidLevelTestStruct + Raw types.Log +} + +func (_LatestValueHolder *LatestValueHolderFilterer) FilterTriggered(opts *bind.FilterOpts, field []int32) (*LatestValueHolderTriggeredIterator, error) { + + var fieldRule []interface{} + for _, fieldItem := range field { + fieldRule = append(fieldRule, fieldItem) + } + + logs, sub, err := _LatestValueHolder.contract.FilterLogs(opts, "Triggered", fieldRule) + if err != nil { + return nil, err + } + return &LatestValueHolderTriggeredIterator{contract: _LatestValueHolder.contract, event: "Triggered", logs: logs, sub: sub}, nil +} + +func (_LatestValueHolder *LatestValueHolderFilterer) WatchTriggered(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggered, field []int32) (event.Subscription, error) { + + var fieldRule []interface{} + for _, fieldItem := range field { + fieldRule = append(fieldRule, fieldItem) + } + + logs, sub, err := _LatestValueHolder.contract.WatchLogs(opts, "Triggered", fieldRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(LatestValueHolderTriggered) + if err := _LatestValueHolder.contract.UnpackLog(event, "Triggered", 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 (_LatestValueHolder *LatestValueHolderFilterer) ParseTriggered(log types.Log) (*LatestValueHolderTriggered, error) { + event := new(LatestValueHolderTriggered) + if err := _LatestValueHolder.contract.UnpackLog(event, "Triggered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type LatestValueHolderTriggeredEventWithDynamicTopicIterator struct { + Event *LatestValueHolderTriggeredEventWithDynamicTopic + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *LatestValueHolderTriggeredEventWithDynamicTopicIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(LatestValueHolderTriggeredEventWithDynamicTopic) + 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(LatestValueHolderTriggeredEventWithDynamicTopic) + 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 *LatestValueHolderTriggeredEventWithDynamicTopicIterator) Error() error { + return it.fail +} + +func (it *LatestValueHolderTriggeredEventWithDynamicTopicIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type LatestValueHolderTriggeredEventWithDynamicTopic struct { + FieldHash common.Hash + Field string + Raw types.Log +} + +func (_LatestValueHolder *LatestValueHolderFilterer) FilterTriggeredEventWithDynamicTopic(opts *bind.FilterOpts, fieldHash []string) (*LatestValueHolderTriggeredEventWithDynamicTopicIterator, error) { + + var fieldHashRule []interface{} + for _, fieldHashItem := range fieldHash { + fieldHashRule = append(fieldHashRule, fieldHashItem) + } + + logs, sub, err := _LatestValueHolder.contract.FilterLogs(opts, "TriggeredEventWithDynamicTopic", fieldHashRule) + if err != nil { + return nil, err + } + return &LatestValueHolderTriggeredEventWithDynamicTopicIterator{contract: _LatestValueHolder.contract, event: "TriggeredEventWithDynamicTopic", logs: logs, sub: sub}, nil +} + +func (_LatestValueHolder *LatestValueHolderFilterer) WatchTriggeredEventWithDynamicTopic(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggeredEventWithDynamicTopic, fieldHash []string) (event.Subscription, error) { + + var fieldHashRule []interface{} + for _, fieldHashItem := range fieldHash { + fieldHashRule = append(fieldHashRule, fieldHashItem) + } + + logs, sub, err := _LatestValueHolder.contract.WatchLogs(opts, "TriggeredEventWithDynamicTopic", fieldHashRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(LatestValueHolderTriggeredEventWithDynamicTopic) + if err := _LatestValueHolder.contract.UnpackLog(event, "TriggeredEventWithDynamicTopic", 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 (_LatestValueHolder *LatestValueHolderFilterer) ParseTriggeredEventWithDynamicTopic(log types.Log) (*LatestValueHolderTriggeredEventWithDynamicTopic, error) { + event := new(LatestValueHolderTriggeredEventWithDynamicTopic) + if err := _LatestValueHolder.contract.UnpackLog(event, "TriggeredEventWithDynamicTopic", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type LatestValueHolderTriggeredWithFourTopicsIterator struct { + Event *LatestValueHolderTriggeredWithFourTopics + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *LatestValueHolderTriggeredWithFourTopicsIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(LatestValueHolderTriggeredWithFourTopics) + 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(LatestValueHolderTriggeredWithFourTopics) + 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 *LatestValueHolderTriggeredWithFourTopicsIterator) Error() error { + return it.fail +} + +func (it *LatestValueHolderTriggeredWithFourTopicsIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type LatestValueHolderTriggeredWithFourTopics struct { + Field1 int32 + Field2 int32 + Field3 int32 + Raw types.Log +} + +func (_LatestValueHolder *LatestValueHolderFilterer) FilterTriggeredWithFourTopics(opts *bind.FilterOpts, field1 []int32, field2 []int32, field3 []int32) (*LatestValueHolderTriggeredWithFourTopicsIterator, error) { + + var field1Rule []interface{} + for _, field1Item := range field1 { + field1Rule = append(field1Rule, field1Item) + } + var field2Rule []interface{} + for _, field2Item := range field2 { + field2Rule = append(field2Rule, field2Item) + } + var field3Rule []interface{} + for _, field3Item := range field3 { + field3Rule = append(field3Rule, field3Item) + } + + logs, sub, err := _LatestValueHolder.contract.FilterLogs(opts, "TriggeredWithFourTopics", field1Rule, field2Rule, field3Rule) + if err != nil { + return nil, err + } + return &LatestValueHolderTriggeredWithFourTopicsIterator{contract: _LatestValueHolder.contract, event: "TriggeredWithFourTopics", logs: logs, sub: sub}, nil +} + +func (_LatestValueHolder *LatestValueHolderFilterer) WatchTriggeredWithFourTopics(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggeredWithFourTopics, field1 []int32, field2 []int32, field3 []int32) (event.Subscription, error) { + + var field1Rule []interface{} + for _, field1Item := range field1 { + field1Rule = append(field1Rule, field1Item) + } + var field2Rule []interface{} + for _, field2Item := range field2 { + field2Rule = append(field2Rule, field2Item) + } + var field3Rule []interface{} + for _, field3Item := range field3 { + field3Rule = append(field3Rule, field3Item) + } + + logs, sub, err := _LatestValueHolder.contract.WatchLogs(opts, "TriggeredWithFourTopics", field1Rule, field2Rule, field3Rule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(LatestValueHolderTriggeredWithFourTopics) + if err := _LatestValueHolder.contract.UnpackLog(event, "TriggeredWithFourTopics", 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 (_LatestValueHolder *LatestValueHolderFilterer) ParseTriggeredWithFourTopics(log types.Log) (*LatestValueHolderTriggeredWithFourTopics, error) { + event := new(LatestValueHolderTriggeredWithFourTopics) + if err := _LatestValueHolder.contract.UnpackLog(event, "TriggeredWithFourTopics", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_LatestValueHolder *LatestValueHolder) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _LatestValueHolder.abi.Events["Triggered"].ID: + return _LatestValueHolder.ParseTriggered(log) + case _LatestValueHolder.abi.Events["TriggeredEventWithDynamicTopic"].ID: + return _LatestValueHolder.ParseTriggeredEventWithDynamicTopic(log) + case _LatestValueHolder.abi.Events["TriggeredWithFourTopics"].ID: + return _LatestValueHolder.ParseTriggeredWithFourTopics(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (LatestValueHolderTriggered) Topic() common.Hash { + return common.HexToHash("0x7188419dcd8b51877b71766f075f3626586c0ff190e7d056aa65ce9acb649a3d") +} + +func (LatestValueHolderTriggeredEventWithDynamicTopic) Topic() common.Hash { + return common.HexToHash("0x3d969732b1bbbb9f1d7eb9f3f14e4cb50a74d950b3ef916a397b85dfbab93c67") +} + +func (LatestValueHolderTriggeredWithFourTopics) Topic() common.Hash { + return common.HexToHash("0x91c80dc390f3d041b3a04b0099b19634499541ea26972250986ee4b24a12fac5") +} + +func (_LatestValueHolder *LatestValueHolder) Address() common.Address { + return _LatestValueHolder.address +} + +type LatestValueHolderInterface interface { + GetDifferentPrimitiveValue(opts *bind.CallOpts) (uint64, error) + + GetElementAtIndex(opts *bind.CallOpts, i *big.Int) (TestStruct, error) + + GetPrimitiveValue(opts *bind.CallOpts) (uint64, error) + + GetSliceValue(opts *bind.CallOpts) ([]uint64, error) + + ReturnSeen(opts *bind.CallOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (TestStruct, error) + + AddTestStruct(opts *bind.TransactOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) + + TriggerEvent(opts *bind.TransactOpts, field int32, differentField string, oracleId uint8, oracleIds [32]uint8, account common.Address, accounts []common.Address, bigField *big.Int, nestedStruct MidLevelTestStruct) (*types.Transaction, error) + + TriggerEventWithDynamicTopic(opts *bind.TransactOpts, field string) (*types.Transaction, error) + + TriggerWithFourTopics(opts *bind.TransactOpts, field1 int32, field2 int32, field3 int32) (*types.Transaction, error) + + FilterTriggered(opts *bind.FilterOpts, field []int32) (*LatestValueHolderTriggeredIterator, error) + + WatchTriggered(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggered, field []int32) (event.Subscription, error) + + ParseTriggered(log types.Log) (*LatestValueHolderTriggered, error) + + FilterTriggeredEventWithDynamicTopic(opts *bind.FilterOpts, fieldHash []string) (*LatestValueHolderTriggeredEventWithDynamicTopicIterator, error) + + WatchTriggeredEventWithDynamicTopic(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggeredEventWithDynamicTopic, fieldHash []string) (event.Subscription, error) + + ParseTriggeredEventWithDynamicTopic(log types.Log) (*LatestValueHolderTriggeredEventWithDynamicTopic, error) + + FilterTriggeredWithFourTopics(opts *bind.FilterOpts, field1 []int32, field2 []int32, field3 []int32) (*LatestValueHolderTriggeredWithFourTopicsIterator, error) + + WatchTriggeredWithFourTopics(opts *bind.WatchOpts, sink chan<- *LatestValueHolderTriggeredWithFourTopics, field1 []int32, field2 []int32, field3 []int32) (event.Subscription, error) + + ParseTriggeredWithFourTopics(log types.Log) (*LatestValueHolderTriggeredWithFourTopics, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_2/i_keeper_registry_master_wrapper_2_2.go b/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_2/i_keeper_registry_master_wrapper_2_2.go new file mode 100644 index 00000000000..fe514342216 --- /dev/null +++ b/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_2/i_keeper_registry_master_wrapper_2_2.go @@ -0,0 +1,6443 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package i_keeper_registry_master_wrapper_2_2 + +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 AutomationRegistryBase22OnchainConfig struct { + PaymentPremiumPPB uint32 + FlatFeeMicroLink uint32 + CheckGasLimit uint32 + StalenessSeconds *big.Int + GasCeilingMultiplier uint16 + MinUpkeepSpend *big.Int + MaxPerformGas uint32 + MaxCheckDataSize uint32 + MaxPerformDataSize uint32 + MaxRevertDataSize uint32 + FallbackGasPrice *big.Int + FallbackLinkPrice *big.Int + Transcoder common.Address + Registrars []common.Address + UpkeepPrivilegeManager common.Address + ReorgProtectionEnabled bool +} + +type AutomationRegistryBase22State struct { + Nonce uint32 + OwnerLinkBalance *big.Int + ExpectedLinkBalance *big.Int + TotalPremium *big.Int + NumUpkeeps *big.Int + ConfigCount uint32 + LatestConfigBlockNumber uint32 + LatestConfigDigest [32]byte + LatestEpoch uint32 + Paused bool +} + +type AutomationRegistryBase22UpkeepInfo struct { + Target common.Address + PerformGas uint32 + CheckData []byte + Balance *big.Int + Admin common.Address + MaxValidBlocknumber uint64 + LastPerformedBlockNumber uint32 + AmountSpent *big.Int + Paused bool + OffchainConfig []byte +} + +var IAutomationRegistryMasterMetaData = &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\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"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\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"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\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"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\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"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\":\"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\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"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\":\"nonpayable\",\"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\":\"nonpayable\",\"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\":\"linkNative\",\"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\":\"linkNative\",\"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\":\"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\":\"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\":[],\"name\":\"getCancellationDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConditionalGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"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\":\"getLinkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkNativeFeedAddress\",\"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\":\"uint8\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"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\":\"getMode\",\"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\":[{\"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\":\"structAutomationRegistryBase2_2.State\",\"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\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"internalType\":\"structAutomationRegistryBase2_2.OnchainConfig\",\"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\":[{\"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\":\"structAutomationRegistryBase2_2.UpkeepInfo\",\"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\":[{\"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\":[{\"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\":[],\"name\":\"recoverFunds\",\"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\":\"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\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"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\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"newPrivilegeConfig\",\"type\":\"bytes\"}],\"name\":\"setAdminPrivilegeConfig\",\"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\":\"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\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"internalType\":\"structAutomationRegistryBase2_2.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"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\":[{\"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\":\"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\":\"upkeepTranscoderVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawOwnerFunds\",\"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 IAutomationRegistryMasterABI = IAutomationRegistryMasterMetaData.ABI + +type IAutomationRegistryMaster struct { + address common.Address + abi abi.ABI + IAutomationRegistryMasterCaller + IAutomationRegistryMasterTransactor + IAutomationRegistryMasterFilterer +} + +type IAutomationRegistryMasterCaller struct { + contract *bind.BoundContract +} + +type IAutomationRegistryMasterTransactor struct { + contract *bind.BoundContract +} + +type IAutomationRegistryMasterFilterer struct { + contract *bind.BoundContract +} + +type IAutomationRegistryMasterSession struct { + Contract *IAutomationRegistryMaster + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type IAutomationRegistryMasterCallerSession struct { + Contract *IAutomationRegistryMasterCaller + CallOpts bind.CallOpts +} + +type IAutomationRegistryMasterTransactorSession struct { + Contract *IAutomationRegistryMasterTransactor + TransactOpts bind.TransactOpts +} + +type IAutomationRegistryMasterRaw struct { + Contract *IAutomationRegistryMaster +} + +type IAutomationRegistryMasterCallerRaw struct { + Contract *IAutomationRegistryMasterCaller +} + +type IAutomationRegistryMasterTransactorRaw struct { + Contract *IAutomationRegistryMasterTransactor +} + +func NewIAutomationRegistryMaster(address common.Address, backend bind.ContractBackend) (*IAutomationRegistryMaster, error) { + abi, err := abi.JSON(strings.NewReader(IAutomationRegistryMasterABI)) + if err != nil { + return nil, err + } + contract, err := bindIAutomationRegistryMaster(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IAutomationRegistryMaster{address: address, abi: abi, IAutomationRegistryMasterCaller: IAutomationRegistryMasterCaller{contract: contract}, IAutomationRegistryMasterTransactor: IAutomationRegistryMasterTransactor{contract: contract}, IAutomationRegistryMasterFilterer: IAutomationRegistryMasterFilterer{contract: contract}}, nil +} + +func NewIAutomationRegistryMasterCaller(address common.Address, caller bind.ContractCaller) (*IAutomationRegistryMasterCaller, error) { + contract, err := bindIAutomationRegistryMaster(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterCaller{contract: contract}, nil +} + +func NewIAutomationRegistryMasterTransactor(address common.Address, transactor bind.ContractTransactor) (*IAutomationRegistryMasterTransactor, error) { + contract, err := bindIAutomationRegistryMaster(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterTransactor{contract: contract}, nil +} + +func NewIAutomationRegistryMasterFilterer(address common.Address, filterer bind.ContractFilterer) (*IAutomationRegistryMasterFilterer, error) { + contract, err := bindIAutomationRegistryMaster(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterFilterer{contract: contract}, nil +} + +func bindIAutomationRegistryMaster(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IAutomationRegistryMasterMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAutomationRegistryMaster.Contract.IAutomationRegistryMasterCaller.contract.Call(opts, result, method, params...) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.IAutomationRegistryMasterTransactor.contract.Transfer(opts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.IAutomationRegistryMasterTransactor.contract.Transact(opts, method, params...) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IAutomationRegistryMaster.Contract.contract.Call(opts, result, method, params...) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.contract.Transfer(opts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.contract.Transact(opts, method, params...) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "checkCallback", id, values, extraData) + + outstruct := new(CheckCallback) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + outstruct.UpkeepFailureReason = *abi.ConvertType(out[2], new(uint8)).(*uint8) + outstruct.GasUsed = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) { + return _IAutomationRegistryMaster.Contract.CheckCallback(&_IAutomationRegistryMaster.CallOpts, id, values, extraData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) { + return _IAutomationRegistryMaster.Contract.CheckCallback(&_IAutomationRegistryMaster.CallOpts, id, values, extraData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) CheckUpkeep(opts *bind.CallOpts, id *big.Int, triggerData []byte) (CheckUpkeep, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "checkUpkeep", id, triggerData) + + outstruct := new(CheckUpkeep) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + outstruct.UpkeepFailureReason = *abi.ConvertType(out[2], new(uint8)).(*uint8) + outstruct.GasUsed = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.GasLimit = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + outstruct.FastGasWei = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + outstruct.LinkNative = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) CheckUpkeep(id *big.Int, triggerData []byte) (CheckUpkeep, + + error) { + return _IAutomationRegistryMaster.Contract.CheckUpkeep(&_IAutomationRegistryMaster.CallOpts, id, triggerData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) CheckUpkeep(id *big.Int, triggerData []byte) (CheckUpkeep, + + error) { + return _IAutomationRegistryMaster.Contract.CheckUpkeep(&_IAutomationRegistryMaster.CallOpts, id, triggerData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) CheckUpkeep0(opts *bind.CallOpts, id *big.Int) (CheckUpkeep0, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "checkUpkeep0", id) + + outstruct := new(CheckUpkeep0) + if err != nil { + return *outstruct, err + } + + outstruct.UpkeepNeeded = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.PerformData = *abi.ConvertType(out[1], new([]byte)).(*[]byte) + outstruct.UpkeepFailureReason = *abi.ConvertType(out[2], new(uint8)).(*uint8) + outstruct.GasUsed = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.GasLimit = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + outstruct.FastGasWei = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + outstruct.LinkNative = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) CheckUpkeep0(id *big.Int) (CheckUpkeep0, + + error) { + return _IAutomationRegistryMaster.Contract.CheckUpkeep0(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) CheckUpkeep0(id *big.Int) (CheckUpkeep0, + + error) { + return _IAutomationRegistryMaster.Contract.CheckUpkeep0(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) FallbackTo(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "fallbackTo") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) FallbackTo() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.FallbackTo(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) FallbackTo() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.FallbackTo(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getActiveUpkeepIDs", startIndex, maxCount) + + if err != nil { + return *new([]*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetActiveUpkeepIDs(startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetActiveUpkeepIDs(&_IAutomationRegistryMaster.CallOpts, startIndex, maxCount) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetActiveUpkeepIDs(startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetActiveUpkeepIDs(&_IAutomationRegistryMaster.CallOpts, startIndex, maxCount) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetAdminPrivilegeConfig(opts *bind.CallOpts, admin common.Address) ([]byte, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getAdminPrivilegeConfig", admin) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetAdminPrivilegeConfig(admin common.Address) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetAdminPrivilegeConfig(&_IAutomationRegistryMaster.CallOpts, admin) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetAdminPrivilegeConfig(admin common.Address) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetAdminPrivilegeConfig(&_IAutomationRegistryMaster.CallOpts, admin) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetAutomationForwarderLogic(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getAutomationForwarderLogic") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetAutomationForwarderLogic() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetAutomationForwarderLogic(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetAutomationForwarderLogic() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetAutomationForwarderLogic(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getBalance", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetBalance(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetBalance(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetBalance(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetBalance(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetCancellationDelay(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getCancellationDelay") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetCancellationDelay() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetCancellationDelay(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetCancellationDelay() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetCancellationDelay(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getConditionalGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetConditionalGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetConditionalGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetConditionalGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetConditionalGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getFastGasFeedAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetFastGasFeedAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetFastGasFeedAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetFastGasFeedAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetFastGasFeedAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getForwarder", upkeepID) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetForwarder(upkeepID *big.Int) (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetForwarder(&_IAutomationRegistryMaster.CallOpts, upkeepID) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetForwarder(upkeepID *big.Int) (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetForwarder(&_IAutomationRegistryMaster.CallOpts, upkeepID) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetLinkAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getLinkAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetLinkAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetLinkAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetLinkAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetLinkAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetLinkNativeFeedAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getLinkNativeFeedAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetLinkNativeFeedAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetLinkNativeFeedAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetLinkNativeFeedAddress() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.GetLinkNativeFeedAddress(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getLogGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetLogGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetLogGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetLogGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetLogGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getMaxPaymentForGas", triggerType, gasLimit) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMaxPaymentForGas(&_IAutomationRegistryMaster.CallOpts, triggerType, gasLimit) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMaxPaymentForGas(&_IAutomationRegistryMaster.CallOpts, triggerType, gasLimit) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getMinBalance", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetMinBalance(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMinBalance(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetMinBalance(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMinBalance(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetMinBalanceForUpkeep(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getMinBalanceForUpkeep", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetMinBalanceForUpkeep(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMinBalanceForUpkeep(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetMinBalanceForUpkeep(id *big.Int) (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetMinBalanceForUpkeep(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetMode(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getMode") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetMode() (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetMode(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetMode() (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetMode(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getPeerRegistryMigrationPermission", peer) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetPeerRegistryMigrationPermission(peer common.Address) (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetPeerRegistryMigrationPermission(&_IAutomationRegistryMaster.CallOpts, peer) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetPeerRegistryMigrationPermission(peer common.Address) (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetPeerRegistryMigrationPermission(&_IAutomationRegistryMaster.CallOpts, peer) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getPerPerformByteGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetPerPerformByteGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetPerPerformByteGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetPerPerformByteGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetPerPerformByteGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetPerSignerGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getPerSignerGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetPerSignerGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetPerSignerGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetPerSignerGasOverhead() (*big.Int, error) { + return _IAutomationRegistryMaster.Contract.GetPerSignerGasOverhead(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getSignerInfo", query) + + outstruct := new(GetSignerInfo) + if err != nil { + return *outstruct, err + } + + outstruct.Active = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Index = *abi.ConvertType(out[1], new(uint8)).(*uint8) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetSignerInfo(query common.Address) (GetSignerInfo, + + error) { + return _IAutomationRegistryMaster.Contract.GetSignerInfo(&_IAutomationRegistryMaster.CallOpts, query) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetSignerInfo(query common.Address) (GetSignerInfo, + + error) { + return _IAutomationRegistryMaster.Contract.GetSignerInfo(&_IAutomationRegistryMaster.CallOpts, query) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetState(opts *bind.CallOpts) (GetState, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getState") + + outstruct := new(GetState) + if err != nil { + return *outstruct, err + } + + outstruct.State = *abi.ConvertType(out[0], new(AutomationRegistryBase22State)).(*AutomationRegistryBase22State) + outstruct.Config = *abi.ConvertType(out[1], new(AutomationRegistryBase22OnchainConfig)).(*AutomationRegistryBase22OnchainConfig) + outstruct.Signers = *abi.ConvertType(out[2], new([]common.Address)).(*[]common.Address) + outstruct.Transmitters = *abi.ConvertType(out[3], new([]common.Address)).(*[]common.Address) + outstruct.F = *abi.ConvertType(out[4], new(uint8)).(*uint8) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetState() (GetState, + + error) { + return _IAutomationRegistryMaster.Contract.GetState(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetState() (GetState, + + error) { + return _IAutomationRegistryMaster.Contract.GetState(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetTransmitterInfo(opts *bind.CallOpts, query common.Address) (GetTransmitterInfo, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getTransmitterInfo", query) + + outstruct := new(GetTransmitterInfo) + if err != nil { + return *outstruct, err + } + + outstruct.Active = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Index = *abi.ConvertType(out[1], new(uint8)).(*uint8) + outstruct.Balance = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.LastCollected = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.Payee = *abi.ConvertType(out[4], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetTransmitterInfo(query common.Address) (GetTransmitterInfo, + + error) { + return _IAutomationRegistryMaster.Contract.GetTransmitterInfo(&_IAutomationRegistryMaster.CallOpts, query) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetTransmitterInfo(query common.Address) (GetTransmitterInfo, + + error) { + return _IAutomationRegistryMaster.Contract.GetTransmitterInfo(&_IAutomationRegistryMaster.CallOpts, query) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getTriggerType", upkeepId) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetTriggerType(upkeepId *big.Int) (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetTriggerType(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetTriggerType(upkeepId *big.Int) (uint8, error) { + return _IAutomationRegistryMaster.Contract.GetTriggerType(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getUpkeep", id) + + if err != nil { + return *new(AutomationRegistryBase22UpkeepInfo), err + } + + out0 := *abi.ConvertType(out[0], new(AutomationRegistryBase22UpkeepInfo)).(*AutomationRegistryBase22UpkeepInfo) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetUpkeep(id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeep(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetUpkeep(id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeep(&_IAutomationRegistryMaster.CallOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getUpkeepPrivilegeConfig", upkeepId) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeepPrivilegeConfig(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeepPrivilegeConfig(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "getUpkeepTriggerConfig", upkeepId) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) GetUpkeepTriggerConfig(upkeepId *big.Int) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeepTriggerConfig(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) GetUpkeepTriggerConfig(upkeepId *big.Int) ([]byte, error) { + return _IAutomationRegistryMaster.Contract.GetUpkeepTriggerConfig(&_IAutomationRegistryMaster.CallOpts, upkeepId) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "hasDedupKey", dedupKey) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) HasDedupKey(dedupKey [32]byte) (bool, error) { + return _IAutomationRegistryMaster.Contract.HasDedupKey(&_IAutomationRegistryMaster.CallOpts, dedupKey) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) HasDedupKey(dedupKey [32]byte) (bool, error) { + return _IAutomationRegistryMaster.Contract.HasDedupKey(&_IAutomationRegistryMaster.CallOpts, dedupKey) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "latestConfigDetails") + + outstruct := new(LatestConfigDetails) + if err != nil { + return *outstruct, err + } + + outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32) + outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) LatestConfigDetails() (LatestConfigDetails, + + error) { + return _IAutomationRegistryMaster.Contract.LatestConfigDetails(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) LatestConfigDetails() (LatestConfigDetails, + + error) { + return _IAutomationRegistryMaster.Contract.LatestConfigDetails(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "latestConfigDigestAndEpoch") + + outstruct := new(LatestConfigDigestAndEpoch) + if err != nil { + return *outstruct, err + } + + outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) + outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, + + error) { + return _IAutomationRegistryMaster.Contract.LatestConfigDigestAndEpoch(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, + + error) { + return _IAutomationRegistryMaster.Contract.LatestConfigDigestAndEpoch(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _IAutomationRegistryMaster.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 (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) Owner() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.Owner(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) Owner() (common.Address, error) { + return _IAutomationRegistryMaster.Contract.Owner(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) SimulatePerformUpkeep(opts *bind.CallOpts, id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "simulatePerformUpkeep", id, performData) + + outstruct := new(SimulatePerformUpkeep) + if err != nil { + return *outstruct, err + } + + outstruct.Success = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.GasUsed = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) { + return _IAutomationRegistryMaster.Contract.SimulatePerformUpkeep(&_IAutomationRegistryMaster.CallOpts, id, performData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) { + return _IAutomationRegistryMaster.Contract.SimulatePerformUpkeep(&_IAutomationRegistryMaster.CallOpts, id, performData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) TypeAndVersion() (string, error) { + return _IAutomationRegistryMaster.Contract.TypeAndVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) TypeAndVersion() (string, error) { + return _IAutomationRegistryMaster.Contract.TypeAndVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "upkeepTranscoderVersion") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) UpkeepTranscoderVersion() (uint8, error) { + return _IAutomationRegistryMaster.Contract.UpkeepTranscoderVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) UpkeepTranscoderVersion() (uint8, error) { + return _IAutomationRegistryMaster.Contract.UpkeepTranscoderVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCaller) UpkeepVersion(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _IAutomationRegistryMaster.contract.Call(opts, &out, "upkeepVersion") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) UpkeepVersion() (uint8, error) { + return _IAutomationRegistryMaster.Contract.UpkeepVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterCallerSession) UpkeepVersion() (uint8, error) { + return _IAutomationRegistryMaster.Contract.UpkeepVersion(&_IAutomationRegistryMaster.CallOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "acceptOwnership") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) AcceptOwnership() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptOwnership(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptOwnership(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "acceptPayeeship", transmitter) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptPayeeship(&_IAutomationRegistryMaster.TransactOpts, transmitter) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptPayeeship(&_IAutomationRegistryMaster.TransactOpts, transmitter) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "acceptUpkeepAdmin", id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptUpkeepAdmin(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AcceptUpkeepAdmin(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "addFunds", id, amount) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AddFunds(&_IAutomationRegistryMaster.TransactOpts, id, amount) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.AddFunds(&_IAutomationRegistryMaster.TransactOpts, id, amount) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) CancelUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "cancelUpkeep", id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) CancelUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.CancelUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) CancelUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.CancelUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "executeCallback", id, payload) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.ExecuteCallback(&_IAutomationRegistryMaster.TransactOpts, id, payload) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.ExecuteCallback(&_IAutomationRegistryMaster.TransactOpts, id, payload) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) MigrateUpkeeps(opts *bind.TransactOpts, ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "migrateUpkeeps", ids, destination) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) MigrateUpkeeps(ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.MigrateUpkeeps(&_IAutomationRegistryMaster.TransactOpts, ids, destination) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) MigrateUpkeeps(ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.MigrateUpkeeps(&_IAutomationRegistryMaster.TransactOpts, ids, destination) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "onTokenTransfer", sender, amount, data) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.OnTokenTransfer(&_IAutomationRegistryMaster.TransactOpts, sender, amount, data) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.OnTokenTransfer(&_IAutomationRegistryMaster.TransactOpts, sender, amount, data) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "pause") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) Pause() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Pause(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) Pause() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Pause(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "pauseUpkeep", id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.PauseUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.PauseUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) ReceiveUpkeeps(opts *bind.TransactOpts, encodedUpkeeps []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "receiveUpkeeps", encodedUpkeeps) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) ReceiveUpkeeps(encodedUpkeeps []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.ReceiveUpkeeps(&_IAutomationRegistryMaster.TransactOpts, encodedUpkeeps) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) ReceiveUpkeeps(encodedUpkeeps []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.ReceiveUpkeeps(&_IAutomationRegistryMaster.TransactOpts, encodedUpkeeps) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) RecoverFunds(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "recoverFunds") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) RecoverFunds() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RecoverFunds(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) RecoverFunds() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RecoverFunds(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "registerUpkeep", target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RegisterUpkeep(&_IAutomationRegistryMaster.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RegisterUpkeep(&_IAutomationRegistryMaster.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "registerUpkeep0", target, gasLimit, admin, checkData, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RegisterUpkeep0(&_IAutomationRegistryMaster.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.RegisterUpkeep0(&_IAutomationRegistryMaster.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setAdminPrivilegeConfig", admin, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetAdminPrivilegeConfig(admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetAdminPrivilegeConfig(&_IAutomationRegistryMaster.TransactOpts, admin, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetAdminPrivilegeConfig(admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetAdminPrivilegeConfig(&_IAutomationRegistryMaster.TransactOpts, admin, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setConfig", signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetConfig(signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetConfig(&_IAutomationRegistryMaster.TransactOpts, signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetConfig(signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetConfig(&_IAutomationRegistryMaster.TransactOpts, signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetConfigTypeSafe(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setConfigTypeSafe", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetConfigTypeSafe(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetConfigTypeSafe(&_IAutomationRegistryMaster.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetConfigTypeSafe(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetConfigTypeSafe(&_IAutomationRegistryMaster.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetPayees(opts *bind.TransactOpts, payees []common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setPayees", payees) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetPayees(payees []common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetPayees(&_IAutomationRegistryMaster.TransactOpts, payees) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetPayees(payees []common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetPayees(&_IAutomationRegistryMaster.TransactOpts, payees) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetPeerRegistryMigrationPermission(opts *bind.TransactOpts, peer common.Address, permission uint8) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setPeerRegistryMigrationPermission", peer, permission) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetPeerRegistryMigrationPermission(peer common.Address, permission uint8) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetPeerRegistryMigrationPermission(&_IAutomationRegistryMaster.TransactOpts, peer, permission) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetPeerRegistryMigrationPermission(peer common.Address, permission uint8) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetPeerRegistryMigrationPermission(&_IAutomationRegistryMaster.TransactOpts, peer, permission) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setUpkeepCheckData", id, newCheckData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepCheckData(&_IAutomationRegistryMaster.TransactOpts, id, newCheckData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepCheckData(&_IAutomationRegistryMaster.TransactOpts, id, newCheckData) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetUpkeepGasLimit(opts *bind.TransactOpts, id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setUpkeepGasLimit", id, gasLimit) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepGasLimit(&_IAutomationRegistryMaster.TransactOpts, id, gasLimit) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepGasLimit(&_IAutomationRegistryMaster.TransactOpts, id, gasLimit) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setUpkeepOffchainConfig", id, config) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepOffchainConfig(&_IAutomationRegistryMaster.TransactOpts, id, config) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepOffchainConfig(&_IAutomationRegistryMaster.TransactOpts, id, config) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetUpkeepPrivilegeConfig(opts *bind.TransactOpts, upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setUpkeepPrivilegeConfig", upkeepId, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetUpkeepPrivilegeConfig(upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepPrivilegeConfig(&_IAutomationRegistryMaster.TransactOpts, upkeepId, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetUpkeepPrivilegeConfig(upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepPrivilegeConfig(&_IAutomationRegistryMaster.TransactOpts, upkeepId, newPrivilegeConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "setUpkeepTriggerConfig", id, triggerConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepTriggerConfig(&_IAutomationRegistryMaster.TransactOpts, id, triggerConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.SetUpkeepTriggerConfig(&_IAutomationRegistryMaster.TransactOpts, id, triggerConfig) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "transferOwnership", to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferOwnership(&_IAutomationRegistryMaster.TransactOpts, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferOwnership(&_IAutomationRegistryMaster.TransactOpts, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "transferPayeeship", transmitter, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferPayeeship(&_IAutomationRegistryMaster.TransactOpts, transmitter, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferPayeeship(&_IAutomationRegistryMaster.TransactOpts, transmitter, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "transferUpkeepAdmin", id, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferUpkeepAdmin(&_IAutomationRegistryMaster.TransactOpts, id, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.TransferUpkeepAdmin(&_IAutomationRegistryMaster.TransactOpts, id, proposed) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "transmit", reportContext, rawReport, rs, ss, rawVs) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) Transmit(reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Transmit(&_IAutomationRegistryMaster.TransactOpts, reportContext, rawReport, rs, ss, rawVs) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) Transmit(reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Transmit(&_IAutomationRegistryMaster.TransactOpts, reportContext, rawReport, rs, ss, rawVs) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "unpause") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) Unpause() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Unpause(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) Unpause() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Unpause(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "unpauseUpkeep", id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.UnpauseUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.UnpauseUpkeep(&_IAutomationRegistryMaster.TransactOpts, id) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "withdrawFunds", id, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawFunds(&_IAutomationRegistryMaster.TransactOpts, id, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawFunds(&_IAutomationRegistryMaster.TransactOpts, id, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) WithdrawOwnerFunds(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "withdrawOwnerFunds") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) WithdrawOwnerFunds() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawOwnerFunds(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) WithdrawOwnerFunds() (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawOwnerFunds(&_IAutomationRegistryMaster.TransactOpts) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.Transact(opts, "withdrawPayment", from, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawPayment(&_IAutomationRegistryMaster.TransactOpts, from, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.WithdrawPayment(&_IAutomationRegistryMaster.TransactOpts, from, to) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.contract.RawTransact(opts, calldata) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Fallback(&_IAutomationRegistryMaster.TransactOpts, calldata) +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterTransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _IAutomationRegistryMaster.Contract.Fallback(&_IAutomationRegistryMaster.TransactOpts, calldata) +} + +type IAutomationRegistryMasterAdminPrivilegeConfigSetIterator struct { + Event *IAutomationRegistryMasterAdminPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterAdminPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterAdminPrivilegeConfigSet) + 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(IAutomationRegistryMasterAdminPrivilegeConfigSet) + 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 *IAutomationRegistryMasterAdminPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterAdminPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterAdminPrivilegeConfigSet struct { + Admin common.Address + PrivilegeConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*IAutomationRegistryMasterAdminPrivilegeConfigSetIterator, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterAdminPrivilegeConfigSetIterator{contract: _IAutomationRegistryMaster.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterAdminPrivilegeConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "AdminPrivilegeConfigSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseAdminPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMasterAdminPrivilegeConfigSet, error) { + event := new(IAutomationRegistryMasterAdminPrivilegeConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterCancelledUpkeepReportIterator struct { + Event *IAutomationRegistryMasterCancelledUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterCancelledUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterCancelledUpkeepReport) + 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(IAutomationRegistryMasterCancelledUpkeepReport) + 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 *IAutomationRegistryMasterCancelledUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterCancelledUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterCancelledUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterCancelledUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterCancelledUpkeepReportIterator{contract: _IAutomationRegistryMaster.contract, event: "CancelledUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterCancelledUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "CancelledUpkeepReport", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseCancelledUpkeepReport(log types.Log) (*IAutomationRegistryMasterCancelledUpkeepReport, error) { + event := new(IAutomationRegistryMasterCancelledUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "CancelledUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterConfigSetIterator struct { + Event *IAutomationRegistryMasterConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterConfigSet) + 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(IAutomationRegistryMasterConfigSet) + 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 *IAutomationRegistryMasterConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterConfigSet struct { + PreviousConfigBlockNumber uint32 + ConfigDigest [32]byte + ConfigCount uint64 + Signers []common.Address + Transmitters []common.Address + F uint8 + OnchainConfig []byte + OffchainConfigVersion uint64 + OffchainConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterConfigSet(opts *bind.FilterOpts) (*IAutomationRegistryMasterConfigSetIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterConfigSetIterator{contract: _IAutomationRegistryMaster.contract, event: "ConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterConfigSet) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "ConfigSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseConfigSet(log types.Log) (*IAutomationRegistryMasterConfigSet, error) { + event := new(IAutomationRegistryMasterConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "ConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterDedupKeyAddedIterator struct { + Event *IAutomationRegistryMasterDedupKeyAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterDedupKeyAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterDedupKeyAdded) + 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(IAutomationRegistryMasterDedupKeyAdded) + 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 *IAutomationRegistryMasterDedupKeyAddedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterDedupKeyAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterDedupKeyAdded struct { + DedupKey [32]byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*IAutomationRegistryMasterDedupKeyAddedIterator, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterDedupKeyAddedIterator{contract: _IAutomationRegistryMaster.contract, event: "DedupKeyAdded", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterDedupKeyAdded) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "DedupKeyAdded", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseDedupKeyAdded(log types.Log) (*IAutomationRegistryMasterDedupKeyAdded, error) { + event := new(IAutomationRegistryMasterDedupKeyAdded) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "DedupKeyAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterFundsAddedIterator struct { + Event *IAutomationRegistryMasterFundsAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterFundsAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterFundsAdded) + 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(IAutomationRegistryMasterFundsAdded) + 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 *IAutomationRegistryMasterFundsAddedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterFundsAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterFundsAdded struct { + Id *big.Int + From common.Address + Amount *big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*IAutomationRegistryMasterFundsAddedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterFundsAddedIterator{contract: _IAutomationRegistryMaster.contract, event: "FundsAdded", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterFundsAdded) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "FundsAdded", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseFundsAdded(log types.Log) (*IAutomationRegistryMasterFundsAdded, error) { + event := new(IAutomationRegistryMasterFundsAdded) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "FundsAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterFundsWithdrawnIterator struct { + Event *IAutomationRegistryMasterFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterFundsWithdrawn) + 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(IAutomationRegistryMasterFundsWithdrawn) + 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 *IAutomationRegistryMasterFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterFundsWithdrawn struct { + Id *big.Int + Amount *big.Int + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterFundsWithdrawnIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterFundsWithdrawnIterator{contract: _IAutomationRegistryMaster.contract, event: "FundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterFundsWithdrawn, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterFundsWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "FundsWithdrawn", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseFundsWithdrawn(log types.Log) (*IAutomationRegistryMasterFundsWithdrawn, error) { + event := new(IAutomationRegistryMasterFundsWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "FundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator struct { + Event *IAutomationRegistryMasterInsufficientFundsUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterInsufficientFundsUpkeepReport) + 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(IAutomationRegistryMasterInsufficientFundsUpkeepReport) + 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 *IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterInsufficientFundsUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator{contract: _IAutomationRegistryMaster.contract, event: "InsufficientFundsUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterInsufficientFundsUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseInsufficientFundsUpkeepReport(log types.Log) (*IAutomationRegistryMasterInsufficientFundsUpkeepReport, error) { + event := new(IAutomationRegistryMasterInsufficientFundsUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterOwnerFundsWithdrawnIterator struct { + Event *IAutomationRegistryMasterOwnerFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterOwnerFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterOwnerFundsWithdrawn) + 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(IAutomationRegistryMasterOwnerFundsWithdrawn) + 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 *IAutomationRegistryMasterOwnerFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterOwnerFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterOwnerFundsWithdrawn struct { + Amount *big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*IAutomationRegistryMasterOwnerFundsWithdrawnIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterOwnerFundsWithdrawnIterator{contract: _IAutomationRegistryMaster.contract, event: "OwnerFundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnerFundsWithdrawn) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterOwnerFundsWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "OwnerFundsWithdrawn", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseOwnerFundsWithdrawn(log types.Log) (*IAutomationRegistryMasterOwnerFundsWithdrawn, error) { + event := new(IAutomationRegistryMasterOwnerFundsWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "OwnerFundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterOwnershipTransferRequestedIterator struct { + Event *IAutomationRegistryMasterOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterOwnershipTransferRequested) + 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(IAutomationRegistryMasterOwnershipTransferRequested) + 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 *IAutomationRegistryMasterOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IAutomationRegistryMasterOwnershipTransferRequestedIterator, 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterOwnershipTransferRequestedIterator{contract: _IAutomationRegistryMaster.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnershipTransferRequested, 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 := _IAutomationRegistryMaster.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(IAutomationRegistryMasterOwnershipTransferRequested) + if err := _IAutomationRegistryMaster.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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseOwnershipTransferRequested(log types.Log) (*IAutomationRegistryMasterOwnershipTransferRequested, error) { + event := new(IAutomationRegistryMasterOwnershipTransferRequested) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterOwnershipTransferredIterator struct { + Event *IAutomationRegistryMasterOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterOwnershipTransferred) + 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(IAutomationRegistryMasterOwnershipTransferred) + 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 *IAutomationRegistryMasterOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IAutomationRegistryMasterOwnershipTransferredIterator, 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterOwnershipTransferredIterator{contract: _IAutomationRegistryMaster.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnershipTransferred, 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 := _IAutomationRegistryMaster.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(IAutomationRegistryMasterOwnershipTransferred) + if err := _IAutomationRegistryMaster.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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseOwnershipTransferred(log types.Log) (*IAutomationRegistryMasterOwnershipTransferred, error) { + event := new(IAutomationRegistryMasterOwnershipTransferred) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterPausedIterator struct { + Event *IAutomationRegistryMasterPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterPaused) + 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(IAutomationRegistryMasterPaused) + 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 *IAutomationRegistryMasterPausedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterPaused struct { + Account common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterPaused(opts *bind.FilterOpts) (*IAutomationRegistryMasterPausedIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "Paused") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterPausedIterator{contract: _IAutomationRegistryMaster.contract, event: "Paused", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPaused) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "Paused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterPaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Paused", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParsePaused(log types.Log) (*IAutomationRegistryMasterPaused, error) { + event := new(IAutomationRegistryMasterPaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Paused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterPayeesUpdatedIterator struct { + Event *IAutomationRegistryMasterPayeesUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterPayeesUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterPayeesUpdated) + 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(IAutomationRegistryMasterPayeesUpdated) + 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 *IAutomationRegistryMasterPayeesUpdatedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterPayeesUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterPayeesUpdated struct { + Transmitters []common.Address + Payees []common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterPayeesUpdated(opts *bind.FilterOpts) (*IAutomationRegistryMasterPayeesUpdatedIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterPayeesUpdatedIterator{contract: _IAutomationRegistryMaster.contract, event: "PayeesUpdated", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeesUpdated) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterPayeesUpdated) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeesUpdated", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParsePayeesUpdated(log types.Log) (*IAutomationRegistryMasterPayeesUpdated, error) { + event := new(IAutomationRegistryMasterPayeesUpdated) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeesUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterPayeeshipTransferRequestedIterator struct { + Event *IAutomationRegistryMasterPayeeshipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterPayeeshipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterPayeeshipTransferRequested) + 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(IAutomationRegistryMasterPayeeshipTransferRequested) + 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 *IAutomationRegistryMasterPayeeshipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterPayeeshipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterPayeeshipTransferRequested struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*IAutomationRegistryMasterPayeeshipTransferRequestedIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "PayeeshipTransferRequested", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterPayeeshipTransferRequestedIterator{contract: _IAutomationRegistryMaster.contract, event: "PayeeshipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _IAutomationRegistryMaster.contract.WatchLogs(opts, "PayeeshipTransferRequested", transmitterRule, 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(IAutomationRegistryMasterPayeeshipTransferRequested) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeeshipTransferRequested", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParsePayeeshipTransferRequested(log types.Log) (*IAutomationRegistryMasterPayeeshipTransferRequested, error) { + event := new(IAutomationRegistryMasterPayeeshipTransferRequested) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeeshipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterPayeeshipTransferredIterator struct { + Event *IAutomationRegistryMasterPayeeshipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterPayeeshipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterPayeeshipTransferred) + 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(IAutomationRegistryMasterPayeeshipTransferred) + 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 *IAutomationRegistryMasterPayeeshipTransferredIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterPayeeshipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterPayeeshipTransferred struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*IAutomationRegistryMasterPayeeshipTransferredIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "PayeeshipTransferred", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterPayeeshipTransferredIterator{contract: _IAutomationRegistryMaster.contract, event: "PayeeshipTransferred", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _IAutomationRegistryMaster.contract.WatchLogs(opts, "PayeeshipTransferred", transmitterRule, 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(IAutomationRegistryMasterPayeeshipTransferred) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeeshipTransferred", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParsePayeeshipTransferred(log types.Log) (*IAutomationRegistryMasterPayeeshipTransferred, error) { + event := new(IAutomationRegistryMasterPayeeshipTransferred) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PayeeshipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterPaymentWithdrawnIterator struct { + Event *IAutomationRegistryMasterPaymentWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterPaymentWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterPaymentWithdrawn) + 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(IAutomationRegistryMasterPaymentWithdrawn) + 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 *IAutomationRegistryMasterPaymentWithdrawnIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterPaymentWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterPaymentWithdrawn struct { + Transmitter common.Address + Amount *big.Int + To common.Address + Payee common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*IAutomationRegistryMasterPaymentWithdrawnIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterPaymentWithdrawnIterator{contract: _IAutomationRegistryMaster.contract, event: "PaymentWithdrawn", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, 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(IAutomationRegistryMasterPaymentWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PaymentWithdrawn", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParsePaymentWithdrawn(log types.Log) (*IAutomationRegistryMasterPaymentWithdrawn, error) { + event := new(IAutomationRegistryMasterPaymentWithdrawn) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "PaymentWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterReorgedUpkeepReportIterator struct { + Event *IAutomationRegistryMasterReorgedUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterReorgedUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterReorgedUpkeepReport) + 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(IAutomationRegistryMasterReorgedUpkeepReport) + 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 *IAutomationRegistryMasterReorgedUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterReorgedUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterReorgedUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterReorgedUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterReorgedUpkeepReportIterator{contract: _IAutomationRegistryMaster.contract, event: "ReorgedUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterReorgedUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "ReorgedUpkeepReport", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseReorgedUpkeepReport(log types.Log) (*IAutomationRegistryMasterReorgedUpkeepReport, error) { + event := new(IAutomationRegistryMasterReorgedUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "ReorgedUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterStaleUpkeepReportIterator struct { + Event *IAutomationRegistryMasterStaleUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterStaleUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterStaleUpkeepReport) + 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(IAutomationRegistryMasterStaleUpkeepReport) + 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 *IAutomationRegistryMasterStaleUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterStaleUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterStaleUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterStaleUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterStaleUpkeepReportIterator{contract: _IAutomationRegistryMaster.contract, event: "StaleUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterStaleUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterStaleUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "StaleUpkeepReport", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseStaleUpkeepReport(log types.Log) (*IAutomationRegistryMasterStaleUpkeepReport, error) { + event := new(IAutomationRegistryMasterStaleUpkeepReport) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "StaleUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterTransmittedIterator struct { + Event *IAutomationRegistryMasterTransmitted + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterTransmittedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterTransmitted) + 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(IAutomationRegistryMasterTransmitted) + 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 *IAutomationRegistryMasterTransmittedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterTransmittedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterTransmitted struct { + ConfigDigest [32]byte + Epoch uint32 + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterTransmitted(opts *bind.FilterOpts) (*IAutomationRegistryMasterTransmittedIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "Transmitted") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterTransmittedIterator{contract: _IAutomationRegistryMaster.contract, event: "Transmitted", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterTransmitted) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "Transmitted") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterTransmitted) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Transmitted", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseTransmitted(log types.Log) (*IAutomationRegistryMasterTransmitted, error) { + event := new(IAutomationRegistryMasterTransmitted) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Transmitted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUnpausedIterator struct { + Event *IAutomationRegistryMasterUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUnpaused) + 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(IAutomationRegistryMasterUnpaused) + 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 *IAutomationRegistryMasterUnpausedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUnpaused struct { + Account common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUnpaused(opts *bind.FilterOpts) (*IAutomationRegistryMasterUnpausedIterator, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUnpausedIterator{contract: _IAutomationRegistryMaster.contract, event: "Unpaused", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUnpaused) (event.Subscription, error) { + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUnpaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Unpaused", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUnpaused(log types.Log) (*IAutomationRegistryMasterUnpaused, error) { + event := new(IAutomationRegistryMasterUnpaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "Unpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator struct { + Event *IAutomationRegistryMasterUpkeepAdminTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepAdminTransferRequested) + 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(IAutomationRegistryMasterUpkeepAdminTransferRequested) + 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 *IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepAdminTransferRequested struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepAdminTransferRequested", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepAdminTransferRequested", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepAdminTransferRequested", idRule, 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(IAutomationRegistryMasterUpkeepAdminTransferRequested) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepAdminTransferRequested", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepAdminTransferRequested(log types.Log) (*IAutomationRegistryMasterUpkeepAdminTransferRequested, error) { + event := new(IAutomationRegistryMasterUpkeepAdminTransferRequested) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepAdminTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepAdminTransferredIterator struct { + Event *IAutomationRegistryMasterUpkeepAdminTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepAdminTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepAdminTransferred) + 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(IAutomationRegistryMasterUpkeepAdminTransferred) + 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 *IAutomationRegistryMasterUpkeepAdminTransferredIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepAdminTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepAdminTransferred struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*IAutomationRegistryMasterUpkeepAdminTransferredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepAdminTransferred", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepAdminTransferredIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepAdminTransferred", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepAdminTransferred", idRule, 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(IAutomationRegistryMasterUpkeepAdminTransferred) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepAdminTransferred", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepAdminTransferred(log types.Log) (*IAutomationRegistryMasterUpkeepAdminTransferred, error) { + event := new(IAutomationRegistryMasterUpkeepAdminTransferred) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepAdminTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepCanceledIterator struct { + Event *IAutomationRegistryMasterUpkeepCanceled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepCanceledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepCanceled) + 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(IAutomationRegistryMasterUpkeepCanceled) + 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 *IAutomationRegistryMasterUpkeepCanceledIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepCanceledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepCanceled struct { + Id *big.Int + AtBlockHeight uint64 + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*IAutomationRegistryMasterUpkeepCanceledIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepCanceledIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepCanceled", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepCanceled) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepCanceled", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepCanceled(log types.Log) (*IAutomationRegistryMasterUpkeepCanceled, error) { + event := new(IAutomationRegistryMasterUpkeepCanceled) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepCanceled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepCheckDataSetIterator struct { + Event *IAutomationRegistryMasterUpkeepCheckDataSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepCheckDataSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepCheckDataSet) + 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(IAutomationRegistryMasterUpkeepCheckDataSet) + 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 *IAutomationRegistryMasterUpkeepCheckDataSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepCheckDataSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepCheckDataSet struct { + Id *big.Int + NewCheckData []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepCheckDataSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepCheckDataSetIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepCheckDataSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepCheckDataSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepCheckDataSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepCheckDataSet(log types.Log) (*IAutomationRegistryMasterUpkeepCheckDataSet, error) { + event := new(IAutomationRegistryMasterUpkeepCheckDataSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepCheckDataSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepGasLimitSetIterator struct { + Event *IAutomationRegistryMasterUpkeepGasLimitSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepGasLimitSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepGasLimitSet) + 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(IAutomationRegistryMasterUpkeepGasLimitSet) + 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 *IAutomationRegistryMasterUpkeepGasLimitSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepGasLimitSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepGasLimitSet struct { + Id *big.Int + GasLimit *big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepGasLimitSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepGasLimitSetIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepGasLimitSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepGasLimitSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepGasLimitSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepGasLimitSet(log types.Log) (*IAutomationRegistryMasterUpkeepGasLimitSet, error) { + event := new(IAutomationRegistryMasterUpkeepGasLimitSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepGasLimitSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepMigratedIterator struct { + Event *IAutomationRegistryMasterUpkeepMigrated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepMigratedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepMigrated) + 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(IAutomationRegistryMasterUpkeepMigrated) + 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 *IAutomationRegistryMasterUpkeepMigratedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepMigratedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepMigrated struct { + Id *big.Int + RemainingBalance *big.Int + Destination common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepMigratedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepMigratedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepMigrated", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepMigrated, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepMigrated) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepMigrated", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepMigrated(log types.Log) (*IAutomationRegistryMasterUpkeepMigrated, error) { + event := new(IAutomationRegistryMasterUpkeepMigrated) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepMigrated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepOffchainConfigSetIterator struct { + Event *IAutomationRegistryMasterUpkeepOffchainConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepOffchainConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepOffchainConfigSet) + 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(IAutomationRegistryMasterUpkeepOffchainConfigSet) + 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 *IAutomationRegistryMasterUpkeepOffchainConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepOffchainConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepOffchainConfigSet struct { + Id *big.Int + OffchainConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepOffchainConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepOffchainConfigSetIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepOffchainConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepOffchainConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepOffchainConfigSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepOffchainConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepOffchainConfigSet, error) { + event := new(IAutomationRegistryMasterUpkeepOffchainConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepOffchainConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepPausedIterator struct { + Event *IAutomationRegistryMasterUpkeepPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepPaused) + 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(IAutomationRegistryMasterUpkeepPaused) + 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 *IAutomationRegistryMasterUpkeepPausedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepPaused struct { + Id *big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepPausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepPausedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepPaused", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepPaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPaused", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepPaused(log types.Log) (*IAutomationRegistryMasterUpkeepPaused, error) { + event := new(IAutomationRegistryMasterUpkeepPaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepPerformedIterator struct { + Event *IAutomationRegistryMasterUpkeepPerformed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepPerformedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepPerformed) + 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(IAutomationRegistryMasterUpkeepPerformed) + 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 *IAutomationRegistryMasterUpkeepPerformedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepPerformedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepPerformed struct { + Id *big.Int + Success bool + TotalPayment *big.Int + GasUsed *big.Int + GasOverhead *big.Int + Trigger []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*IAutomationRegistryMasterUpkeepPerformedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepPerformedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepPerformed", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepPerformed) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPerformed", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepPerformed(log types.Log) (*IAutomationRegistryMasterUpkeepPerformed, error) { + event := new(IAutomationRegistryMasterUpkeepPerformed) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPerformed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator struct { + Event *IAutomationRegistryMasterUpkeepPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepPrivilegeConfigSet) + 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(IAutomationRegistryMasterUpkeepPrivilegeConfigSet) + 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 *IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepPrivilegeConfigSet struct { + Id *big.Int + PrivilegeConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepPrivilegeConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepPrivilegeConfigSet, error) { + event := new(IAutomationRegistryMasterUpkeepPrivilegeConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepReceivedIterator struct { + Event *IAutomationRegistryMasterUpkeepReceived + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepReceivedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepReceived) + 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(IAutomationRegistryMasterUpkeepReceived) + 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 *IAutomationRegistryMasterUpkeepReceivedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepReceivedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepReceived struct { + Id *big.Int + StartingBalance *big.Int + ImportedFrom common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepReceivedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepReceivedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepReceived", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepReceived, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepReceived) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepReceived", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepReceived(log types.Log) (*IAutomationRegistryMasterUpkeepReceived, error) { + event := new(IAutomationRegistryMasterUpkeepReceived) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepReceived", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepRegisteredIterator struct { + Event *IAutomationRegistryMasterUpkeepRegistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepRegisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepRegistered) + 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(IAutomationRegistryMasterUpkeepRegistered) + 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 *IAutomationRegistryMasterUpkeepRegisteredIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepRegistered struct { + Id *big.Int + PerformGas uint32 + Admin common.Address + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepRegisteredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepRegisteredIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepRegistered", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepRegistered, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepRegistered) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepRegistered", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepRegistered(log types.Log) (*IAutomationRegistryMasterUpkeepRegistered, error) { + event := new(IAutomationRegistryMasterUpkeepRegistered) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepTriggerConfigSetIterator struct { + Event *IAutomationRegistryMasterUpkeepTriggerConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepTriggerConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepTriggerConfigSet) + 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(IAutomationRegistryMasterUpkeepTriggerConfigSet) + 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 *IAutomationRegistryMasterUpkeepTriggerConfigSetIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepTriggerConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepTriggerConfigSet struct { + Id *big.Int + TriggerConfig []byte + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepTriggerConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepTriggerConfigSetIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepTriggerConfigSet", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepTriggerConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepTriggerConfigSet", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepTriggerConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepTriggerConfigSet, error) { + event := new(IAutomationRegistryMasterUpkeepTriggerConfigSet) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepTriggerConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type IAutomationRegistryMasterUpkeepUnpausedIterator struct { + Event *IAutomationRegistryMasterUpkeepUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *IAutomationRegistryMasterUpkeepUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(IAutomationRegistryMasterUpkeepUnpaused) + 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(IAutomationRegistryMasterUpkeepUnpaused) + 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 *IAutomationRegistryMasterUpkeepUnpausedIterator) Error() error { + return it.fail +} + +func (it *IAutomationRegistryMasterUpkeepUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type IAutomationRegistryMasterUpkeepUnpaused struct { + Id *big.Int + Raw types.Log +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepUnpausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.FilterLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return &IAutomationRegistryMasterUpkeepUnpausedIterator{contract: _IAutomationRegistryMaster.contract, event: "UpkeepUnpaused", logs: logs, sub: sub}, nil +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepUnpaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _IAutomationRegistryMaster.contract.WatchLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(IAutomationRegistryMasterUpkeepUnpaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepUnpaused", 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 (_IAutomationRegistryMaster *IAutomationRegistryMasterFilterer) ParseUpkeepUnpaused(log types.Log) (*IAutomationRegistryMasterUpkeepUnpaused, error) { + event := new(IAutomationRegistryMasterUpkeepUnpaused) + if err := _IAutomationRegistryMaster.contract.UnpackLog(event, "UpkeepUnpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type CheckCallback struct { + UpkeepNeeded bool + PerformData []byte + UpkeepFailureReason uint8 + GasUsed *big.Int +} +type CheckUpkeep struct { + UpkeepNeeded bool + PerformData []byte + UpkeepFailureReason uint8 + GasUsed *big.Int + GasLimit *big.Int + FastGasWei *big.Int + LinkNative *big.Int +} +type CheckUpkeep0 struct { + UpkeepNeeded bool + PerformData []byte + UpkeepFailureReason uint8 + GasUsed *big.Int + GasLimit *big.Int + FastGasWei *big.Int + LinkNative *big.Int +} +type GetSignerInfo struct { + Active bool + Index uint8 +} +type GetState struct { + State AutomationRegistryBase22State + Config AutomationRegistryBase22OnchainConfig + Signers []common.Address + Transmitters []common.Address + F uint8 +} +type GetTransmitterInfo struct { + Active bool + Index uint8 + Balance *big.Int + LastCollected *big.Int + Payee common.Address +} +type LatestConfigDetails struct { + ConfigCount uint32 + BlockNumber uint32 + ConfigDigest [32]byte +} +type LatestConfigDigestAndEpoch struct { + ScanLogs bool + ConfigDigest [32]byte + Epoch uint32 +} +type SimulatePerformUpkeep struct { + Success bool + GasUsed *big.Int +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMaster) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _IAutomationRegistryMaster.abi.Events["AdminPrivilegeConfigSet"].ID: + return _IAutomationRegistryMaster.ParseAdminPrivilegeConfigSet(log) + case _IAutomationRegistryMaster.abi.Events["CancelledUpkeepReport"].ID: + return _IAutomationRegistryMaster.ParseCancelledUpkeepReport(log) + case _IAutomationRegistryMaster.abi.Events["ConfigSet"].ID: + return _IAutomationRegistryMaster.ParseConfigSet(log) + case _IAutomationRegistryMaster.abi.Events["DedupKeyAdded"].ID: + return _IAutomationRegistryMaster.ParseDedupKeyAdded(log) + case _IAutomationRegistryMaster.abi.Events["FundsAdded"].ID: + return _IAutomationRegistryMaster.ParseFundsAdded(log) + case _IAutomationRegistryMaster.abi.Events["FundsWithdrawn"].ID: + return _IAutomationRegistryMaster.ParseFundsWithdrawn(log) + case _IAutomationRegistryMaster.abi.Events["InsufficientFundsUpkeepReport"].ID: + return _IAutomationRegistryMaster.ParseInsufficientFundsUpkeepReport(log) + case _IAutomationRegistryMaster.abi.Events["OwnerFundsWithdrawn"].ID: + return _IAutomationRegistryMaster.ParseOwnerFundsWithdrawn(log) + case _IAutomationRegistryMaster.abi.Events["OwnershipTransferRequested"].ID: + return _IAutomationRegistryMaster.ParseOwnershipTransferRequested(log) + case _IAutomationRegistryMaster.abi.Events["OwnershipTransferred"].ID: + return _IAutomationRegistryMaster.ParseOwnershipTransferred(log) + case _IAutomationRegistryMaster.abi.Events["Paused"].ID: + return _IAutomationRegistryMaster.ParsePaused(log) + case _IAutomationRegistryMaster.abi.Events["PayeesUpdated"].ID: + return _IAutomationRegistryMaster.ParsePayeesUpdated(log) + case _IAutomationRegistryMaster.abi.Events["PayeeshipTransferRequested"].ID: + return _IAutomationRegistryMaster.ParsePayeeshipTransferRequested(log) + case _IAutomationRegistryMaster.abi.Events["PayeeshipTransferred"].ID: + return _IAutomationRegistryMaster.ParsePayeeshipTransferred(log) + case _IAutomationRegistryMaster.abi.Events["PaymentWithdrawn"].ID: + return _IAutomationRegistryMaster.ParsePaymentWithdrawn(log) + case _IAutomationRegistryMaster.abi.Events["ReorgedUpkeepReport"].ID: + return _IAutomationRegistryMaster.ParseReorgedUpkeepReport(log) + case _IAutomationRegistryMaster.abi.Events["StaleUpkeepReport"].ID: + return _IAutomationRegistryMaster.ParseStaleUpkeepReport(log) + case _IAutomationRegistryMaster.abi.Events["Transmitted"].ID: + return _IAutomationRegistryMaster.ParseTransmitted(log) + case _IAutomationRegistryMaster.abi.Events["Unpaused"].ID: + return _IAutomationRegistryMaster.ParseUnpaused(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepAdminTransferRequested"].ID: + return _IAutomationRegistryMaster.ParseUpkeepAdminTransferRequested(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepAdminTransferred"].ID: + return _IAutomationRegistryMaster.ParseUpkeepAdminTransferred(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepCanceled"].ID: + return _IAutomationRegistryMaster.ParseUpkeepCanceled(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepCheckDataSet"].ID: + return _IAutomationRegistryMaster.ParseUpkeepCheckDataSet(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepGasLimitSet"].ID: + return _IAutomationRegistryMaster.ParseUpkeepGasLimitSet(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepMigrated"].ID: + return _IAutomationRegistryMaster.ParseUpkeepMigrated(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepOffchainConfigSet"].ID: + return _IAutomationRegistryMaster.ParseUpkeepOffchainConfigSet(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepPaused"].ID: + return _IAutomationRegistryMaster.ParseUpkeepPaused(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepPerformed"].ID: + return _IAutomationRegistryMaster.ParseUpkeepPerformed(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepPrivilegeConfigSet"].ID: + return _IAutomationRegistryMaster.ParseUpkeepPrivilegeConfigSet(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepReceived"].ID: + return _IAutomationRegistryMaster.ParseUpkeepReceived(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepRegistered"].ID: + return _IAutomationRegistryMaster.ParseUpkeepRegistered(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepTriggerConfigSet"].ID: + return _IAutomationRegistryMaster.ParseUpkeepTriggerConfigSet(log) + case _IAutomationRegistryMaster.abi.Events["UpkeepUnpaused"].ID: + return _IAutomationRegistryMaster.ParseUpkeepUnpaused(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (IAutomationRegistryMasterAdminPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") +} + +func (IAutomationRegistryMasterCancelledUpkeepReport) Topic() common.Hash { + return common.HexToHash("0xc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636") +} + +func (IAutomationRegistryMasterConfigSet) Topic() common.Hash { + return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05") +} + +func (IAutomationRegistryMasterDedupKeyAdded) Topic() common.Hash { + return common.HexToHash("0xa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f2") +} + +func (IAutomationRegistryMasterFundsAdded) Topic() common.Hash { + return common.HexToHash("0xafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203") +} + +func (IAutomationRegistryMasterFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0xf3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318") +} + +func (IAutomationRegistryMasterInsufficientFundsUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") +} + +func (IAutomationRegistryMasterOwnerFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0x1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f1") +} + +func (IAutomationRegistryMasterOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (IAutomationRegistryMasterOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (IAutomationRegistryMasterPaused) Topic() common.Hash { + return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258") +} + +func (IAutomationRegistryMasterPayeesUpdated) Topic() common.Hash { + return common.HexToHash("0xa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725") +} + +func (IAutomationRegistryMasterPayeeshipTransferRequested) Topic() common.Hash { + return common.HexToHash("0x84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e38367") +} + +func (IAutomationRegistryMasterPayeeshipTransferred) Topic() common.Hash { + return common.HexToHash("0x78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b3") +} + +func (IAutomationRegistryMasterPaymentWithdrawn) Topic() common.Hash { + return common.HexToHash("0x9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698") +} + +func (IAutomationRegistryMasterReorgedUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301") +} + +func (IAutomationRegistryMasterStaleUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8") +} + +func (IAutomationRegistryMasterTransmitted) Topic() common.Hash { + return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62") +} + +func (IAutomationRegistryMasterUnpaused) Topic() common.Hash { + return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa") +} + +func (IAutomationRegistryMasterUpkeepAdminTransferRequested) Topic() common.Hash { + return common.HexToHash("0xb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b35") +} + +func (IAutomationRegistryMasterUpkeepAdminTransferred) Topic() common.Hash { + return common.HexToHash("0x5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c") +} + +func (IAutomationRegistryMasterUpkeepCanceled) Topic() common.Hash { + return common.HexToHash("0x91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f791181") +} + +func (IAutomationRegistryMasterUpkeepCheckDataSet) Topic() common.Hash { + return common.HexToHash("0xcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d") +} + +func (IAutomationRegistryMasterUpkeepGasLimitSet) Topic() common.Hash { + return common.HexToHash("0xc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c") +} + +func (IAutomationRegistryMasterUpkeepMigrated) Topic() common.Hash { + return common.HexToHash("0xb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff") +} + +func (IAutomationRegistryMasterUpkeepOffchainConfigSet) Topic() common.Hash { + return common.HexToHash("0x3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850") +} + +func (IAutomationRegistryMasterUpkeepPaused) Topic() common.Hash { + return common.HexToHash("0x8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f") +} + +func (IAutomationRegistryMasterUpkeepPerformed) Topic() common.Hash { + return common.HexToHash("0xad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b") +} + +func (IAutomationRegistryMasterUpkeepPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae7769") +} + +func (IAutomationRegistryMasterUpkeepReceived) Topic() common.Hash { + return common.HexToHash("0x74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71") +} + +func (IAutomationRegistryMasterUpkeepRegistered) Topic() common.Hash { + return common.HexToHash("0xbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d012") +} + +func (IAutomationRegistryMasterUpkeepTriggerConfigSet) Topic() common.Hash { + return common.HexToHash("0x2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664") +} + +func (IAutomationRegistryMasterUpkeepUnpaused) Topic() common.Hash { + return common.HexToHash("0x7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a47456") +} + +func (_IAutomationRegistryMaster *IAutomationRegistryMaster) Address() common.Address { + return _IAutomationRegistryMaster.address +} + +type IAutomationRegistryMasterInterface interface { + CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (CheckCallback, + + error) + + CheckUpkeep(opts *bind.CallOpts, id *big.Int, triggerData []byte) (CheckUpkeep, + + error) + + CheckUpkeep0(opts *bind.CallOpts, id *big.Int) (CheckUpkeep0, + + error) + + FallbackTo(opts *bind.CallOpts) (common.Address, error) + + GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) + + GetAdminPrivilegeConfig(opts *bind.CallOpts, admin common.Address) ([]byte, error) + + GetAutomationForwarderLogic(opts *bind.CallOpts) (common.Address, error) + + GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetCancellationDelay(opts *bind.CallOpts) (*big.Int, error) + + GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) + + GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) + + GetLinkAddress(opts *bind.CallOpts) (common.Address, error) + + GetLinkNativeFeedAddress(opts *bind.CallOpts) (common.Address, error) + + GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) + + GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetMinBalanceForUpkeep(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetMode(opts *bind.CallOpts) (uint8, error) + + GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) + + GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetPerSignerGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, + + error) + + GetState(opts *bind.CallOpts) (GetState, + + error) + + GetTransmitterInfo(opts *bind.CallOpts, query common.Address) (GetTransmitterInfo, + + error) + + GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) + + GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) + + GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + + GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + + HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) + + LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, + + error) + + LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, + + error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + SimulatePerformUpkeep(opts *bind.CallOpts, id *big.Int, performData []byte) (SimulatePerformUpkeep, + + error) + + TypeAndVersion(opts *bind.CallOpts) (string, error) + + UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) + + UpkeepVersion(opts *bind.CallOpts) (uint8, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) + + AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) + + CancelUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) + + MigrateUpkeeps(opts *bind.TransactOpts, ids []*big.Int, destination common.Address) (*types.Transaction, error) + + OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) + + Pause(opts *bind.TransactOpts) (*types.Transaction, error) + + PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + ReceiveUpkeeps(opts *bind.TransactOpts, encodedUpkeeps []byte) (*types.Transaction, error) + + RecoverFunds(opts *bind.TransactOpts) (*types.Transaction, error) + + RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) + + RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) + + SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) + + SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) + + SetConfigTypeSafe(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) + + SetPayees(opts *bind.TransactOpts, payees []common.Address) (*types.Transaction, error) + + SetPeerRegistryMigrationPermission(opts *bind.TransactOpts, peer common.Address, permission uint8) (*types.Transaction, error) + + SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) + + SetUpkeepGasLimit(opts *bind.TransactOpts, id *big.Int, gasLimit uint32) (*types.Transaction, error) + + SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) + + SetUpkeepPrivilegeConfig(opts *bind.TransactOpts, upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) + + SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) + + TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) + + Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) + + Unpause(opts *bind.TransactOpts) (*types.Transaction, error) + + UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) + + WithdrawOwnerFunds(opts *bind.TransactOpts) (*types.Transaction, error) + + WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) + + Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) + + FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*IAutomationRegistryMasterAdminPrivilegeConfigSetIterator, error) + + WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) + + ParseAdminPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMasterAdminPrivilegeConfigSet, error) + + FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterCancelledUpkeepReportIterator, error) + + WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseCancelledUpkeepReport(log types.Log) (*IAutomationRegistryMasterCancelledUpkeepReport, error) + + FilterConfigSet(opts *bind.FilterOpts) (*IAutomationRegistryMasterConfigSetIterator, error) + + WatchConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterConfigSet) (event.Subscription, error) + + ParseConfigSet(log types.Log) (*IAutomationRegistryMasterConfigSet, error) + + FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*IAutomationRegistryMasterDedupKeyAddedIterator, error) + + WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) + + ParseDedupKeyAdded(log types.Log) (*IAutomationRegistryMasterDedupKeyAdded, error) + + FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*IAutomationRegistryMasterFundsAddedIterator, error) + + WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) + + ParseFundsAdded(log types.Log) (*IAutomationRegistryMasterFundsAdded, error) + + FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterFundsWithdrawnIterator, error) + + WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterFundsWithdrawn, id []*big.Int) (event.Subscription, error) + + ParseFundsWithdrawn(log types.Log) (*IAutomationRegistryMasterFundsWithdrawn, error) + + FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterInsufficientFundsUpkeepReportIterator, error) + + WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseInsufficientFundsUpkeepReport(log types.Log) (*IAutomationRegistryMasterInsufficientFundsUpkeepReport, error) + + FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*IAutomationRegistryMasterOwnerFundsWithdrawnIterator, error) + + WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnerFundsWithdrawn) (event.Subscription, error) + + ParseOwnerFundsWithdrawn(log types.Log) (*IAutomationRegistryMasterOwnerFundsWithdrawn, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IAutomationRegistryMasterOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*IAutomationRegistryMasterOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*IAutomationRegistryMasterOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*IAutomationRegistryMasterOwnershipTransferred, error) + + FilterPaused(opts *bind.FilterOpts) (*IAutomationRegistryMasterPausedIterator, error) + + WatchPaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPaused) (event.Subscription, error) + + ParsePaused(log types.Log) (*IAutomationRegistryMasterPaused, error) + + FilterPayeesUpdated(opts *bind.FilterOpts) (*IAutomationRegistryMasterPayeesUpdatedIterator, error) + + WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeesUpdated) (event.Subscription, error) + + ParsePayeesUpdated(log types.Log) (*IAutomationRegistryMasterPayeesUpdated, error) + + FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*IAutomationRegistryMasterPayeeshipTransferRequestedIterator, error) + + WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferRequested(log types.Log) (*IAutomationRegistryMasterPayeeshipTransferRequested, error) + + FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*IAutomationRegistryMasterPayeeshipTransferredIterator, error) + + WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferred(log types.Log) (*IAutomationRegistryMasterPayeeshipTransferred, error) + + FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*IAutomationRegistryMasterPaymentWithdrawnIterator, error) + + WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) + + ParsePaymentWithdrawn(log types.Log) (*IAutomationRegistryMasterPaymentWithdrawn, error) + + FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterReorgedUpkeepReportIterator, error) + + WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseReorgedUpkeepReport(log types.Log) (*IAutomationRegistryMasterReorgedUpkeepReport, error) + + FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterStaleUpkeepReportIterator, error) + + WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterStaleUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseStaleUpkeepReport(log types.Log) (*IAutomationRegistryMasterStaleUpkeepReport, error) + + FilterTransmitted(opts *bind.FilterOpts) (*IAutomationRegistryMasterTransmittedIterator, error) + + WatchTransmitted(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterTransmitted) (event.Subscription, error) + + ParseTransmitted(log types.Log) (*IAutomationRegistryMasterTransmitted, error) + + FilterUnpaused(opts *bind.FilterOpts) (*IAutomationRegistryMasterUnpausedIterator, error) + + WatchUnpaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUnpaused) (event.Subscription, error) + + ParseUnpaused(log types.Log) (*IAutomationRegistryMasterUnpaused, error) + + FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*IAutomationRegistryMasterUpkeepAdminTransferRequestedIterator, error) + + WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferRequested(log types.Log) (*IAutomationRegistryMasterUpkeepAdminTransferRequested, error) + + FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*IAutomationRegistryMasterUpkeepAdminTransferredIterator, error) + + WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferred(log types.Log) (*IAutomationRegistryMasterUpkeepAdminTransferred, error) + + FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*IAutomationRegistryMasterUpkeepCanceledIterator, error) + + WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) + + ParseUpkeepCanceled(log types.Log) (*IAutomationRegistryMasterUpkeepCanceled, error) + + FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepCheckDataSetIterator, error) + + WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepCheckDataSet(log types.Log) (*IAutomationRegistryMasterUpkeepCheckDataSet, error) + + FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepGasLimitSetIterator, error) + + WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepGasLimitSet(log types.Log) (*IAutomationRegistryMasterUpkeepGasLimitSet, error) + + FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepMigratedIterator, error) + + WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepMigrated, id []*big.Int) (event.Subscription, error) + + ParseUpkeepMigrated(log types.Log) (*IAutomationRegistryMasterUpkeepMigrated, error) + + FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepOffchainConfigSetIterator, error) + + WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepOffchainConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepOffchainConfigSet, error) + + FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepPausedIterator, error) + + WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPaused(log types.Log) (*IAutomationRegistryMasterUpkeepPaused, error) + + FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*IAutomationRegistryMasterUpkeepPerformedIterator, error) + + WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) + + ParseUpkeepPerformed(log types.Log) (*IAutomationRegistryMasterUpkeepPerformed, error) + + FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepPrivilegeConfigSetIterator, error) + + WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPrivilegeConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepPrivilegeConfigSet, error) + + FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepReceivedIterator, error) + + WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepReceived, id []*big.Int) (event.Subscription, error) + + ParseUpkeepReceived(log types.Log) (*IAutomationRegistryMasterUpkeepReceived, error) + + FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepRegisteredIterator, error) + + WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepRegistered, id []*big.Int) (event.Subscription, error) + + ParseUpkeepRegistered(log types.Log) (*IAutomationRegistryMasterUpkeepRegistered, error) + + FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepTriggerConfigSetIterator, error) + + WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepTriggerConfigSet(log types.Log) (*IAutomationRegistryMasterUpkeepTriggerConfigSet, error) + + FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*IAutomationRegistryMasterUpkeepUnpausedIterator, error) + + WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *IAutomationRegistryMasterUpkeepUnpaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepUnpaused(log types.Log) (*IAutomationRegistryMasterUpkeepUnpaused, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_2/keeper_registry_logic_a_wrapper_2_2.go b/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_2/keeper_registry_logic_a_wrapper_2_2.go new file mode 100644 index 00000000000..064fc2eeca9 --- /dev/null +++ b/core/gethwrappers/generated/keeper_registry_logic_a_wrapper_2_2/keeper_registry_logic_a_wrapper_2_2.go @@ -0,0 +1,4863 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package keeper_registry_logic_a_wrapper_2_2 + +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 +) + +var AutomationRegistryLogicAMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_2\",\"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\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"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\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"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\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"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\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"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\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"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\":\"nonpayable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"addFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"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\":\"enumAutomationRegistryBase2_2.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_2.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\":\"linkNative\",\"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_2.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\":\"linkNative\",\"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_2.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\":[{\"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_2.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"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\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"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\"},{\"internalType\":\"bytes\",\"name\":\"triggerConfig\",\"type\":\"bytes\"}],\"name\":\"setUpkeepTriggerConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x6101406040523480156200001257600080fd5b50604051620061fd380380620061fd8339810160408190526200003591620003df565b80816001600160a01b0316634b4fd03b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000406565b826001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003df565b836001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003df565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003df565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003df565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b9816200031b565b505050846002811115620002d157620002d162000429565b60e0816002811115620002e857620002e862000429565b9052506001600160a01b0393841660805291831660a052821660c0528116610100529190911661012052506200043f9050565b336001600160a01b03821603620003755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003dc57600080fd5b50565b600060208284031215620003f257600080fd5b8151620003ff81620003c6565b9392505050565b6000602082840312156200041957600080fd5b815160038110620003ff57600080fd5b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e0516101005161012051615d44620004b96000396000818161010e01526101a90152600081816103e10152611fbd01526000818161356301528181613799015281816139e10152613b890152600061310d015260006131f1015260008181611dff01526123cb0152615d446000f3fe60806040523480156200001157600080fd5b50600436106200010c5760003560e01c806385c1b0ba11620000a5578063c8048022116200006f578063c804802214620002b7578063ce7dc5b414620002ce578063f2fde38b14620002e5578063f7d334ba14620002fc576200010c565b806385c1b0ba14620002535780638da5cb5b146200026a5780638e86139b1462000289578063948108f714620002a0576200010c565b80634ee88d3511620000e75780634ee88d3514620001ef5780636ded9eae146200020657806371791aa0146200021d57806379ba50971462000249576200010c565b806328f32f38146200015457806329c5efad146200017e578063349e8cca14620001a7575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e8080156200014d573d6000f35b3d6000fd5b005b6200016b6200016536600462004216565b62000313565b6040519081526020015b60405180910390f35b620001956200018f366004620042fc565b6200068d565b60405162000175949392919062004424565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200162000175565b620001526200020036600462004461565b62000931565b6200016b62000217366004620044b1565b62000999565b620002346200022e366004620042fc565b620009ff565b60405162000175979695949392919062004564565b620001526200110c565b6200015262000264366004620045b6565b6200120f565b60005473ffffffffffffffffffffffffffffffffffffffff16620001c9565b620001526200029a36600462004643565b62001e80565b62000152620002b1366004620046a6565b62002208565b62000152620002c8366004620046d5565b6200249b565b62000195620002df366004620047ab565b62002862565b62000152620002f636600462004822565b62002932565b620002346200030d366004620046d5565b6200294a565b6000805473ffffffffffffffffffffffffffffffffffffffff1633148015906200034757506200034560093362002988565b155b156200037f576040517fd48b678b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff89163b620003ce576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b620003d986620029bc565b9050600089307f00000000000000000000000000000000000000000000000000000000000000006040516200040e9062003fa7565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562000458573d6000803e3d6000fd5b5090506200051f826040518060e001604052806000151581526020018c63ffffffff16815260200163ffffffff801681526020018473ffffffffffffffffffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff16815260200160006bffffffffffffffffffffffff168152602001600063ffffffff168152508a89898080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508b92508a915062002b609050565b6015805474010000000000000000000000000000000000000000900463ffffffff169060146200054f8362004871565b91906101000a81548163ffffffff021916908363ffffffff16021790555050817fbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d0128a8a604051620005c892919063ffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a2817fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d878760405162000604929190620048e0565b60405180910390a2817f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664856040516200063e9190620048f6565b60405180910390a2817f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf485084604051620006789190620048f6565b60405180910390a25098975050505050505050565b600060606000806200069e62002f4b565b600086815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff90811694830194909452650100000000008104841694820194909452690100000000000000000090930473ffffffffffffffffffffffffffffffffffffffff166060840152600101546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a0840152780100000000000000000000000000000000000000000000000090041660c08201525a9150600080826060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620007b8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007de919062004918565b73ffffffffffffffffffffffffffffffffffffffff166014600101600c9054906101000a900463ffffffff1663ffffffff168960405162000820919062004938565b60006040518083038160008787f1925050503d806000811462000860576040519150601f19603f3d011682016040523d82523d6000602084013e62000865565b606091505b50915091505a62000877908562004956565b935081620008a257600060405180602001604052806000815250600796509650965050505062000928565b80806020019051810190620008b89190620049c7565b909750955086620008e657600060405180602001604052806000815250600496509650965050505062000928565b601654865164010000000090910463ffffffff1610156200092457600060405180602001604052806000815250600596509650965050505062000928565b5050505b92959194509250565b6200093c8362002f86565b6000838152601b602052604090206200095782848362004abc565b50827f2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d566483836040516200098c929190620048e0565b60405180910390a2505050565b6000620009f388888860008989604051806020016040528060008152508a8a8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506200031392505050565b98975050505050505050565b60006060600080600080600062000a1562002f4b565b600062000a228a6200303c565b905060006012604051806101400160405290816000820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160008201600c9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160109054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160149054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160189054906101000a900462ffffff1662ffffff1662ffffff16815260200160008201601b9054906101000a900461ffff1661ffff1661ffff16815260200160008201601d9054906101000a900460ff1660ff1660ff16815260200160008201601e9054906101000a900460ff1615151515815260200160008201601f9054906101000a900460ff161515151581526020016001820160009054906101000a900460ff16151515158152505090506000600460008d81526020019081526020016000206040518060e00160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160059054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160099054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016001820160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff16815260200160018201600c9054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff166bffffffffffffffffffffffff1681526020016001820160189054906101000a900463ffffffff1663ffffffff1663ffffffff168152505090508160e001511562000d61576000604051806020016040528060008152506009600084602001516000808263ffffffff169250995099509950995099509950995050505062001100565b604081015163ffffffff9081161462000db2576000604051806020016040528060008152506001600084602001516000808263ffffffff169250995099509950995099509950995050505062001100565b80511562000df8576000604051806020016040528060008152506002600084602001516000808263ffffffff169250995099509950995099509950995050505062001100565b62000e0382620030ea565b602083015160165492975090955060009162000e35918591879190640100000000900463ffffffff168a8a87620032dc565b9050806bffffffffffffffffffffffff168260a001516bffffffffffffffffffffffff16101562000e9f576000604051806020016040528060008152506006600085602001516000808263ffffffff1692509a509a509a509a509a509a509a505050505062001100565b600062000eae8e868f6200332d565b90505a9850600080846060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000f06573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f2c919062004918565b73ffffffffffffffffffffffffffffffffffffffff166014600101600c9054906101000a900463ffffffff1663ffffffff168460405162000f6e919062004938565b60006040518083038160008787f1925050503d806000811462000fae576040519150601f19603f3d011682016040523d82523d6000602084013e62000fb3565b606091505b50915091505a62000fc5908c62004956565b9a5081620010455760165481516801000000000000000090910463ffffffff1610156200102257505060408051602080820190925260008082529490910151939c509a50600899505063ffffffff90911695506200110092505050565b602090940151939b5060039a505063ffffffff9092169650620011009350505050565b808060200190518101906200105b9190620049c7565b909e509c508d6200109c57505060408051602080820190925260008082529490910151939c509a50600499505063ffffffff90911695506200110092505050565b6016548d5164010000000090910463ffffffff161015620010ed57505060408051602080820190925260008082529490910151939c509a50600599505063ffffffff90911695506200110092505050565b505050506020015163ffffffff16945050505b92959891949750929550565b60015473ffffffffffffffffffffffffffffffffffffffff16331462001193576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600173ffffffffffffffffffffffffffffffffffffffff82166000908152601a602052604090205460ff1660038111156200124e576200124e620043b9565b141580156200129a5750600373ffffffffffffffffffffffffffffffffffffffff82166000908152601a602052604090205460ff166003811115620012975762001297620043b9565b14155b15620012d2576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6014546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1662001332576040517fd12d7d8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008290036200136e576040517f2c2fc94100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081018290526000808567ffffffffffffffff811115620013c557620013c56200409d565b604051908082528060200260200182016040528015620013ef578160200160208202803683370190505b50905060008667ffffffffffffffff8111156200141057620014106200409d565b6040519080825280602002602001820160405280156200149757816020015b6040805160e08101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816200142f5790505b50905060008767ffffffffffffffff811115620014b857620014b86200409d565b604051908082528060200260200182016040528015620014ed57816020015b6060815260200190600190039081620014d75790505b50905060008867ffffffffffffffff8111156200150e576200150e6200409d565b6040519080825280602002602001820160405280156200154357816020015b60608152602001906001900390816200152d5790505b50905060008967ffffffffffffffff8111156200156457620015646200409d565b6040519080825280602002602001820160405280156200159957816020015b6060815260200190600190039081620015835790505b50905060005b8a81101562001b7d578b8b82818110620015bd57620015bd62004be4565b60209081029290920135600081815260048452604090819020815160e081018352815460ff811615158252610100810463ffffffff90811697830197909752650100000000008104871693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490931660c08401529a509098506200169c90508962002f86565b60608801516040517f1a5da6c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c8116600483015290911690631a5da6c890602401600060405180830381600087803b1580156200170c57600080fd5b505af115801562001721573d6000803e3d6000fd5b50505050878582815181106200173b576200173b62004be4565b6020026020010181905250600560008a815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff168682815181106200178f576200178f62004be4565b73ffffffffffffffffffffffffffffffffffffffff90921660209283029190910182015260008a81526007909152604090208054620017ce9062004a14565b80601f0160208091040260200160405190810160405280929190818152602001828054620017fc9062004a14565b80156200184d5780601f1062001821576101008083540402835291602001916200184d565b820191906000526020600020905b8154815290600101906020018083116200182f57829003601f168201915b505050505084828151811062001867576200186762004be4565b6020026020010181905250601b60008a81526020019081526020016000208054620018929062004a14565b80601f0160208091040260200160405190810160405280929190818152602001828054620018c09062004a14565b8015620019115780601f10620018e55761010080835404028352916020019162001911565b820191906000526020600020905b815481529060010190602001808311620018f357829003601f168201915b50505050508382815181106200192b576200192b62004be4565b6020026020010181905250601c60008a81526020019081526020016000208054620019569062004a14565b80601f0160208091040260200160405190810160405280929190818152602001828054620019849062004a14565b8015620019d55780601f10620019a957610100808354040283529160200191620019d5565b820191906000526020600020905b815481529060010190602001808311620019b757829003601f168201915b5050505050828281518110620019ef57620019ef62004be4565b60200260200101819052508760a001516bffffffffffffffffffffffff168762001a1a919062004c13565b60008a815260046020908152604080832080547fffffff000000000000000000000000000000000000000000000000000000000016815560010180547fffffffff000000000000000000000000000000000000000000000000000000001690556007909152812091985062001a90919062003fb5565b6000898152601b6020526040812062001aa99162003fb5565b6000898152601c6020526040812062001ac29162003fb5565b600089815260066020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905562001b0360028a6200354f565b5060a0880151604080516bffffffffffffffffffffffff909216825273ffffffffffffffffffffffffffffffffffffffff8c1660208301528a917fb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff910160405180910390a28062001b748162004c29565b9150506200159f565b508560195462001b8e919062004956565b60195560008b8b868167ffffffffffffffff81111562001bb25762001bb26200409d565b60405190808252806020026020018201604052801562001bdc578160200160208202803683370190505b508988888860405160200162001bfa98979695949392919062004dcf565b60405160208183030381529060405290508973ffffffffffffffffffffffffffffffffffffffff16638e86139b6014600001600c9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c71249ab60038e73ffffffffffffffffffffffffffffffffffffffff1663aab9edd66040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001cb6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001cdc919062004e9f565b866040518463ffffffff1660e01b815260040162001cfd9392919062004ec4565b600060405180830381865afa15801562001d1b573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405262001d63919081019062004eeb565b6040518263ffffffff1660e01b815260040162001d819190620048f6565b600060405180830381600087803b15801562001d9c57600080fd5b505af115801562001db1573d6000803e3d6000fd5b50506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d81166004830152602482018b90527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb91506044016020604051808303816000875af115801562001e4b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001e71919062004f24565b50505050505050505050505050565b6002336000908152601a602052604090205460ff16600381111562001ea95762001ea9620043b9565b1415801562001edf57506003336000908152601a602052604090205460ff16600381111562001edc5762001edc620043b9565b14155b1562001f17576040517f0ebeec3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080808080808062001f2d888a018a6200511c565b965096509650965096509650965060005b8751811015620021fc57600073ffffffffffffffffffffffffffffffffffffffff1687828151811062001f755762001f7562004be4565b60200260200101516060015173ffffffffffffffffffffffffffffffffffffffff1603620020895785818151811062001fb25762001fb262004be4565b6020026020010151307f000000000000000000000000000000000000000000000000000000000000000060405162001fea9062003fa7565b73ffffffffffffffffffffffffffffffffffffffff938416815291831660208301529091166040820152606001604051809103906000f08015801562002034573d6000803e3d6000fd5b508782815181106200204a576200204a62004be4565b60200260200101516060019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b62002141888281518110620020a257620020a262004be4565b6020026020010151888381518110620020bf57620020bf62004be4565b6020026020010151878481518110620020dc57620020dc62004be4565b6020026020010151878581518110620020f957620020f962004be4565b602002602001015187868151811062002116576200211662004be4565b602002602001015187878151811062002133576200213362004be4565b602002602001015162002b60565b87818151811062002156576200215662004be4565b60200260200101517f74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a7188838151811062002194576200219462004be4565b602002602001015160a0015133604051620021df9291906bffffffffffffffffffffffff92909216825273ffffffffffffffffffffffffffffffffffffffff16602082015260400190565b60405180910390a280620021f38162004c29565b91505062001f3e565b50505050505050505050565b600082815260046020908152604091829020825160e081018452815460ff81161515825263ffffffff6101008204811694830194909452650100000000008104841694820185905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004821660c0820152911462002306576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818160a001516200231891906200524d565b600084815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff93841602179055601954620023809184169062004c13565b6019556040517f23b872dd0000000000000000000000000000000000000000000000000000000081523360048201523060248201526bffffffffffffffffffffffff831660448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af11580156200242a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002450919062004f24565b506040516bffffffffffffffffffffffff83168152339084907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a3505050565b6000818152600460209081526040808320815160e081018352815460ff81161515825263ffffffff6101008204811695830195909552650100000000008104851693820184905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004831660c082015292911415906200258460005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16149050818015620025df5750808015620025dd5750620025d06200355d565b836040015163ffffffff16115b155b1562002617576040517ffbc0357800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b801580156200264a575060008481526005602052604090205473ffffffffffffffffffffffffffffffffffffffff163314155b1562002682576040517ffbdb8e5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006200268e6200355d565b905081620026a657620026a360328262004c13565b90505b6000858152600460205260409020805463ffffffff80841665010000000000027fffffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffff90921691909117909155620027029060029087906200354f16565b5060145460808501516bffffffffffffffffffffffff91821691600091168211156200276b57608086015162002739908362005275565b90508560a001516bffffffffffffffffffffffff16816bffffffffffffffffffffffff1611156200276b575060a08501515b808660a001516200277d919062005275565b600088815260046020526040902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff166c010000000000000000000000006bffffffffffffffffffffffff93841602179055601554620027e5918391166200524d565b601580547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff9290921691909117905560405167ffffffffffffffff84169088907f91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f79118190600090a350505050505050565b600060606000806200287362002f4b565b6000634b56a42e60e01b88888860405160240162002894939291906200529d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915290506200291f89826200068d565b929c919b50995090975095505050505050565b6200293c62003619565b62002947816200369c565b50565b600060606000806000806000620029718860405180602001604052806000815250620009ff565b959e949d50929b5090995097509550909350915050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415155b90505b92915050565b6000806000620029e36001620029d16200355d565b620029dd919062004956565b62003793565b601554604080516020810193909352309083015274010000000000000000000000000000000000000000900463ffffffff166060820152608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083015201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060045b600f81101562002aef578282828151811062002aab5762002aab62004be4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508062002ae68162004c29565b91505062002a8b565b5083600181111562002b055762002b05620043b9565b60f81b81600f8151811062002b1e5762002b1e62004be4565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535062002b5881620052d1565b949350505050565b6012547e01000000000000000000000000000000000000000000000000000000000000900460ff161562002bc0576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601654835163ffffffff909116101562002c06576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108fc856020015163ffffffff16108062002c445750601554602086015163ffffffff70010000000000000000000000000000000090920482169116115b1562002c7c576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460205260409020546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff161562002ce6576040517f6e3b930b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000868152600460209081526040808320885181548a8501518b85015160608d01517fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009093169315157fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff169390931761010063ffffffff92831602177fffffff000000000000000000000000000000000000000000000000ffffffffff1665010000000000938216939093027fffffff0000000000000000000000000000000000000000ffffffffffffffffff1692909217690100000000000000000073ffffffffffffffffffffffffffffffffffffffff9283160217835560808b01516001909301805460a08d015160c08e01516bffffffffffffffffffffffff9687167fffffffffffffffff000000000000000000000000000000000000000000000000909316929092176c010000000000000000000000009690911695909502949094177fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff1678010000000000000000000000000000000000000000000000009490931693909302919091179091556005835281842080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169189169190911790556007909152902062002ed9848262005314565b508460a001516bffffffffffffffffffffffff1660195462002efc919062004c13565b6019556000868152601b6020526040902062002f19838262005314565b506000868152601c6020526040902062002f34828262005314565b5062002f42600287620038fb565b50505050505050565b321562002f84576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff16331462002fe4576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205465010000000000900463ffffffff9081161462002947576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818160045b600f811015620030d1577fff00000000000000000000000000000000000000000000000000000000000000821683826020811062003085576200308562004be4565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614620030bc57506000949350505050565b80620030c88162004c29565b91505062003043565b5081600f1a600181111562002b585762002b58620043b9565b6000806000836080015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801562003177573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200319d919062005456565b5094509092505050600081131580620031b557508142105b80620031da5750828015620031da5750620031d1824262004956565b8463ffffffff16105b15620031eb576017549550620031ef565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156200325b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003281919062005456565b50945090925050506000811315806200329957508142105b80620032be5750828015620032be5750620032b5824262004956565b8463ffffffff16105b15620032cf576018549450620032d3565b8094505b50505050915091565b600080620032f088878b60c0015162003909565b90506000806200330d8b8a63ffffffff16858a8a60018b620039a8565b90925090506200331e81836200524d565b9b9a5050505050505050505050565b60606000836001811115620033465762003346620043b9565b0362003413576000848152600760205260409081902090517f6e04ff0d00000000000000000000000000000000000000000000000000000000916200338e916024016200554e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152905062003548565b60018360018111156200342a576200342a620043b9565b036200351657600082806020019051810190620034489190620055c5565b6000868152600760205260409081902090519192507f40691db400000000000000000000000000000000000000000000000000000000916200348f918491602401620056d9565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529150620035489050565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9392505050565b6000620029b3838362003e4a565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115620035965762003596620043b9565b036200361457606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620035e9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200360f9190620057a1565b905090565b504390565b60005473ffffffffffffffffffffffffffffffffffffffff16331462002f84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016200118a565b3373ffffffffffffffffffffffffffffffffffffffff8216036200371d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200118a565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115620037cc57620037cc620043b9565b03620038f1576000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562003821573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620038479190620057a1565b9050808310158062003865575061010062003863848362004956565b115b15620038745750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa158015620038cb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620035489190620057a1565b504090565b919050565b6000620029b3838362003f55565b60008080856001811115620039225762003922620043b9565b0362003933575062015f9062003956565b60018560018111156200394a576200394a620043b9565b036200351657506201adb05b6200396963ffffffff85166014620057bb565b62003976846001620057fb565b620039879060ff16611d4c620057bb565b62003993908362004c13565b6200399f919062004c13565b95945050505050565b60008060008960a0015161ffff1687620039c39190620057bb565b9050838015620039d25750803a105b15620039db57503a5b600060027f0000000000000000000000000000000000000000000000000000000000000000600281111562003a145762003a14620043b9565b0362003b8557604080516000815260208101909152851562003a785760003660405180608001604052806048815260200162005cf06048913960405160200162003a619392919062005817565b604051602081830303815290604052905062003ae6565b60165462003a9690640100000000900463ffffffff16600462005840565b63ffffffff1667ffffffffffffffff81111562003ab75762003ab76200409d565b6040519080825280601f01601f19166020018201604052801562003ae2576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e9062003b38908490600401620048f6565b602060405180830381865afa15801562003b56573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003b7c9190620057a1565b91505062003cef565b60017f0000000000000000000000000000000000000000000000000000000000000000600281111562003bbc5762003bbc620043b9565b0362003cef57841562003c4457606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562003c16573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003c3c9190620057a1565b905062003cef565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa15801562003c93573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003cb991906200586f565b505060165492945062003cde93505050640100000000900463ffffffff1682620057bb565b62003ceb906010620057bb565b9150505b8462003d0e57808b60a0015161ffff1662003d0b9190620057bb565b90505b62003d1e61ffff871682620058ba565b90506000878262003d308c8e62004c13565b62003d3c9086620057bb565b62003d48919062004c13565b62003d5c90670de0b6b3a7640000620057bb565b62003d689190620058ba565b905060008c6040015163ffffffff1664e8d4a5100062003d899190620057bb565b898e6020015163ffffffff16858f8862003da49190620057bb565b62003db0919062004c13565b62003dc090633b9aca00620057bb565b62003dcc9190620057bb565b62003dd89190620058ba565b62003de4919062004c13565b90506b033b2e3c9fd0803ce800000062003dff828462004c13565b111562003e38576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b6000818152600183016020526040812054801562003f4357600062003e7160018362004956565b855490915060009062003e879060019062004956565b905081811462003ef357600086600001828154811062003eab5762003eab62004be4565b906000526020600020015490508087600001848154811062003ed15762003ed162004be4565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062003f075762003f07620058f6565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050620029b6565b6000915050620029b6565b5092915050565b600081815260018301602052604081205462003f9e57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620029b6565b506000620029b6565b6103ca806200592683390190565b50805462003fc39062004a14565b6000825580601f1062003fd4575050565b601f0160209004906000526020600020908101906200294791905b8082111562004005576000815560010162003fef565b5090565b73ffffffffffffffffffffffffffffffffffffffff811681146200294757600080fd5b803563ffffffff81168114620038f657600080fd5b803560028110620038f657600080fd5b60008083601f8401126200406457600080fd5b50813567ffffffffffffffff8111156200407d57600080fd5b6020830191508360208285010111156200409657600080fd5b9250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160e0810167ffffffffffffffff81118282101715620040f257620040f26200409d565b60405290565b604051610100810167ffffffffffffffff81118282101715620040f257620040f26200409d565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156200416957620041696200409d565b604052919050565b600067ffffffffffffffff8211156200418e576200418e6200409d565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b600082601f830112620041cc57600080fd5b8135620041e3620041dd8262004171565b6200411f565b818152846020838601011115620041f957600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060008060e0898b0312156200423357600080fd5b8835620042408162004009565b97506200425060208a016200402c565b96506040890135620042628162004009565b95506200427260608a0162004041565b9450608089013567ffffffffffffffff808211156200429057600080fd5b6200429e8c838d0162004051565b909650945060a08b0135915080821115620042b857600080fd5b620042c68c838d01620041ba565b935060c08b0135915080821115620042dd57600080fd5b50620042ec8b828c01620041ba565b9150509295985092959890939650565b600080604083850312156200431057600080fd5b82359150602083013567ffffffffffffffff8111156200432f57600080fd5b6200433d85828601620041ba565b9150509250929050565b60005b83811015620043645781810151838201526020016200434a565b50506000910152565b600081518084526200438781602086016020860162004347565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600a811062004420577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b9052565b84151581526080602082015260006200444160808301866200436d565b9050620044526040830185620043e8565b82606083015295945050505050565b6000806000604084860312156200447757600080fd5b83359250602084013567ffffffffffffffff8111156200449657600080fd5b620044a48682870162004051565b9497909650939450505050565b600080600080600080600060a0888a031215620044cd57600080fd5b8735620044da8162004009565b9650620044ea602089016200402c565b95506040880135620044fc8162004009565b9450606088013567ffffffffffffffff808211156200451a57600080fd5b620045288b838c0162004051565b909650945060808a01359150808211156200454257600080fd5b50620045518a828b0162004051565b989b979a50959850939692959293505050565b871515815260e0602082015260006200458160e08301896200436d565b9050620045926040830188620043e8565b8560608301528460808301528360a08301528260c083015298975050505050505050565b600080600060408486031215620045cc57600080fd5b833567ffffffffffffffff80821115620045e557600080fd5b818601915086601f830112620045fa57600080fd5b8135818111156200460a57600080fd5b8760208260051b85010111156200462057600080fd5b60209283019550935050840135620046388162004009565b809150509250925092565b600080602083850312156200465757600080fd5b823567ffffffffffffffff8111156200466f57600080fd5b6200467d8582860162004051565b90969095509350505050565b80356bffffffffffffffffffffffff81168114620038f657600080fd5b60008060408385031215620046ba57600080fd5b82359150620046cc6020840162004689565b90509250929050565b600060208284031215620046e857600080fd5b5035919050565b600067ffffffffffffffff8211156200470c576200470c6200409d565b5060051b60200190565b600082601f8301126200472857600080fd5b813560206200473b620041dd83620046ef565b82815260059290921b840181019181810190868411156200475b57600080fd5b8286015b84811015620047a057803567ffffffffffffffff811115620047815760008081fd5b620047918986838b0101620041ba565b8452509183019183016200475f565b509695505050505050565b60008060008060608587031215620047c257600080fd5b84359350602085013567ffffffffffffffff80821115620047e257600080fd5b620047f08883890162004716565b945060408701359150808211156200480757600080fd5b50620048168782880162004051565b95989497509550505050565b6000602082840312156200483557600080fd5b8135620035488162004009565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600063ffffffff8083168181036200488d576200488d62004842565b6001019392505050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60208152600062002b5860208301848662004897565b602081526000620029b360208301846200436d565b8051620038f68162004009565b6000602082840312156200492b57600080fd5b8151620035488162004009565b600082516200494c81846020870162004347565b9190910192915050565b81810381811115620029b657620029b662004842565b80151581146200294757600080fd5b600082601f8301126200498d57600080fd5b81516200499e620041dd8262004171565b818152846020838601011115620049b457600080fd5b62002b5882602083016020870162004347565b60008060408385031215620049db57600080fd5b8251620049e8816200496c565b602084015190925067ffffffffffffffff81111562004a0657600080fd5b6200433d858286016200497b565b600181811c9082168062004a2957607f821691505b60208210810362004a63577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111562004ab757600081815260208120601f850160051c8101602086101562004a925750805b601f850160051c820191505b8181101562004ab35782815560010162004a9e565b5050505b505050565b67ffffffffffffffff83111562004ad75762004ad76200409d565b62004aef8362004ae8835462004a14565b8362004a69565b6000601f84116001811462004b44576000851562004b0d5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835562004bdd565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101562004b95578685013582556020948501946001909201910162004b73565b508682101562004bd1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b80820180821115620029b657620029b662004842565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820362004c5d5762004c5d62004842565b5060010190565b600081518084526020808501945080840160005b8381101562004d235781518051151588528381015163ffffffff908116858a01526040808301519091169089015260608082015173ffffffffffffffffffffffffffffffffffffffff16908901526080808201516bffffffffffffffffffffffff169089015260a08082015162004cfe828b01826bffffffffffffffffffffffff169052565b505060c09081015163ffffffff169088015260e0909601959082019060010162004c78565b509495945050505050565b600081518084526020808501945080840160005b8381101562004d2357815173ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010162004d42565b600081518084526020808501808196508360051b8101915082860160005b8581101562004dc257828403895262004daf8483516200436d565b9885019893509084019060010162004d94565b5091979650505050505050565b60e081528760e082015260006101007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a111562004e0c57600080fd5b8960051b808c8386013783018381038201602085015262004e308282018b62004c64565b915050828103604084015262004e47818962004d2e565b9050828103606084015262004e5d818862004d2e565b9050828103608084015262004e73818762004d76565b905082810360a084015262004e89818662004d76565b905082810360c08401526200331e818562004d76565b60006020828403121562004eb257600080fd5b815160ff811681146200354857600080fd5b60ff8416815260ff831660208201526060604082015260006200399f60608301846200436d565b60006020828403121562004efe57600080fd5b815167ffffffffffffffff81111562004f1657600080fd5b62002b58848285016200497b565b60006020828403121562004f3757600080fd5b815162003548816200496c565b600082601f83011262004f5657600080fd5b8135602062004f69620041dd83620046ef565b82815260059290921b8401810191818101908684111562004f8957600080fd5b8286015b84811015620047a0578035835291830191830162004f8d565b600082601f83011262004fb857600080fd5b8135602062004fcb620041dd83620046ef565b82815260e0928302850182019282820191908785111562004feb57600080fd5b8387015b85811015620050a25781818a031215620050095760008081fd5b62005013620040cc565b813562005020816200496c565b81526200502f8287016200402c565b868201526040620050428184016200402c565b90820152606082810135620050578162004009565b9082015260806200506a83820162004689565b9082015260a06200507d83820162004689565b9082015260c0620050908382016200402c565b90820152845292840192810162004fef565b5090979650505050505050565b600082601f830112620050c157600080fd5b81356020620050d4620041dd83620046ef565b82815260059290921b84018101918181019086841115620050f457600080fd5b8286015b84811015620047a05780356200510e8162004009565b8352918301918301620050f8565b600080600080600080600060e0888a0312156200513857600080fd5b873567ffffffffffffffff808211156200515157600080fd5b6200515f8b838c0162004f44565b985060208a01359150808211156200517657600080fd5b620051848b838c0162004fa6565b975060408a01359150808211156200519b57600080fd5b620051a98b838c01620050af565b965060608a0135915080821115620051c057600080fd5b620051ce8b838c01620050af565b955060808a0135915080821115620051e557600080fd5b620051f38b838c0162004716565b945060a08a01359150808211156200520a57600080fd5b620052188b838c0162004716565b935060c08a01359150808211156200522f57600080fd5b506200523e8a828b0162004716565b91505092959891949750929550565b6bffffffffffffffffffffffff81811683821601908082111562003f4e5762003f4e62004842565b6bffffffffffffffffffffffff82811682821603908082111562003f4e5762003f4e62004842565b604081526000620052b2604083018662004d76565b8281036020840152620052c781858762004897565b9695505050505050565b8051602080830151919081101562004a63577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60209190910360031b1b16919050565b815167ffffffffffffffff8111156200533157620053316200409d565b620053498162005342845462004a14565b8462004a69565b602080601f8311600181146200539f5760008415620053685750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b17855562004ab3565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015620053ee57888601518255948401946001909101908401620053cd565b50858210156200542b57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b805169ffffffffffffffffffff81168114620038f657600080fd5b600080600080600060a086880312156200546f57600080fd5b6200547a866200543b565b94506020860151935060408601519250606086015191506200549f608087016200543b565b90509295509295909350565b60008154620054ba8162004a14565b808552602060018381168015620054da5760018114620055135762005543565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008516838901528284151560051b890101955062005543565b866000528260002060005b858110156200553b5781548a82018601529083019084016200551e565b890184019650505b505050505092915050565b602081526000620029b36020830184620054ab565b600082601f8301126200557557600080fd5b8151602062005588620041dd83620046ef565b82815260059290921b84018101918181019086841115620055a857600080fd5b8286015b84811015620047a05780518352918301918301620055ac565b600060208284031215620055d857600080fd5b815167ffffffffffffffff80821115620055f157600080fd5b9083019061010082860312156200560757600080fd5b62005611620040f8565b82518152602083015160208201526040830151604082015260608301516060820152608083015160808201526200564b60a084016200490b565b60a082015260c0830151828111156200566357600080fd5b620056718782860162005563565b60c08301525060e0830151828111156200568a57600080fd5b62005698878286016200497b565b60e08301525095945050505050565b600081518084526020808501945080840160005b8381101562004d2357815187529582019590820190600101620056bb565b60408152825160408201526020830151606082015260408301516080820152606083015160a0820152608083015160c082015273ffffffffffffffffffffffffffffffffffffffff60a08401511660e0820152600060c08401516101008081850152506200574c610140840182620056a7565b905060e08501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0848303016101208501526200578a82826200436d565b91505082810360208401526200399f8185620054ab565b600060208284031215620057b457600080fd5b5051919050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615620057f657620057f662004842565b500290565b60ff8181168382160190811115620029b657620029b662004842565b8284823760008382016000815283516200583681836020880162004347565b0195945050505050565b600063ffffffff8083168185168183048111821515161562005866576200586662004842565b02949350505050565b60008060008060008060c087890312156200588957600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600082620058f1577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe60c060405234801561001057600080fd5b506040516103ca3803806103ca83398101604081905261002f91610076565b600080546001600160a01b0319166001600160a01b039384161790559181166080521660a0526100b9565b80516001600160a01b038116811461007157600080fd5b919050565b60008060006060848603121561008b57600080fd5b6100948461005a565b92506100a26020850161005a565b91506100b06040850161005a565b90509250925092565b60805160a0516102e76100e36000396000603801526000818160c4015261011701526102e76000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806379188d161461007b578063f00e6a2a146100aa575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610076573d6000f35b3d6000fd5b61008e6100893660046101c1565b6100ee565b6040805192151583526020830191909152015b60405180910390f35b60405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001681526020016100a1565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331461011557600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005a91505a61138881101561014957600080fd5b61138881039050856040820482031161016157600080fd5b50803b61016d57600080fd5b6000808551602087016000858af192505a610188908361029a565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080604083850312156101d457600080fd5b82359150602083013567ffffffffffffffff808211156101f357600080fd5b818501915085601f83011261020757600080fd5b81358181111561021957610219610192565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561025f5761025f610192565b8160405282815288602084870101111561027857600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b818103818111156102d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291505056fea164736f6c6343000810000a307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", +} + +var AutomationRegistryLogicAABI = AutomationRegistryLogicAMetaData.ABI + +var AutomationRegistryLogicABin = AutomationRegistryLogicAMetaData.Bin + +func DeployAutomationRegistryLogicA(auth *bind.TransactOpts, backend bind.ContractBackend, logicB common.Address) (common.Address, *types.Transaction, *AutomationRegistryLogicA, error) { + parsed, err := AutomationRegistryLogicAMetaData.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(AutomationRegistryLogicABin), backend, logicB) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationRegistryLogicA{address: address, abi: *parsed, AutomationRegistryLogicACaller: AutomationRegistryLogicACaller{contract: contract}, AutomationRegistryLogicATransactor: AutomationRegistryLogicATransactor{contract: contract}, AutomationRegistryLogicAFilterer: AutomationRegistryLogicAFilterer{contract: contract}}, nil +} + +type AutomationRegistryLogicA struct { + address common.Address + abi abi.ABI + AutomationRegistryLogicACaller + AutomationRegistryLogicATransactor + AutomationRegistryLogicAFilterer +} + +type AutomationRegistryLogicACaller struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicATransactor struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicAFilterer struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicASession struct { + Contract *AutomationRegistryLogicA + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationRegistryLogicACallerSession struct { + Contract *AutomationRegistryLogicACaller + CallOpts bind.CallOpts +} + +type AutomationRegistryLogicATransactorSession struct { + Contract *AutomationRegistryLogicATransactor + TransactOpts bind.TransactOpts +} + +type AutomationRegistryLogicARaw struct { + Contract *AutomationRegistryLogicA +} + +type AutomationRegistryLogicACallerRaw struct { + Contract *AutomationRegistryLogicACaller +} + +type AutomationRegistryLogicATransactorRaw struct { + Contract *AutomationRegistryLogicATransactor +} + +func NewAutomationRegistryLogicA(address common.Address, backend bind.ContractBackend) (*AutomationRegistryLogicA, error) { + abi, err := abi.JSON(strings.NewReader(AutomationRegistryLogicAABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationRegistryLogicA(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicA{address: address, abi: abi, AutomationRegistryLogicACaller: AutomationRegistryLogicACaller{contract: contract}, AutomationRegistryLogicATransactor: AutomationRegistryLogicATransactor{contract: contract}, AutomationRegistryLogicAFilterer: AutomationRegistryLogicAFilterer{contract: contract}}, nil +} + +func NewAutomationRegistryLogicACaller(address common.Address, caller bind.ContractCaller) (*AutomationRegistryLogicACaller, error) { + contract, err := bindAutomationRegistryLogicA(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicACaller{contract: contract}, nil +} + +func NewAutomationRegistryLogicATransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationRegistryLogicATransactor, error) { + contract, err := bindAutomationRegistryLogicA(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicATransactor{contract: contract}, nil +} + +func NewAutomationRegistryLogicAFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationRegistryLogicAFilterer, error) { + contract, err := bindAutomationRegistryLogicA(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAFilterer{contract: contract}, nil +} + +func bindAutomationRegistryLogicA(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationRegistryLogicAMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicARaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistryLogicA.Contract.AutomationRegistryLogicACaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicARaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AutomationRegistryLogicATransactor.contract.Transfer(opts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicARaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AutomationRegistryLogicATransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicACallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistryLogicA.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.contract.Transfer(opts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicACaller) FallbackTo(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicA.contract.Call(opts, &out, "fallbackTo") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) FallbackTo() (common.Address, error) { + return _AutomationRegistryLogicA.Contract.FallbackTo(&_AutomationRegistryLogicA.CallOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicACallerSession) FallbackTo() (common.Address, error) { + return _AutomationRegistryLogicA.Contract.FallbackTo(&_AutomationRegistryLogicA.CallOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicACaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicA.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 (_AutomationRegistryLogicA *AutomationRegistryLogicASession) Owner() (common.Address, error) { + return _AutomationRegistryLogicA.Contract.Owner(&_AutomationRegistryLogicA.CallOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicACallerSession) Owner() (common.Address, error) { + return _AutomationRegistryLogicA.Contract.Owner(&_AutomationRegistryLogicA.CallOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "acceptOwnership") +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AcceptOwnership(&_AutomationRegistryLogicA.TransactOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AcceptOwnership(&_AutomationRegistryLogicA.TransactOpts) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "addFunds", id, amount) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AddFunds(&_AutomationRegistryLogicA.TransactOpts, id, amount) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) AddFunds(id *big.Int, amount *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.AddFunds(&_AutomationRegistryLogicA.TransactOpts, id, amount) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CancelUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "cancelUpkeep", id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CancelUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CancelUpkeep(&_AutomationRegistryLogicA.TransactOpts, id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CancelUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CancelUpkeep(&_AutomationRegistryLogicA.TransactOpts, id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "checkCallback", id, values, extraData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckCallback(&_AutomationRegistryLogicA.TransactOpts, id, values, extraData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CheckCallback(id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckCallback(&_AutomationRegistryLogicA.TransactOpts, id, values, extraData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CheckUpkeep(opts *bind.TransactOpts, id *big.Int, triggerData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "checkUpkeep", id, triggerData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CheckUpkeep(id *big.Int, triggerData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckUpkeep(&_AutomationRegistryLogicA.TransactOpts, id, triggerData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CheckUpkeep(id *big.Int, triggerData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckUpkeep(&_AutomationRegistryLogicA.TransactOpts, id, triggerData) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) CheckUpkeep0(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "checkUpkeep0", id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) CheckUpkeep0(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckUpkeep0(&_AutomationRegistryLogicA.TransactOpts, id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) CheckUpkeep0(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.CheckUpkeep0(&_AutomationRegistryLogicA.TransactOpts, id) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "executeCallback", id, payload) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.ExecuteCallback(&_AutomationRegistryLogicA.TransactOpts, id, payload) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) ExecuteCallback(id *big.Int, payload []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.ExecuteCallback(&_AutomationRegistryLogicA.TransactOpts, id, payload) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) MigrateUpkeeps(opts *bind.TransactOpts, ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "migrateUpkeeps", ids, destination) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) MigrateUpkeeps(ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.MigrateUpkeeps(&_AutomationRegistryLogicA.TransactOpts, ids, destination) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) MigrateUpkeeps(ids []*big.Int, destination common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.MigrateUpkeeps(&_AutomationRegistryLogicA.TransactOpts, ids, destination) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) ReceiveUpkeeps(opts *bind.TransactOpts, encodedUpkeeps []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "receiveUpkeeps", encodedUpkeeps) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) ReceiveUpkeeps(encodedUpkeeps []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.ReceiveUpkeeps(&_AutomationRegistryLogicA.TransactOpts, encodedUpkeeps) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) ReceiveUpkeeps(encodedUpkeeps []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.ReceiveUpkeeps(&_AutomationRegistryLogicA.TransactOpts, encodedUpkeeps) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "registerUpkeep", target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.RegisterUpkeep(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) RegisterUpkeep(target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.RegisterUpkeep(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, triggerType, checkData, triggerConfig, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "registerUpkeep0", target, gasLimit, admin, checkData, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.RegisterUpkeep0(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) RegisterUpkeep0(target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.RegisterUpkeep0(&_AutomationRegistryLogicA.TransactOpts, target, gasLimit, admin, checkData, offchainConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "setUpkeepTriggerConfig", id, triggerConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.SetUpkeepTriggerConfig(&_AutomationRegistryLogicA.TransactOpts, id, triggerConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) SetUpkeepTriggerConfig(id *big.Int, triggerConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.SetUpkeepTriggerConfig(&_AutomationRegistryLogicA.TransactOpts, id, triggerConfig) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.Transact(opts, "transferOwnership", to) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.TransferOwnership(&_AutomationRegistryLogicA.TransactOpts, to) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.TransferOwnership(&_AutomationRegistryLogicA.TransactOpts, to) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.contract.RawTransact(opts, calldata) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicASession) Fallback(calldata []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.Fallback(&_AutomationRegistryLogicA.TransactOpts, calldata) +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicATransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicA.Contract.Fallback(&_AutomationRegistryLogicA.TransactOpts, calldata) +} + +type AutomationRegistryLogicAAdminPrivilegeConfigSetIterator struct { + Event *AutomationRegistryLogicAAdminPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAAdminPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAAdminPrivilegeConfigSet) + 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(AutomationRegistryLogicAAdminPrivilegeConfigSet) + 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 *AutomationRegistryLogicAAdminPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAAdminPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAAdminPrivilegeConfigSet struct { + Admin common.Address + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicAAdminPrivilegeConfigSetIterator, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAAdminPrivilegeConfigSetIterator{contract: _AutomationRegistryLogicA.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAAdminPrivilegeConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "AdminPrivilegeConfigSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicAAdminPrivilegeConfigSet, error) { + event := new(AutomationRegistryLogicAAdminPrivilegeConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicACancelledUpkeepReportIterator struct { + Event *AutomationRegistryLogicACancelledUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicACancelledUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicACancelledUpkeepReport) + 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(AutomationRegistryLogicACancelledUpkeepReport) + 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 *AutomationRegistryLogicACancelledUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicACancelledUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicACancelledUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicACancelledUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicACancelledUpkeepReportIterator{contract: _AutomationRegistryLogicA.contract, event: "CancelledUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicACancelledUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicACancelledUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "CancelledUpkeepReport", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryLogicACancelledUpkeepReport, error) { + event := new(AutomationRegistryLogicACancelledUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "CancelledUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicADedupKeyAddedIterator struct { + Event *AutomationRegistryLogicADedupKeyAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicADedupKeyAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicADedupKeyAdded) + 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(AutomationRegistryLogicADedupKeyAdded) + 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 *AutomationRegistryLogicADedupKeyAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicADedupKeyAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicADedupKeyAdded struct { + DedupKey [32]byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryLogicADedupKeyAddedIterator, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicADedupKeyAddedIterator{contract: _AutomationRegistryLogicA.contract, event: "DedupKeyAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicADedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicADedupKeyAdded) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "DedupKeyAdded", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseDedupKeyAdded(log types.Log) (*AutomationRegistryLogicADedupKeyAdded, error) { + event := new(AutomationRegistryLogicADedupKeyAdded) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "DedupKeyAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAFundsAddedIterator struct { + Event *AutomationRegistryLogicAFundsAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAFundsAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAFundsAdded) + 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(AutomationRegistryLogicAFundsAdded) + 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 *AutomationRegistryLogicAFundsAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAFundsAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAFundsAdded struct { + Id *big.Int + From common.Address + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryLogicAFundsAddedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAFundsAddedIterator{contract: _AutomationRegistryLogicA.contract, event: "FundsAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAFundsAdded) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "FundsAdded", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseFundsAdded(log types.Log) (*AutomationRegistryLogicAFundsAdded, error) { + event := new(AutomationRegistryLogicAFundsAdded) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "FundsAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAFundsWithdrawnIterator struct { + Event *AutomationRegistryLogicAFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAFundsWithdrawn) + 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(AutomationRegistryLogicAFundsWithdrawn) + 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 *AutomationRegistryLogicAFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAFundsWithdrawn struct { + Id *big.Int + Amount *big.Int + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAFundsWithdrawnIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAFundsWithdrawnIterator{contract: _AutomationRegistryLogicA.contract, event: "FundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFundsWithdrawn, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAFundsWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "FundsWithdrawn", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseFundsWithdrawn(log types.Log) (*AutomationRegistryLogicAFundsWithdrawn, error) { + event := new(AutomationRegistryLogicAFundsWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "FundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator struct { + Event *AutomationRegistryLogicAInsufficientFundsUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAInsufficientFundsUpkeepReport) + 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(AutomationRegistryLogicAInsufficientFundsUpkeepReport) + 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 *AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAInsufficientFundsUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator{contract: _AutomationRegistryLogicA.contract, event: "InsufficientFundsUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAInsufficientFundsUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryLogicAInsufficientFundsUpkeepReport, error) { + event := new(AutomationRegistryLogicAInsufficientFundsUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAOwnerFundsWithdrawnIterator struct { + Event *AutomationRegistryLogicAOwnerFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAOwnerFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAOwnerFundsWithdrawn) + 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(AutomationRegistryLogicAOwnerFundsWithdrawn) + 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 *AutomationRegistryLogicAOwnerFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAOwnerFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAOwnerFundsWithdrawn struct { + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryLogicAOwnerFundsWithdrawnIterator, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAOwnerFundsWithdrawnIterator{contract: _AutomationRegistryLogicA.contract, event: "OwnerFundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnerFundsWithdrawn) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAOwnerFundsWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "OwnerFundsWithdrawn", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryLogicAOwnerFundsWithdrawn, error) { + event := new(AutomationRegistryLogicAOwnerFundsWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "OwnerFundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAOwnershipTransferRequestedIterator struct { + Event *AutomationRegistryLogicAOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAOwnershipTransferRequested) + 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(AutomationRegistryLogicAOwnershipTransferRequested) + 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 *AutomationRegistryLogicAOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicAOwnershipTransferRequestedIterator, 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAOwnershipTransferRequestedIterator{contract: _AutomationRegistryLogicA.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnershipTransferRequested, 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 := _AutomationRegistryLogicA.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(AutomationRegistryLogicAOwnershipTransferRequested) + if err := _AutomationRegistryLogicA.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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryLogicAOwnershipTransferRequested, error) { + event := new(AutomationRegistryLogicAOwnershipTransferRequested) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAOwnershipTransferredIterator struct { + Event *AutomationRegistryLogicAOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAOwnershipTransferred) + 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(AutomationRegistryLogicAOwnershipTransferred) + 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 *AutomationRegistryLogicAOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicAOwnershipTransferredIterator, 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAOwnershipTransferredIterator{contract: _AutomationRegistryLogicA.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnershipTransferred, 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 := _AutomationRegistryLogicA.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(AutomationRegistryLogicAOwnershipTransferred) + if err := _AutomationRegistryLogicA.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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseOwnershipTransferred(log types.Log) (*AutomationRegistryLogicAOwnershipTransferred, error) { + event := new(AutomationRegistryLogicAOwnershipTransferred) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAPausedIterator struct { + Event *AutomationRegistryLogicAPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAPaused) + 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(AutomationRegistryLogicAPaused) + 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 *AutomationRegistryLogicAPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAPaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryLogicAPausedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "Paused") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAPausedIterator{contract: _AutomationRegistryLogicA.contract, event: "Paused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "Paused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAPaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "Paused", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParsePaused(log types.Log) (*AutomationRegistryLogicAPaused, error) { + event := new(AutomationRegistryLogicAPaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "Paused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAPayeesUpdatedIterator struct { + Event *AutomationRegistryLogicAPayeesUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAPayeesUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAPayeesUpdated) + 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(AutomationRegistryLogicAPayeesUpdated) + 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 *AutomationRegistryLogicAPayeesUpdatedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAPayeesUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAPayeesUpdated struct { + Transmitters []common.Address + Payees []common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryLogicAPayeesUpdatedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAPayeesUpdatedIterator{contract: _AutomationRegistryLogicA.contract, event: "PayeesUpdated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeesUpdated) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAPayeesUpdated) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeesUpdated", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParsePayeesUpdated(log types.Log) (*AutomationRegistryLogicAPayeesUpdated, error) { + event := new(AutomationRegistryLogicAPayeesUpdated) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeesUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAPayeeshipTransferRequestedIterator struct { + Event *AutomationRegistryLogicAPayeeshipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAPayeeshipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAPayeeshipTransferRequested) + 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(AutomationRegistryLogicAPayeeshipTransferRequested) + 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 *AutomationRegistryLogicAPayeeshipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAPayeeshipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAPayeeshipTransferRequested struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicAPayeeshipTransferRequestedIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "PayeeshipTransferRequested", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAPayeeshipTransferRequestedIterator{contract: _AutomationRegistryLogicA.contract, event: "PayeeshipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicA.contract.WatchLogs(opts, "PayeeshipTransferRequested", transmitterRule, 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(AutomationRegistryLogicAPayeeshipTransferRequested) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeeshipTransferRequested", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryLogicAPayeeshipTransferRequested, error) { + event := new(AutomationRegistryLogicAPayeeshipTransferRequested) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeeshipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAPayeeshipTransferredIterator struct { + Event *AutomationRegistryLogicAPayeeshipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAPayeeshipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAPayeeshipTransferred) + 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(AutomationRegistryLogicAPayeeshipTransferred) + 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 *AutomationRegistryLogicAPayeeshipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAPayeeshipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAPayeeshipTransferred struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicAPayeeshipTransferredIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "PayeeshipTransferred", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAPayeeshipTransferredIterator{contract: _AutomationRegistryLogicA.contract, event: "PayeeshipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicA.contract.WatchLogs(opts, "PayeeshipTransferred", transmitterRule, 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(AutomationRegistryLogicAPayeeshipTransferred) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeeshipTransferred", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryLogicAPayeeshipTransferred, error) { + event := new(AutomationRegistryLogicAPayeeshipTransferred) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PayeeshipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAPaymentWithdrawnIterator struct { + Event *AutomationRegistryLogicAPaymentWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAPaymentWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAPaymentWithdrawn) + 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(AutomationRegistryLogicAPaymentWithdrawn) + 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 *AutomationRegistryLogicAPaymentWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAPaymentWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAPaymentWithdrawn struct { + Transmitter common.Address + Amount *big.Int + To common.Address + Payee common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryLogicAPaymentWithdrawnIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAPaymentWithdrawnIterator{contract: _AutomationRegistryLogicA.contract, event: "PaymentWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, 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(AutomationRegistryLogicAPaymentWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PaymentWithdrawn", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryLogicAPaymentWithdrawn, error) { + event := new(AutomationRegistryLogicAPaymentWithdrawn) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "PaymentWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAReorgedUpkeepReportIterator struct { + Event *AutomationRegistryLogicAReorgedUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAReorgedUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAReorgedUpkeepReport) + 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(AutomationRegistryLogicAReorgedUpkeepReport) + 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 *AutomationRegistryLogicAReorgedUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAReorgedUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAReorgedUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAReorgedUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAReorgedUpkeepReportIterator{contract: _AutomationRegistryLogicA.contract, event: "ReorgedUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAReorgedUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "ReorgedUpkeepReport", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryLogicAReorgedUpkeepReport, error) { + event := new(AutomationRegistryLogicAReorgedUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "ReorgedUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAStaleUpkeepReportIterator struct { + Event *AutomationRegistryLogicAStaleUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAStaleUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAStaleUpkeepReport) + 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(AutomationRegistryLogicAStaleUpkeepReport) + 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 *AutomationRegistryLogicAStaleUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAStaleUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAStaleUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAStaleUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAStaleUpkeepReportIterator{contract: _AutomationRegistryLogicA.contract, event: "StaleUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAStaleUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAStaleUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "StaleUpkeepReport", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryLogicAStaleUpkeepReport, error) { + event := new(AutomationRegistryLogicAStaleUpkeepReport) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "StaleUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUnpausedIterator struct { + Event *AutomationRegistryLogicAUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUnpaused) + 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(AutomationRegistryLogicAUnpaused) + 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 *AutomationRegistryLogicAUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUnpaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryLogicAUnpausedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUnpausedIterator{contract: _AutomationRegistryLogicA.contract, event: "Unpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUnpaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUnpaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "Unpaused", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUnpaused(log types.Log) (*AutomationRegistryLogicAUnpaused, error) { + event := new(AutomationRegistryLogicAUnpaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "Unpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator struct { + Event *AutomationRegistryLogicAUpkeepAdminTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepAdminTransferRequested) + 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(AutomationRegistryLogicAUpkeepAdminTransferRequested) + 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 *AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepAdminTransferRequested struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepAdminTransferRequested", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepAdminTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepAdminTransferRequested", idRule, 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(AutomationRegistryLogicAUpkeepAdminTransferRequested) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepAdminTransferRequested", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryLogicAUpkeepAdminTransferRequested, error) { + event := new(AutomationRegistryLogicAUpkeepAdminTransferRequested) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepAdminTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepAdminTransferredIterator struct { + Event *AutomationRegistryLogicAUpkeepAdminTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepAdminTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepAdminTransferred) + 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(AutomationRegistryLogicAUpkeepAdminTransferred) + 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 *AutomationRegistryLogicAUpkeepAdminTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepAdminTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepAdminTransferred struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicAUpkeepAdminTransferredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepAdminTransferred", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepAdminTransferredIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepAdminTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepAdminTransferred", idRule, 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(AutomationRegistryLogicAUpkeepAdminTransferred) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepAdminTransferred", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryLogicAUpkeepAdminTransferred, error) { + event := new(AutomationRegistryLogicAUpkeepAdminTransferred) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepAdminTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepCanceledIterator struct { + Event *AutomationRegistryLogicAUpkeepCanceled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepCanceledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepCanceled) + 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(AutomationRegistryLogicAUpkeepCanceled) + 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 *AutomationRegistryLogicAUpkeepCanceledIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepCanceledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepCanceled struct { + Id *big.Int + AtBlockHeight uint64 + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryLogicAUpkeepCanceledIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepCanceledIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepCanceled", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepCanceled) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepCanceled", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepCanceled(log types.Log) (*AutomationRegistryLogicAUpkeepCanceled, error) { + event := new(AutomationRegistryLogicAUpkeepCanceled) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepCanceled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepCheckDataSetIterator struct { + Event *AutomationRegistryLogicAUpkeepCheckDataSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepCheckDataSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepCheckDataSet) + 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(AutomationRegistryLogicAUpkeepCheckDataSet) + 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 *AutomationRegistryLogicAUpkeepCheckDataSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepCheckDataSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepCheckDataSet struct { + Id *big.Int + NewCheckData []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepCheckDataSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepCheckDataSetIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepCheckDataSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepCheckDataSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepCheckDataSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryLogicAUpkeepCheckDataSet, error) { + event := new(AutomationRegistryLogicAUpkeepCheckDataSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepCheckDataSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepGasLimitSetIterator struct { + Event *AutomationRegistryLogicAUpkeepGasLimitSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepGasLimitSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepGasLimitSet) + 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(AutomationRegistryLogicAUpkeepGasLimitSet) + 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 *AutomationRegistryLogicAUpkeepGasLimitSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepGasLimitSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepGasLimitSet struct { + Id *big.Int + GasLimit *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepGasLimitSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepGasLimitSetIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepGasLimitSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepGasLimitSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepGasLimitSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryLogicAUpkeepGasLimitSet, error) { + event := new(AutomationRegistryLogicAUpkeepGasLimitSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepGasLimitSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepMigratedIterator struct { + Event *AutomationRegistryLogicAUpkeepMigrated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepMigratedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepMigrated) + 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(AutomationRegistryLogicAUpkeepMigrated) + 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 *AutomationRegistryLogicAUpkeepMigratedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepMigratedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepMigrated struct { + Id *big.Int + RemainingBalance *big.Int + Destination common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepMigratedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepMigratedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepMigrated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepMigrated, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepMigrated) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepMigrated", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepMigrated(log types.Log) (*AutomationRegistryLogicAUpkeepMigrated, error) { + event := new(AutomationRegistryLogicAUpkeepMigrated) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepMigrated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepOffchainConfigSetIterator struct { + Event *AutomationRegistryLogicAUpkeepOffchainConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepOffchainConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepOffchainConfigSet) + 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(AutomationRegistryLogicAUpkeepOffchainConfigSet) + 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 *AutomationRegistryLogicAUpkeepOffchainConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepOffchainConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepOffchainConfigSet struct { + Id *big.Int + OffchainConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepOffchainConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepOffchainConfigSetIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepOffchainConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepOffchainConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepOffchainConfigSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepOffchainConfigSet, error) { + event := new(AutomationRegistryLogicAUpkeepOffchainConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepOffchainConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepPausedIterator struct { + Event *AutomationRegistryLogicAUpkeepPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepPaused) + 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(AutomationRegistryLogicAUpkeepPaused) + 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 *AutomationRegistryLogicAUpkeepPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepPaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepPausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepPausedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepPaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepPaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPaused", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepPaused(log types.Log) (*AutomationRegistryLogicAUpkeepPaused, error) { + event := new(AutomationRegistryLogicAUpkeepPaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepPerformedIterator struct { + Event *AutomationRegistryLogicAUpkeepPerformed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepPerformedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepPerformed) + 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(AutomationRegistryLogicAUpkeepPerformed) + 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 *AutomationRegistryLogicAUpkeepPerformedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepPerformedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepPerformed struct { + Id *big.Int + Success bool + TotalPayment *big.Int + GasUsed *big.Int + GasOverhead *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryLogicAUpkeepPerformedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepPerformedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepPerformed", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepPerformed) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPerformed", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepPerformed(log types.Log) (*AutomationRegistryLogicAUpkeepPerformed, error) { + event := new(AutomationRegistryLogicAUpkeepPerformed) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPerformed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator struct { + Event *AutomationRegistryLogicAUpkeepPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepPrivilegeConfigSet) + 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(AutomationRegistryLogicAUpkeepPrivilegeConfigSet) + 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 *AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepPrivilegeConfigSet struct { + Id *big.Int + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepPrivilegeConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepPrivilegeConfigSet, error) { + event := new(AutomationRegistryLogicAUpkeepPrivilegeConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepReceivedIterator struct { + Event *AutomationRegistryLogicAUpkeepReceived + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepReceivedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepReceived) + 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(AutomationRegistryLogicAUpkeepReceived) + 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 *AutomationRegistryLogicAUpkeepReceivedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepReceivedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepReceived struct { + Id *big.Int + StartingBalance *big.Int + ImportedFrom common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepReceivedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepReceivedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepReceived", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepReceived, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepReceived) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepReceived", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepReceived(log types.Log) (*AutomationRegistryLogicAUpkeepReceived, error) { + event := new(AutomationRegistryLogicAUpkeepReceived) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepReceived", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepRegisteredIterator struct { + Event *AutomationRegistryLogicAUpkeepRegistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepRegisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepRegistered) + 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(AutomationRegistryLogicAUpkeepRegistered) + 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 *AutomationRegistryLogicAUpkeepRegisteredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepRegistered struct { + Id *big.Int + PerformGas uint32 + Admin common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepRegisteredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepRegisteredIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepRegistered", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepRegistered, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepRegistered) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepRegistered", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepRegistered(log types.Log) (*AutomationRegistryLogicAUpkeepRegistered, error) { + event := new(AutomationRegistryLogicAUpkeepRegistered) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepTriggerConfigSetIterator struct { + Event *AutomationRegistryLogicAUpkeepTriggerConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepTriggerConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepTriggerConfigSet) + 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(AutomationRegistryLogicAUpkeepTriggerConfigSet) + 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 *AutomationRegistryLogicAUpkeepTriggerConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepTriggerConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepTriggerConfigSet struct { + Id *big.Int + TriggerConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepTriggerConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepTriggerConfigSetIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepTriggerConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepTriggerConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepTriggerConfigSet", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepTriggerConfigSet, error) { + event := new(AutomationRegistryLogicAUpkeepTriggerConfigSet) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepTriggerConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicAUpkeepUnpausedIterator struct { + Event *AutomationRegistryLogicAUpkeepUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicAUpkeepUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicAUpkeepUnpaused) + 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(AutomationRegistryLogicAUpkeepUnpaused) + 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 *AutomationRegistryLogicAUpkeepUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicAUpkeepUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicAUpkeepUnpaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepUnpausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.FilterLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicAUpkeepUnpausedIterator{contract: _AutomationRegistryLogicA.contract, event: "UpkeepUnpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepUnpaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicA.contract.WatchLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicAUpkeepUnpaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepUnpaused", 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 (_AutomationRegistryLogicA *AutomationRegistryLogicAFilterer) ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryLogicAUpkeepUnpaused, error) { + event := new(AutomationRegistryLogicAUpkeepUnpaused) + if err := _AutomationRegistryLogicA.contract.UnpackLog(event, "UpkeepUnpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicA) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _AutomationRegistryLogicA.abi.Events["AdminPrivilegeConfigSet"].ID: + return _AutomationRegistryLogicA.ParseAdminPrivilegeConfigSet(log) + case _AutomationRegistryLogicA.abi.Events["CancelledUpkeepReport"].ID: + return _AutomationRegistryLogicA.ParseCancelledUpkeepReport(log) + case _AutomationRegistryLogicA.abi.Events["DedupKeyAdded"].ID: + return _AutomationRegistryLogicA.ParseDedupKeyAdded(log) + case _AutomationRegistryLogicA.abi.Events["FundsAdded"].ID: + return _AutomationRegistryLogicA.ParseFundsAdded(log) + case _AutomationRegistryLogicA.abi.Events["FundsWithdrawn"].ID: + return _AutomationRegistryLogicA.ParseFundsWithdrawn(log) + case _AutomationRegistryLogicA.abi.Events["InsufficientFundsUpkeepReport"].ID: + return _AutomationRegistryLogicA.ParseInsufficientFundsUpkeepReport(log) + case _AutomationRegistryLogicA.abi.Events["OwnerFundsWithdrawn"].ID: + return _AutomationRegistryLogicA.ParseOwnerFundsWithdrawn(log) + case _AutomationRegistryLogicA.abi.Events["OwnershipTransferRequested"].ID: + return _AutomationRegistryLogicA.ParseOwnershipTransferRequested(log) + case _AutomationRegistryLogicA.abi.Events["OwnershipTransferred"].ID: + return _AutomationRegistryLogicA.ParseOwnershipTransferred(log) + case _AutomationRegistryLogicA.abi.Events["Paused"].ID: + return _AutomationRegistryLogicA.ParsePaused(log) + case _AutomationRegistryLogicA.abi.Events["PayeesUpdated"].ID: + return _AutomationRegistryLogicA.ParsePayeesUpdated(log) + case _AutomationRegistryLogicA.abi.Events["PayeeshipTransferRequested"].ID: + return _AutomationRegistryLogicA.ParsePayeeshipTransferRequested(log) + case _AutomationRegistryLogicA.abi.Events["PayeeshipTransferred"].ID: + return _AutomationRegistryLogicA.ParsePayeeshipTransferred(log) + case _AutomationRegistryLogicA.abi.Events["PaymentWithdrawn"].ID: + return _AutomationRegistryLogicA.ParsePaymentWithdrawn(log) + case _AutomationRegistryLogicA.abi.Events["ReorgedUpkeepReport"].ID: + return _AutomationRegistryLogicA.ParseReorgedUpkeepReport(log) + case _AutomationRegistryLogicA.abi.Events["StaleUpkeepReport"].ID: + return _AutomationRegistryLogicA.ParseStaleUpkeepReport(log) + case _AutomationRegistryLogicA.abi.Events["Unpaused"].ID: + return _AutomationRegistryLogicA.ParseUnpaused(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepAdminTransferRequested"].ID: + return _AutomationRegistryLogicA.ParseUpkeepAdminTransferRequested(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepAdminTransferred"].ID: + return _AutomationRegistryLogicA.ParseUpkeepAdminTransferred(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepCanceled"].ID: + return _AutomationRegistryLogicA.ParseUpkeepCanceled(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepCheckDataSet"].ID: + return _AutomationRegistryLogicA.ParseUpkeepCheckDataSet(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepGasLimitSet"].ID: + return _AutomationRegistryLogicA.ParseUpkeepGasLimitSet(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepMigrated"].ID: + return _AutomationRegistryLogicA.ParseUpkeepMigrated(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepOffchainConfigSet"].ID: + return _AutomationRegistryLogicA.ParseUpkeepOffchainConfigSet(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepPaused"].ID: + return _AutomationRegistryLogicA.ParseUpkeepPaused(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepPerformed"].ID: + return _AutomationRegistryLogicA.ParseUpkeepPerformed(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepPrivilegeConfigSet"].ID: + return _AutomationRegistryLogicA.ParseUpkeepPrivilegeConfigSet(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepReceived"].ID: + return _AutomationRegistryLogicA.ParseUpkeepReceived(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepRegistered"].ID: + return _AutomationRegistryLogicA.ParseUpkeepRegistered(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepTriggerConfigSet"].ID: + return _AutomationRegistryLogicA.ParseUpkeepTriggerConfigSet(log) + case _AutomationRegistryLogicA.abi.Events["UpkeepUnpaused"].ID: + return _AutomationRegistryLogicA.ParseUpkeepUnpaused(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (AutomationRegistryLogicAAdminPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") +} + +func (AutomationRegistryLogicACancelledUpkeepReport) Topic() common.Hash { + return common.HexToHash("0xc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636") +} + +func (AutomationRegistryLogicADedupKeyAdded) Topic() common.Hash { + return common.HexToHash("0xa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f2") +} + +func (AutomationRegistryLogicAFundsAdded) Topic() common.Hash { + return common.HexToHash("0xafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203") +} + +func (AutomationRegistryLogicAFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0xf3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318") +} + +func (AutomationRegistryLogicAInsufficientFundsUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") +} + +func (AutomationRegistryLogicAOwnerFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0x1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f1") +} + +func (AutomationRegistryLogicAOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (AutomationRegistryLogicAOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (AutomationRegistryLogicAPaused) Topic() common.Hash { + return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258") +} + +func (AutomationRegistryLogicAPayeesUpdated) Topic() common.Hash { + return common.HexToHash("0xa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725") +} + +func (AutomationRegistryLogicAPayeeshipTransferRequested) Topic() common.Hash { + return common.HexToHash("0x84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e38367") +} + +func (AutomationRegistryLogicAPayeeshipTransferred) Topic() common.Hash { + return common.HexToHash("0x78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b3") +} + +func (AutomationRegistryLogicAPaymentWithdrawn) Topic() common.Hash { + return common.HexToHash("0x9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698") +} + +func (AutomationRegistryLogicAReorgedUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301") +} + +func (AutomationRegistryLogicAStaleUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8") +} + +func (AutomationRegistryLogicAUnpaused) Topic() common.Hash { + return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa") +} + +func (AutomationRegistryLogicAUpkeepAdminTransferRequested) Topic() common.Hash { + return common.HexToHash("0xb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b35") +} + +func (AutomationRegistryLogicAUpkeepAdminTransferred) Topic() common.Hash { + return common.HexToHash("0x5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c") +} + +func (AutomationRegistryLogicAUpkeepCanceled) Topic() common.Hash { + return common.HexToHash("0x91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f791181") +} + +func (AutomationRegistryLogicAUpkeepCheckDataSet) Topic() common.Hash { + return common.HexToHash("0xcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d") +} + +func (AutomationRegistryLogicAUpkeepGasLimitSet) Topic() common.Hash { + return common.HexToHash("0xc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c") +} + +func (AutomationRegistryLogicAUpkeepMigrated) Topic() common.Hash { + return common.HexToHash("0xb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff") +} + +func (AutomationRegistryLogicAUpkeepOffchainConfigSet) Topic() common.Hash { + return common.HexToHash("0x3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850") +} + +func (AutomationRegistryLogicAUpkeepPaused) Topic() common.Hash { + return common.HexToHash("0x8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f") +} + +func (AutomationRegistryLogicAUpkeepPerformed) Topic() common.Hash { + return common.HexToHash("0xad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b") +} + +func (AutomationRegistryLogicAUpkeepPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae7769") +} + +func (AutomationRegistryLogicAUpkeepReceived) Topic() common.Hash { + return common.HexToHash("0x74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71") +} + +func (AutomationRegistryLogicAUpkeepRegistered) Topic() common.Hash { + return common.HexToHash("0xbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d012") +} + +func (AutomationRegistryLogicAUpkeepTriggerConfigSet) Topic() common.Hash { + return common.HexToHash("0x2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664") +} + +func (AutomationRegistryLogicAUpkeepUnpaused) Topic() common.Hash { + return common.HexToHash("0x7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a47456") +} + +func (_AutomationRegistryLogicA *AutomationRegistryLogicA) Address() common.Address { + return _AutomationRegistryLogicA.address +} + +type AutomationRegistryLogicAInterface interface { + FallbackTo(opts *bind.CallOpts) (common.Address, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AddFunds(opts *bind.TransactOpts, id *big.Int, amount *big.Int) (*types.Transaction, error) + + CancelUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + CheckCallback(opts *bind.TransactOpts, id *big.Int, values [][]byte, extraData []byte) (*types.Transaction, error) + + CheckUpkeep(opts *bind.TransactOpts, id *big.Int, triggerData []byte) (*types.Transaction, error) + + CheckUpkeep0(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + ExecuteCallback(opts *bind.TransactOpts, id *big.Int, payload []byte) (*types.Transaction, error) + + MigrateUpkeeps(opts *bind.TransactOpts, ids []*big.Int, destination common.Address) (*types.Transaction, error) + + ReceiveUpkeeps(opts *bind.TransactOpts, encodedUpkeeps []byte) (*types.Transaction, error) + + RegisterUpkeep(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, triggerType uint8, checkData []byte, triggerConfig []byte, offchainConfig []byte) (*types.Transaction, error) + + RegisterUpkeep0(opts *bind.TransactOpts, target common.Address, gasLimit uint32, admin common.Address, checkData []byte, offchainConfig []byte) (*types.Transaction, error) + + SetUpkeepTriggerConfig(opts *bind.TransactOpts, id *big.Int, triggerConfig []byte) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) + + FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicAAdminPrivilegeConfigSetIterator, error) + + WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) + + ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicAAdminPrivilegeConfigSet, error) + + FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicACancelledUpkeepReportIterator, error) + + WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicACancelledUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryLogicACancelledUpkeepReport, error) + + FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryLogicADedupKeyAddedIterator, error) + + WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicADedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) + + ParseDedupKeyAdded(log types.Log) (*AutomationRegistryLogicADedupKeyAdded, error) + + FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryLogicAFundsAddedIterator, error) + + WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) + + ParseFundsAdded(log types.Log) (*AutomationRegistryLogicAFundsAdded, error) + + FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAFundsWithdrawnIterator, error) + + WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAFundsWithdrawn, id []*big.Int) (event.Subscription, error) + + ParseFundsWithdrawn(log types.Log) (*AutomationRegistryLogicAFundsWithdrawn, error) + + FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAInsufficientFundsUpkeepReportIterator, error) + + WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryLogicAInsufficientFundsUpkeepReport, error) + + FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryLogicAOwnerFundsWithdrawnIterator, error) + + WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnerFundsWithdrawn) (event.Subscription, error) + + ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryLogicAOwnerFundsWithdrawn, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicAOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryLogicAOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicAOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*AutomationRegistryLogicAOwnershipTransferred, error) + + FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryLogicAPausedIterator, error) + + WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPaused) (event.Subscription, error) + + ParsePaused(log types.Log) (*AutomationRegistryLogicAPaused, error) + + FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryLogicAPayeesUpdatedIterator, error) + + WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeesUpdated) (event.Subscription, error) + + ParsePayeesUpdated(log types.Log) (*AutomationRegistryLogicAPayeesUpdated, error) + + FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicAPayeeshipTransferRequestedIterator, error) + + WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryLogicAPayeeshipTransferRequested, error) + + FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicAPayeeshipTransferredIterator, error) + + WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryLogicAPayeeshipTransferred, error) + + FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryLogicAPaymentWithdrawnIterator, error) + + WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) + + ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryLogicAPaymentWithdrawn, error) + + FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAReorgedUpkeepReportIterator, error) + + WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryLogicAReorgedUpkeepReport, error) + + FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAStaleUpkeepReportIterator, error) + + WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAStaleUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryLogicAStaleUpkeepReport, error) + + FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryLogicAUnpausedIterator, error) + + WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUnpaused) (event.Subscription, error) + + ParseUnpaused(log types.Log) (*AutomationRegistryLogicAUnpaused, error) + + FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicAUpkeepAdminTransferRequestedIterator, error) + + WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryLogicAUpkeepAdminTransferRequested, error) + + FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicAUpkeepAdminTransferredIterator, error) + + WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryLogicAUpkeepAdminTransferred, error) + + FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryLogicAUpkeepCanceledIterator, error) + + WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) + + ParseUpkeepCanceled(log types.Log) (*AutomationRegistryLogicAUpkeepCanceled, error) + + FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepCheckDataSetIterator, error) + + WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryLogicAUpkeepCheckDataSet, error) + + FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepGasLimitSetIterator, error) + + WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryLogicAUpkeepGasLimitSet, error) + + FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepMigratedIterator, error) + + WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepMigrated, id []*big.Int) (event.Subscription, error) + + ParseUpkeepMigrated(log types.Log) (*AutomationRegistryLogicAUpkeepMigrated, error) + + FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepOffchainConfigSetIterator, error) + + WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepOffchainConfigSet, error) + + FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepPausedIterator, error) + + WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPaused(log types.Log) (*AutomationRegistryLogicAUpkeepPaused, error) + + FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryLogicAUpkeepPerformedIterator, error) + + WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) + + ParseUpkeepPerformed(log types.Log) (*AutomationRegistryLogicAUpkeepPerformed, error) + + FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepPrivilegeConfigSetIterator, error) + + WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepPrivilegeConfigSet, error) + + FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepReceivedIterator, error) + + WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepReceived, id []*big.Int) (event.Subscription, error) + + ParseUpkeepReceived(log types.Log) (*AutomationRegistryLogicAUpkeepReceived, error) + + FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepRegisteredIterator, error) + + WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepRegistered, id []*big.Int) (event.Subscription, error) + + ParseUpkeepRegistered(log types.Log) (*AutomationRegistryLogicAUpkeepRegistered, error) + + FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepTriggerConfigSetIterator, error) + + WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryLogicAUpkeepTriggerConfigSet, error) + + FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicAUpkeepUnpausedIterator, error) + + WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicAUpkeepUnpaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryLogicAUpkeepUnpaused, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_2/keeper_registry_logic_b_wrapper_2_2.go b/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_2/keeper_registry_logic_b_wrapper_2_2.go new file mode 100644 index 00000000000..b12b24c204a --- /dev/null +++ b/core/gethwrappers/generated/keeper_registry_logic_b_wrapper_2_2/keeper_registry_logic_b_wrapper_2_2.go @@ -0,0 +1,5709 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package keeper_registry_logic_b_wrapper_2_2 + +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 AutomationRegistryBase22OnchainConfig struct { + PaymentPremiumPPB uint32 + FlatFeeMicroLink uint32 + CheckGasLimit uint32 + StalenessSeconds *big.Int + GasCeilingMultiplier uint16 + MinUpkeepSpend *big.Int + MaxPerformGas uint32 + MaxCheckDataSize uint32 + MaxPerformDataSize uint32 + MaxRevertDataSize uint32 + FallbackGasPrice *big.Int + FallbackLinkPrice *big.Int + Transcoder common.Address + Registrars []common.Address + UpkeepPrivilegeManager common.Address + ReorgProtectionEnabled bool +} + +type AutomationRegistryBase22State struct { + Nonce uint32 + OwnerLinkBalance *big.Int + ExpectedLinkBalance *big.Int + TotalPremium *big.Int + NumUpkeeps *big.Int + ConfigCount uint32 + LatestConfigBlockNumber uint32 + LatestConfigDigest [32]byte + LatestEpoch uint32 + Paused bool +} + +type AutomationRegistryBase22UpkeepInfo struct { + Target common.Address + PerformGas uint32 + CheckData []byte + Balance *big.Int + Admin common.Address + MaxValidBlocknumber uint64 + LastPerformedBlockNumber uint32 + AmountSpent *big.Int + Paused bool + OffchainConfig []byte +} + +var AutomationRegistryLogicBMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"enumAutomationRegistryBase2_2.Mode\",\"name\":\"mode\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkNativeFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"fastGasFeed\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"automationForwarderLogic\",\"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\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"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\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"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\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"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\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"DedupKeyAdded\",\"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\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"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\"},{\"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\":\"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\":\"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\":[],\"name\":\"getCancellationDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConditionalGasOverhead\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"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\":\"contractIAutomationForwarder\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLinkNativeFeedAddress\",\"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\":\"enumAutomationRegistryBase2_2.Trigger\",\"name\":\"triggerType\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"gasLimit\",\"type\":\"uint32\"}],\"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\":\"getMode\",\"outputs\":[{\"internalType\":\"enumAutomationRegistryBase2_2.Mode\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"peer\",\"type\":\"address\"}],\"name\":\"getPeerRegistryMigrationPermission\",\"outputs\":[{\"internalType\":\"enumAutomationRegistryBase2_2.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\":[{\"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\":\"structAutomationRegistryBase2_2.State\",\"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\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"internalType\":\"structAutomationRegistryBase2_2.OnchainConfig\",\"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\":[{\"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\":\"enumAutomationRegistryBase2_2.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\":\"structAutomationRegistryBase2_2.UpkeepInfo\",\"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\":[{\"internalType\":\"bytes32\",\"name\":\"dedupKey\",\"type\":\"bytes32\"}],\"name\":\"hasDedupKey\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"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\":[],\"name\":\"recoverFunds\",\"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\":\"enumAutomationRegistryBase2_2.MigrationPermission\",\"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\":\"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\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"unpauseUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepTranscoderVersion\",\"outputs\":[{\"internalType\":\"enumUpkeepFormat\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"upkeepVersion\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"withdrawFunds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawOwnerFunds\",\"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\"}]", + Bin: "0x6101206040523480156200001257600080fd5b5060405162005081380380620050818339810160408190526200003591620001e9565b84848484843380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000121565b505050846002811115620000dc57620000dc6200025e565b60e0816002811115620000f357620000f36200025e565b9052506001600160a01b0393841660805291831660a052821660c05216610100525062000274945050505050565b336001600160a01b038216036200017b5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001e457600080fd5b919050565b600080600080600060a086880312156200020257600080fd5b8551600381106200021257600080fd5b94506200022260208701620001cc565b93506200023260408701620001cc565b92506200024260608701620001cc565b91506200025260808701620001cc565b90509295509295909350565b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e05161010051614d82620002ff6000396000610587015260008181610525015281816134090152818161398c0152613b1f0152600081816105f401526131fd01526000818161071c01526132d70152600081816107aa01528181611c6701528181611f3c015281816123a5015281816128b8015261293c0152614d826000f3fe608060405234801561001057600080fd5b50600436106103365760003560e01c806379ba5097116101b2578063b121e147116100f9578063ca30e603116100a2578063eb5dcd6c1161007c578063eb5dcd6c146107f4578063ed56b3e114610807578063f2fde38b1461087a578063faa3e9961461088d57600080fd5b8063ca30e603146107a8578063cd7f71b5146107ce578063d7632648146107e157600080fd5b8063b657bc9c116100d3578063b657bc9c1461076d578063b79550be14610780578063c7c3a19a1461078857600080fd5b8063b121e14714610740578063b148ab6b14610753578063b6511a2a1461076657600080fd5b80638dcf0fe71161015b578063aab9edd611610135578063aab9edd614610703578063abc76ae014610712578063b10b673c1461071a57600080fd5b80638dcf0fe7146106ca578063a710b221146106dd578063a72aa27e146106f057600080fd5b80638456cb591161018c5780638456cb59146106915780638765ecbe146106995780638da5cb5b146106ac57600080fd5b806379ba50971461063e57806379ea9943146106465780637d9b97e01461068957600080fd5b8063421d183b116102815780635165f2f51161022a5780636209e1e9116102045780636209e1e9146105df5780636709d0e5146105f2578063671d36ed14610618578063744bfe611461062b57600080fd5b80635165f2f5146105725780635425d8ac146105855780635b6aa71c146105cc57600080fd5b80634b4fd03b1161025b5780634b4fd03b146105235780634ca16c52146105495780635147cd591461055257600080fd5b8063421d183b1461047a57806344cb70b8146104e057806348013d7b1461051357600080fd5b80631a2af011116102e3578063232c1cc5116102bd578063232c1cc5146104585780633b9cce591461045f5780633f4ba83a1461047257600080fd5b80631a2af011146103d45780631e010439146103e7578063207b65161461044557600080fd5b80631865c57d116103145780631865c57d14610388578063187256e8146103a157806319d97a94146103b457600080fd5b8063050ee65d1461033b57806306e3b632146103535780630b7d33e614610373575b600080fd5b6201adb05b6040519081526020015b60405180910390f35b610366610361366004613eaa565b6108d3565b60405161034a9190613ecc565b610386610381366004613f59565b6109f0565b005b610390610aaa565b60405161034a95949392919061416a565b6103866103af3660046142a1565b610f0e565b6103c76103c23660046142de565b610f7f565b60405161034a9190614365565b6103866103e2366004614378565b611021565b6104286103f53660046142de565b6000908152600460205260409020600101546c0100000000000000000000000090046bffffffffffffffffffffffff1690565b6040516bffffffffffffffffffffffff909116815260200161034a565b6103c76104533660046142de565b611127565b6014610340565b61038661046d36600461439d565b611144565b61038661139a565b61048d610488366004614412565b611400565b60408051951515865260ff90941660208601526bffffffffffffffffffffffff9283169385019390935216606083015273ffffffffffffffffffffffffffffffffffffffff16608082015260a00161034a565b6105036104ee3660046142de565b60009081526008602052604090205460ff1690565b604051901515815260200161034a565b60005b60405161034a919061446e565b7f0000000000000000000000000000000000000000000000000000000000000000610516565b62015f90610340565b6105656105603660046142de565b61151f565b60405161034a9190614481565b6103866105803660046142de565b61152a565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161034a565b6104286105da3660046144ae565b6116a1565b6103c76105ed366004614412565b611839565b7f00000000000000000000000000000000000000000000000000000000000000006105a7565b6103866106263660046144e7565b61186d565b610386610639366004614378565b611947565b610386611d62565b6105a76106543660046142de565b6000908152600460205260409020546901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1690565b610386611e64565b610386611fbf565b6103866106a73660046142de565b612040565b60005473ffffffffffffffffffffffffffffffffffffffff166105a7565b6103866106d8366004613f59565b6121ba565b6103866106eb366004614523565b61220f565b6103866106fe366004614551565b612477565b6040516003815260200161034a565b611d4c610340565b7f00000000000000000000000000000000000000000000000000000000000000006105a7565b61038661074e366004614412565b61256c565b6103866107613660046142de565b612664565b6032610340565b61042861077b3660046142de565b612852565b61038661287f565b61079b6107963660046142de565b6129db565b60405161034a9190614574565b7f00000000000000000000000000000000000000000000000000000000000000006105a7565b6103866107dc366004613f59565b612dae565b6104286107ef3660046142de565b612e45565b610386610802366004614523565b612e50565b610861610815366004614412565b73ffffffffffffffffffffffffffffffffffffffff166000908152600c602090815260409182902082518084019093525460ff8082161515808552610100909204169290910182905291565b60408051921515835260ff90911660208301520161034a565b610386610888366004614412565b612fae565b6108c661089b366004614412565b73ffffffffffffffffffffffffffffffffffffffff166000908152601a602052604090205460ff1690565b60405161034a91906146ab565b606060006108e16002612fc2565b905080841061091c576040517f1390f2a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061092884866146ee565b905081811180610936575083155b6109405780610942565b815b905060006109508683614701565b67ffffffffffffffff81111561096857610968614714565b604051908082528060200260200182016040528015610991578160200160208202803683370190505b50905060005b81518110156109e4576109b56109ad88836146ee565b600290612fcc565b8282815181106109c7576109c7614743565b6020908102919091010152806109dc81614772565b915050610997565b50925050505b92915050565b6016546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff163314610a51576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152601d60205260409020610a6a82848361484c565b50827f2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae77698383604051610a9d929190614967565b60405180910390a2505050565b6040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152604080516102008101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e08201839052610100820183905261012082018390526101408201839052610160820183905261018082018390526101a08201526101c081018290526101e0810191909152604080516101408101825260155463ffffffff7401000000000000000000000000000000000000000082041682526bffffffffffffffffffffffff90811660208301526019549282019290925260125490911660608281019190915290819060009060808101610beb6002612fc2565b8152601554780100000000000000000000000000000000000000000000000080820463ffffffff9081166020808601919091527c01000000000000000000000000000000000000000000000000000000008404821660408087019190915260115460608088019190915260125474010000000000000000000000000000000000000000810485166080808a01919091527e01000000000000000000000000000000000000000000000000000000000000820460ff16151560a0998a01528351610200810185526c0100000000000000000000000080840488168252700100000000000000000000000000000000808504891697830197909752808a0488169582019590955296820462ffffff16928701929092527b01000000000000000000000000000000000000000000000000000000900461ffff16908501526014546bffffffffffffffffffffffff8116968501969096529304811660c083015260165480821660e08401526401000000008104821661010084015268010000000000000000900416610120820152601754610140820152601854610160820152910473ffffffffffffffffffffffffffffffffffffffff166101808201529095506101a08101610db86009612fdf565b81526016546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1660208083019190915260135460ff9081161515604093840152601254600d80548551818602810186019096528086529599508a958a959194600e947d01000000000000000000000000000000000000000000000000000000000090940490931692859190830182828015610e8d57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e62575b5050505050925081805480602002602001604051908101604052809291908181526020018280548015610ef657602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610ecb575b50505050509150945094509450945094509091929394565b610f16612fec565b73ffffffffffffffffffffffffffffffffffffffff82166000908152601a6020526040902080548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836003811115610f7657610f7661442f565b02179055505050565b6000818152601d60205260409020805460609190610f9c906147aa565b80601f0160208091040260200160405190810160405280929190818152602001828054610fc8906147aa565b80156110155780601f10610fea57610100808354040283529160200191611015565b820191906000526020600020905b815481529060010190602001808311610ff857829003601f168201915b50505050509050919050565b61102a8261306f565b3373ffffffffffffffffffffffffffffffffffffffff821603611079576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff8281169116146111235760008281526006602052604080822080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff851690811790915590519091339185917fb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b3591a45b5050565b6000818152601b60205260409020805460609190610f9c906147aa565b61114c612fec565b600e548114611187576040517fcf54c06a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b600e54811015611359576000600e82815481106111a9576111a9614743565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff908116808452600f909252604083205491935016908585858181106111f3576111f3614743565b90506020020160208101906112089190614412565b905073ffffffffffffffffffffffffffffffffffffffff8116158061129b575073ffffffffffffffffffffffffffffffffffffffff82161580159061127957508073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b801561129b575073ffffffffffffffffffffffffffffffffffffffff81811614155b156112d2576040517fb387a23800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff818116146113435773ffffffffffffffffffffffffffffffffffffffff8381166000908152600f6020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169183169190911790555b505050808061135190614772565b91505061118a565b507fa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725600e838360405161138e939291906149b4565b60405180910390a15050565b6113a2612fec565b601280547fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020015b60405180910390a1565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e0100000000000000000000000000009004909116606082015282918291829182919082906114c65760608201516012546000916114b2916bffffffffffffffffffffffff16614a66565b600e549091506114c29082614aba565b9150505b8151602083015160408401516114dd908490614ae5565b6060949094015173ffffffffffffffffffffffffffffffffffffffff9a8b166000908152600f6020526040902054929b919a9499509750921694509092505050565b60006109ea82613123565b6115338161306f565b600081815260046020908152604091829020825160e081018452815460ff8116151580835263ffffffff610100830481169584019590955265010000000000820485169583019590955273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c082015290611632576040517f1b88a78400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556116716002836131ce565b5060405182907f7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a4745690600090a25050565b60408051610140810182526012546bffffffffffffffffffffffff8116825263ffffffff6c010000000000000000000000008204811660208401527001000000000000000000000000000000008204811693830193909352740100000000000000000000000000000000000000008104909216606082015262ffffff7801000000000000000000000000000000000000000000000000830416608082015261ffff7b0100000000000000000000000000000000000000000000000000000083041660a082015260ff7d0100000000000000000000000000000000000000000000000000000000008304811660c08301527e0100000000000000000000000000000000000000000000000000000000000083048116151560e08301527f01000000000000000000000000000000000000000000000000000000000000009092048216151561010082015260135490911615156101208201526000908180611806836131da565b9150915061182f838787601460020160049054906101000a900463ffffffff16868660006133b8565b9695505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152601e60205260409020805460609190610f9c906147aa565b6016546c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1633146118ce576040517f77c3599200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83166000908152601e602052604090206118fe82848361484c565b508273ffffffffffffffffffffffffffffffffffffffff167f7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d28383604051610a9d929190614967565b6012547f0100000000000000000000000000000000000000000000000000000000000000900460ff16156119a7576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f010000000000000000000000000000000000000000000000000000000000000017905573ffffffffffffffffffffffffffffffffffffffff8116611a3d576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000828152600460209081526040808320815160e081018352815460ff81161515825263ffffffff610100820481168387015265010000000000820481168386015273ffffffffffffffffffffffffffffffffffffffff6901000000000000000000909204821660608401526001909301546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a08401527801000000000000000000000000000000000000000000000000900490921660c082015286855260059093529220549091163314611b44576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b4c613403565b816040015163ffffffff161115611b8f576040517fff84e5dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600460205260409020600101546019546c010000000000000000000000009091046bffffffffffffffffffffffff1690611bcf908290614701565b60195560008481526004602081905260409182902060010180547fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff16905590517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116928201929092526bffffffffffffffffffffffff831660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015611cb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd69190614b0a565b50604080516bffffffffffffffffffffffff8316815273ffffffffffffffffffffffffffffffffffffffff8516602082015285917ff3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318910160405180910390a25050601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690555050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611de8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611e6c612fec565b6015546019546bffffffffffffffffffffffff90911690611e8e908290614701565b601955601580547fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001690556040516bffffffffffffffffffffffff821681527f1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f19060200160405180910390a16040517fa9059cbb0000000000000000000000000000000000000000000000000000000081523360048201526bffffffffffffffffffffffff821660248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044015b6020604051808303816000875af1158015611f9b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111239190614b0a565b611fc7612fec565b601280547fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e010000000000000000000000000000000000000000000000000000000000001790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258906020016113f6565b6120498161306f565b600081815260046020908152604091829020825160e081018452815460ff8116158015835263ffffffff610100830481169584019590955265010000000000820485169583019590955273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c082015290612148576040517f514b6c2400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600082815260046020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561218a6002836134b8565b5060405182907f8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f90600090a25050565b6121c38361306f565b6000838152601c602052604090206121dc82848361484c565b50827f3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf48508383604051610a9d929190614967565b73ffffffffffffffffffffffffffffffffffffffff811661225c576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600f60205260409020541633146122bc576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e546000916122df9185916bffffffffffffffffffffffff16906134c4565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600b6020526040902080547fffffffffffffffffffffffffffffffffffff000000000000000000000000ffff169055601954909150612349906bffffffffffffffffffffffff831690614701565b6019556040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526bffffffffffffffffffffffff831660248301527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af11580156123ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124129190614b0a565b5060405133815273ffffffffffffffffffffffffffffffffffffffff808416916bffffffffffffffffffffffff8416918616907f9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f406989060200160405180910390a4505050565b6108fc8163ffffffff1610806124ac575060155463ffffffff7001000000000000000000000000000000009091048116908216115b156124e3576040517f14c237fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6124ec8261306f565b60008281526004602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000ff1661010063ffffffff861690810291909117909155915191825283917fc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c910160405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff8181166000908152601060205260409020541633146125cc576040517f6752e7aa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8181166000818152600f602090815260408083208054337fffffffffffffffffffffffff000000000000000000000000000000000000000080831682179093556010909452828520805490921690915590519416939092849290917f78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b39190a45050565b600081815260046020908152604091829020825160e081018452815460ff81161515825263ffffffff6101008204811694830194909452650100000000008104841694820185905273ffffffffffffffffffffffffffffffffffffffff69010000000000000000009091041660608201526001909101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a083015278010000000000000000000000000000000000000000000000009004821660c08201529114612761576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526006602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146127be576040517f6352a85300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008281526005602090815260408083208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821790935560069094528285208054909216909155905173ffffffffffffffffffffffffffffffffffffffff90911692839186917f5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c91a4505050565b60006109ea61286083613123565b600084815260046020526040902054610100900463ffffffff166116a1565b612887612fec565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612914573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129389190614b2c565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33601954846129859190614701565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401611f7c565b604080516101408101825260008082526020820181905260609282018390528282018190526080820181905260a0820181905260c0820181905260e082018190526101008201526101208101919091526000828152600460209081526040808320815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606083018190526001909101546bffffffffffffffffffffffff80821660808501526c0100000000000000000000000082041660a08401527801000000000000000000000000000000000000000000000000900490921660c0820152919015612b7357816060015173ffffffffffffffffffffffffffffffffffffffff1663f00e6a2a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b6e9190614b45565b612b76565b60005b90506040518061014001604052808273ffffffffffffffffffffffffffffffffffffffff168152602001836020015163ffffffff168152602001600760008781526020019081526020016000208054612bce906147aa565b80601f0160208091040260200160405190810160405280929190818152602001828054612bfa906147aa565b8015612c475780601f10612c1c57610100808354040283529160200191612c47565b820191906000526020600020905b815481529060010190602001808311612c2a57829003601f168201915b505050505081526020018360a001516bffffffffffffffffffffffff1681526020016005600087815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001836040015163ffffffff1667ffffffffffffffff1681526020018360c0015163ffffffff16815260200183608001516bffffffffffffffffffffffff168152602001836000015115158152602001601c60008781526020019081526020016000208054612d24906147aa565b80601f0160208091040260200160405190810160405280929190818152602001828054612d50906147aa565b8015612d9d5780601f10612d7257610100808354040283529160200191612d9d565b820191906000526020600020905b815481529060010190602001808311612d8057829003601f168201915b505050505081525092505050919050565b612db78361306f565b60165463ffffffff16811115612df9576040517fae7235df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000838152600760205260409020612e1282848361484c565b50827fcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d8383604051610a9d929190614967565b60006109ea82612852565b73ffffffffffffffffffffffffffffffffffffffff8281166000908152600f6020526040902054163314612eb0576040517fcebf515b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821603612eff576040517f8c8728c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8281166000908152601060205260409020548116908216146111235773ffffffffffffffffffffffffffffffffffffffff82811660008181526010602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169486169485179055513392917f84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e3836791a45050565b612fb6612fec565b612fbf816136cc565b50565b60006109ea825490565b6000612fd883836137c1565b9392505050565b60606000612fd8836137eb565b60005473ffffffffffffffffffffffffffffffffffffffff16331461306d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401611ddf565b565b60008181526005602052604090205473ffffffffffffffffffffffffffffffffffffffff1633146130cc576040517fa47c170600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090205465010000000000900463ffffffff90811614612fbf576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000818160045b600f8110156131b0577fff00000000000000000000000000000000000000000000000000000000000000821683826020811061316857613168614743565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461319e57506000949350505050565b806131a881614772565b91505061312a565b5081600f1a60018111156131c6576131c661442f565b949350505050565b6000612fd88383613846565b6000806000836080015162ffffff1690506000808263ffffffff161190506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613266573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061328a9190614b7c565b50945090925050506000811315806132a157508142105b806132c257508280156132c257506132b98242614701565b8463ffffffff16105b156132d15760175495506132d5565b8095505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613340573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133649190614b7c565b509450909250505060008113158061337b57508142105b8061339c575082801561339c57506133938242614701565b8463ffffffff16105b156133ab5760185494506133af565b8094505b50505050915091565b6000806133ca88878b60c00151613895565b90506000806133e58b8a63ffffffff16858a8a60018b613957565b90925090506133f48183614ae5565b9b9a5050505050505050505050565b600060017f000000000000000000000000000000000000000000000000000000000000000060028111156134395761343961442f565b036134b357606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561348a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134ae9190614b2c565b905090565b504390565b6000612fd88383613db0565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e01000000000000000000000000000090049091166060820152906136c057600081606001518561355c9190614a66565b9050600061356a8583614aba565b9050808360400181815161357e9190614ae5565b6bffffffffffffffffffffffff169052506135998582614bcc565b836060018181516135aa9190614ae5565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361374b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401611ddf565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008260000182815481106137d8576137d8614743565b9060005260206000200154905092915050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561101557602002820191906000526020600020905b8154815260200190600101908083116138275750505050509050919050565b600081815260018301602052604081205461388d575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556109ea565b5060006109ea565b600080808560018111156138ab576138ab61442f565b036138ba575062015f9061390f565b60018560018111156138ce576138ce61442f565b036138dd57506201adb061390f565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61392063ffffffff85166014614c00565b61392b846001614c3d565b61393a9060ff16611d4c614c00565b61394490836146ee565b61394e91906146ee565b95945050505050565b60008060008960a0015161ffff16876139709190614c00565b905083801561397e5750803a105b1561398657503a5b600060027f000000000000000000000000000000000000000000000000000000000000000060028111156139bc576139bc61442f565b03613b1b576040805160008152602081019091528515613a1a57600036604051806080016040528060488152602001614d2e60489139604051602001613a0493929190614c56565b6040516020818303038152906040529050613a82565b601654613a3690640100000000900463ffffffff166004614c7d565b63ffffffff1667ffffffffffffffff811115613a5457613a54614714565b6040519080825280601f01601f191660200182016040528015613a7e576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e90613ad2908490600401614365565b602060405180830381865afa158015613aef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b139190614b2c565b915050613c75565b60017f00000000000000000000000000000000000000000000000000000000000000006002811115613b4f57613b4f61442f565b03613c75578415613bd157606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ba6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bca9190614b2c565b9050613c75565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa158015613c1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c439190614ca0565b5050601654929450613c6693505050640100000000900463ffffffff1682614c00565b613c71906010614c00565b9150505b84613c9157808b60a0015161ffff16613c8e9190614c00565b90505b613c9f61ffff871682614cea565b905060008782613caf8c8e6146ee565b613cb99086614c00565b613cc391906146ee565b613cd590670de0b6b3a7640000614c00565b613cdf9190614cea565b905060008c6040015163ffffffff1664e8d4a51000613cfe9190614c00565b898e6020015163ffffffff16858f88613d179190614c00565b613d2191906146ee565b613d2f90633b9aca00614c00565b613d399190614c00565b613d439190614cea565b613d4d91906146ee565b90506b033b2e3c9fd0803ce8000000613d6682846146ee565b1115613d9e576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b60008181526001830160205260408120548015613e99576000613dd4600183614701565b8554909150600090613de890600190614701565b9050818114613e4d576000866000018281548110613e0857613e08614743565b9060005260206000200154905080876000018481548110613e2b57613e2b614743565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080613e5e57613e5e614cfe565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506109ea565b60009150506109ea565b5092915050565b60008060408385031215613ebd57600080fd5b50508035926020909101359150565b6020808252825182820181905260009190848201906040850190845b81811015613f0457835183529284019291840191600101613ee8565b50909695505050505050565b60008083601f840112613f2257600080fd5b50813567ffffffffffffffff811115613f3a57600080fd5b602083019150836020828501011115613f5257600080fd5b9250929050565b600080600060408486031215613f6e57600080fd5b83359250602084013567ffffffffffffffff811115613f8c57600080fd5b613f9886828701613f10565b9497909650939450505050565b600081518084526020808501945080840160005b83811015613feb57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613fb9565b509495945050505050565b805163ffffffff1682526000610200602083015161401c602086018263ffffffff169052565b506040830151614034604086018263ffffffff169052565b50606083015161404b606086018262ffffff169052565b506080830151614061608086018261ffff169052565b5060a083015161408160a08601826bffffffffffffffffffffffff169052565b5060c083015161409960c086018263ffffffff169052565b5060e08301516140b160e086018263ffffffff169052565b506101008381015163ffffffff908116918601919091526101208085015190911690850152610140808401519085015261016080840151908501526101808084015173ffffffffffffffffffffffffffffffffffffffff16908501526101a08084015181860183905261412683870182613fa5565b925050506101c0808401516141528287018273ffffffffffffffffffffffffffffffffffffffff169052565b50506101e09283015115159390920192909252919050565b855163ffffffff16815260006101c0602088015161419860208501826bffffffffffffffffffffffff169052565b506040880151604084015260608801516141c260608501826bffffffffffffffffffffffff169052565b506080880151608084015260a08801516141e460a085018263ffffffff169052565b5060c08801516141fc60c085018263ffffffff169052565b5060e088015160e08401526101008089015161421f8286018263ffffffff169052565b505061012088810151151590840152610140830181905261424281840188613ff6565b90508281036101608401526142578187613fa5565b905082810361018084015261426c8186613fa5565b91505061182f6101a083018460ff169052565b73ffffffffffffffffffffffffffffffffffffffff81168114612fbf57600080fd5b600080604083850312156142b457600080fd5b82356142bf8161427f565b91506020830135600481106142d357600080fd5b809150509250929050565b6000602082840312156142f057600080fd5b5035919050565b60005b838110156143125781810151838201526020016142fa565b50506000910152565b600081518084526143338160208601602086016142f7565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000612fd8602083018461431b565b6000806040838503121561438b57600080fd5b8235915060208301356142d38161427f565b600080602083850312156143b057600080fd5b823567ffffffffffffffff808211156143c857600080fd5b818501915085601f8301126143dc57600080fd5b8135818111156143eb57600080fd5b8660208260051b850101111561440057600080fd5b60209290920196919550909350505050565b60006020828403121561442457600080fd5b8135612fd88161427f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60038110612fbf57612fbf61442f565b6020810161447b8361445e565b91905290565b602081016002831061447b5761447b61442f565b803563ffffffff811681146144a957600080fd5b919050565b600080604083850312156144c157600080fd5b8235600281106144d057600080fd5b91506144de60208401614495565b90509250929050565b6000806000604084860312156144fc57600080fd5b83356145078161427f565b9250602084013567ffffffffffffffff811115613f8c57600080fd5b6000806040838503121561453657600080fd5b82356145418161427f565b915060208301356142d38161427f565b6000806040838503121561456457600080fd5b823591506144de60208401614495565b6020815261459b60208201835173ffffffffffffffffffffffffffffffffffffffff169052565b600060208301516145b4604084018263ffffffff169052565b5060408301516101408060608501526145d161016085018361431b565b915060608501516145f260808601826bffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015163ffffffff811660e08601525060e085015161010061465e818701836bffffffffffffffffffffffff169052565b86015190506101206146738682018315159052565b8601518584037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00183870152905061182f838261431b565b602081016004831061447b5761447b61442f565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b808201808211156109ea576109ea6146bf565b818103818111156109ea576109ea6146bf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036147a3576147a36146bf565b5060010190565b600181811c908216806147be57607f821691505b6020821081036147f7577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f82111561484757600081815260208120601f850160051c810160208610156148245750805b601f850160051c820191505b8181101561484357828155600101614830565b5050505b505050565b67ffffffffffffffff83111561486457614864614714565b6148788361487283546147aa565b836147fd565b6000601f8411600181146148ca57600085156148945750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355614960565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101561491957868501358255602094850194600190920191016148f9565b5086821015614954577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b6000604082016040835280865480835260608501915087600052602092508260002060005b82811015614a0b57815473ffffffffffffffffffffffffffffffffffffffff16845292840192600191820191016149d9565b505050838103828501528481528590820160005b86811015614a5a578235614a328161427f565b73ffffffffffffffffffffffffffffffffffffffff1682529183019190830190600101614a1f565b50979650505050505050565b6bffffffffffffffffffffffff828116828216039080821115613ea357613ea36146bf565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006bffffffffffffffffffffffff80841680614ad957614ad9614a8b565b92169190910492915050565b6bffffffffffffffffffffffff818116838216019080821115613ea357613ea36146bf565b600060208284031215614b1c57600080fd5b81518015158114612fd857600080fd5b600060208284031215614b3e57600080fd5b5051919050565b600060208284031215614b5757600080fd5b8151612fd88161427f565b805169ffffffffffffffffffff811681146144a957600080fd5b600080600080600060a08688031215614b9457600080fd5b614b9d86614b62565b9450602086015193506040860151925060608601519150614bc060808701614b62565b90509295509295909350565b60006bffffffffffffffffffffffff80831681851681830481118215151615614bf757614bf76146bf565b02949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615614c3857614c386146bf565b500290565b60ff81811683821601908111156109ea576109ea6146bf565b828482376000838201600081528351614c738183602088016142f7565b0195945050505050565b600063ffffffff80831681851681830481118215151615614bf757614bf76146bf565b60008060008060008060c08789031215614cb957600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b600082614cf957614cf9614a8b565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", +} + +var AutomationRegistryLogicBABI = AutomationRegistryLogicBMetaData.ABI + +var AutomationRegistryLogicBBin = AutomationRegistryLogicBMetaData.Bin + +func DeployAutomationRegistryLogicB(auth *bind.TransactOpts, backend bind.ContractBackend, mode uint8, link common.Address, linkNativeFeed common.Address, fastGasFeed common.Address, automationForwarderLogic common.Address) (common.Address, *types.Transaction, *AutomationRegistryLogicB, error) { + parsed, err := AutomationRegistryLogicBMetaData.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(AutomationRegistryLogicBBin), backend, mode, link, linkNativeFeed, fastGasFeed, automationForwarderLogic) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationRegistryLogicB{address: address, abi: *parsed, AutomationRegistryLogicBCaller: AutomationRegistryLogicBCaller{contract: contract}, AutomationRegistryLogicBTransactor: AutomationRegistryLogicBTransactor{contract: contract}, AutomationRegistryLogicBFilterer: AutomationRegistryLogicBFilterer{contract: contract}}, nil +} + +type AutomationRegistryLogicB struct { + address common.Address + abi abi.ABI + AutomationRegistryLogicBCaller + AutomationRegistryLogicBTransactor + AutomationRegistryLogicBFilterer +} + +type AutomationRegistryLogicBCaller struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicBTransactor struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicBFilterer struct { + contract *bind.BoundContract +} + +type AutomationRegistryLogicBSession struct { + Contract *AutomationRegistryLogicB + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationRegistryLogicBCallerSession struct { + Contract *AutomationRegistryLogicBCaller + CallOpts bind.CallOpts +} + +type AutomationRegistryLogicBTransactorSession struct { + Contract *AutomationRegistryLogicBTransactor + TransactOpts bind.TransactOpts +} + +type AutomationRegistryLogicBRaw struct { + Contract *AutomationRegistryLogicB +} + +type AutomationRegistryLogicBCallerRaw struct { + Contract *AutomationRegistryLogicBCaller +} + +type AutomationRegistryLogicBTransactorRaw struct { + Contract *AutomationRegistryLogicBTransactor +} + +func NewAutomationRegistryLogicB(address common.Address, backend bind.ContractBackend) (*AutomationRegistryLogicB, error) { + abi, err := abi.JSON(strings.NewReader(AutomationRegistryLogicBABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationRegistryLogicB(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicB{address: address, abi: abi, AutomationRegistryLogicBCaller: AutomationRegistryLogicBCaller{contract: contract}, AutomationRegistryLogicBTransactor: AutomationRegistryLogicBTransactor{contract: contract}, AutomationRegistryLogicBFilterer: AutomationRegistryLogicBFilterer{contract: contract}}, nil +} + +func NewAutomationRegistryLogicBCaller(address common.Address, caller bind.ContractCaller) (*AutomationRegistryLogicBCaller, error) { + contract, err := bindAutomationRegistryLogicB(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBCaller{contract: contract}, nil +} + +func NewAutomationRegistryLogicBTransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationRegistryLogicBTransactor, error) { + contract, err := bindAutomationRegistryLogicB(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBTransactor{contract: contract}, nil +} + +func NewAutomationRegistryLogicBFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationRegistryLogicBFilterer, error) { + contract, err := bindAutomationRegistryLogicB(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBFilterer{contract: contract}, nil +} + +func bindAutomationRegistryLogicB(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationRegistryLogicBMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistryLogicB.Contract.AutomationRegistryLogicBCaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AutomationRegistryLogicBTransactor.contract.Transfer(opts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AutomationRegistryLogicBTransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistryLogicB.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.contract.Transfer(opts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getActiveUpkeepIDs", startIndex, maxCount) + + if err != nil { + return *new([]*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new([]*big.Int)).(*[]*big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetActiveUpkeepIDs(startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetActiveUpkeepIDs(&_AutomationRegistryLogicB.CallOpts, startIndex, maxCount) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetActiveUpkeepIDs(startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetActiveUpkeepIDs(&_AutomationRegistryLogicB.CallOpts, startIndex, maxCount) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetAdminPrivilegeConfig(opts *bind.CallOpts, admin common.Address) ([]byte, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getAdminPrivilegeConfig", admin) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetAdminPrivilegeConfig(admin common.Address) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetAdminPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, admin) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetAdminPrivilegeConfig(admin common.Address) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetAdminPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, admin) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetAutomationForwarderLogic(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getAutomationForwarderLogic") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetAutomationForwarderLogic() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetAutomationForwarderLogic(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetAutomationForwarderLogic() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetAutomationForwarderLogic(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getBalance", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetBalance(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetBalance(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetBalance(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetBalance(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetCancellationDelay(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getCancellationDelay") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetCancellationDelay() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetCancellationDelay(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetCancellationDelay() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetCancellationDelay(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getConditionalGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetConditionalGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetConditionalGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetConditionalGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetConditionalGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getFastGasFeedAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetFastGasFeedAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetFastGasFeedAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetFastGasFeedAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetFastGasFeedAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getForwarder", upkeepID) + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetForwarder(upkeepID *big.Int) (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetForwarder(&_AutomationRegistryLogicB.CallOpts, upkeepID) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetForwarder(upkeepID *big.Int) (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetForwarder(&_AutomationRegistryLogicB.CallOpts, upkeepID) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetLinkAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getLinkAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetLinkAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetLinkAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetLinkAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetLinkAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetLinkNativeFeedAddress(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getLinkNativeFeedAddress") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetLinkNativeFeedAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetLinkNativeFeedAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetLinkNativeFeedAddress() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.GetLinkNativeFeedAddress(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getLogGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetLogGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetLogGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetLogGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetLogGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMaxPaymentForGas", triggerType, gasLimit) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMaxPaymentForGas(&_AutomationRegistryLogicB.CallOpts, triggerType, gasLimit) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMaxPaymentForGas(triggerType uint8, gasLimit uint32) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMaxPaymentForGas(&_AutomationRegistryLogicB.CallOpts, triggerType, gasLimit) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMinBalance", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMinBalance(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMinBalance(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMinBalance(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMinBalance(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMinBalanceForUpkeep(opts *bind.CallOpts, id *big.Int) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMinBalanceForUpkeep", id) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMinBalanceForUpkeep(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMinBalanceForUpkeep(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMinBalanceForUpkeep(id *big.Int) (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetMinBalanceForUpkeep(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetMode(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getMode") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetMode() (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetMode(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetMode() (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetMode(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getPeerRegistryMigrationPermission", peer) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetPeerRegistryMigrationPermission(peer common.Address) (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.CallOpts, peer) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetPeerRegistryMigrationPermission(peer common.Address) (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.CallOpts, peer) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getPerPerformByteGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetPerPerformByteGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetPerPerformByteGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetPerPerformByteGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetPerPerformByteGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetPerSignerGasOverhead(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getPerSignerGasOverhead") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetPerSignerGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetPerSignerGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetPerSignerGasOverhead() (*big.Int, error) { + return _AutomationRegistryLogicB.Contract.GetPerSignerGasOverhead(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, + + error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getSignerInfo", query) + + outstruct := new(GetSignerInfo) + if err != nil { + return *outstruct, err + } + + outstruct.Active = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Index = *abi.ConvertType(out[1], new(uint8)).(*uint8) + + return *outstruct, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetSignerInfo(query common.Address) (GetSignerInfo, + + error) { + return _AutomationRegistryLogicB.Contract.GetSignerInfo(&_AutomationRegistryLogicB.CallOpts, query) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetSignerInfo(query common.Address) (GetSignerInfo, + + error) { + return _AutomationRegistryLogicB.Contract.GetSignerInfo(&_AutomationRegistryLogicB.CallOpts, query) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetState(opts *bind.CallOpts) (GetState, + + error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getState") + + outstruct := new(GetState) + if err != nil { + return *outstruct, err + } + + outstruct.State = *abi.ConvertType(out[0], new(AutomationRegistryBase22State)).(*AutomationRegistryBase22State) + outstruct.Config = *abi.ConvertType(out[1], new(AutomationRegistryBase22OnchainConfig)).(*AutomationRegistryBase22OnchainConfig) + outstruct.Signers = *abi.ConvertType(out[2], new([]common.Address)).(*[]common.Address) + outstruct.Transmitters = *abi.ConvertType(out[3], new([]common.Address)).(*[]common.Address) + outstruct.F = *abi.ConvertType(out[4], new(uint8)).(*uint8) + + return *outstruct, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetState() (GetState, + + error) { + return _AutomationRegistryLogicB.Contract.GetState(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetState() (GetState, + + error) { + return _AutomationRegistryLogicB.Contract.GetState(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetTransmitterInfo(opts *bind.CallOpts, query common.Address) (GetTransmitterInfo, + + error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getTransmitterInfo", query) + + outstruct := new(GetTransmitterInfo) + if err != nil { + return *outstruct, err + } + + outstruct.Active = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.Index = *abi.ConvertType(out[1], new(uint8)).(*uint8) + outstruct.Balance = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.LastCollected = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.Payee = *abi.ConvertType(out[4], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetTransmitterInfo(query common.Address) (GetTransmitterInfo, + + error) { + return _AutomationRegistryLogicB.Contract.GetTransmitterInfo(&_AutomationRegistryLogicB.CallOpts, query) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetTransmitterInfo(query common.Address) (GetTransmitterInfo, + + error) { + return _AutomationRegistryLogicB.Contract.GetTransmitterInfo(&_AutomationRegistryLogicB.CallOpts, query) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getTriggerType", upkeepId) + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetTriggerType(upkeepId *big.Int) (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetTriggerType(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetTriggerType(upkeepId *big.Int) (uint8, error) { + return _AutomationRegistryLogicB.Contract.GetTriggerType(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getUpkeep", id) + + if err != nil { + return *new(AutomationRegistryBase22UpkeepInfo), err + } + + out0 := *abi.ConvertType(out[0], new(AutomationRegistryBase22UpkeepInfo)).(*AutomationRegistryBase22UpkeepInfo) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetUpkeep(id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeep(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetUpkeep(id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeep(&_AutomationRegistryLogicB.CallOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getUpkeepPrivilegeConfig", upkeepId) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "getUpkeepTriggerConfig", upkeepId) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) GetUpkeepTriggerConfig(upkeepId *big.Int) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeepTriggerConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) GetUpkeepTriggerConfig(upkeepId *big.Int) ([]byte, error) { + return _AutomationRegistryLogicB.Contract.GetUpkeepTriggerConfig(&_AutomationRegistryLogicB.CallOpts, upkeepId) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "hasDedupKey", dedupKey) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) HasDedupKey(dedupKey [32]byte) (bool, error) { + return _AutomationRegistryLogicB.Contract.HasDedupKey(&_AutomationRegistryLogicB.CallOpts, dedupKey) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) HasDedupKey(dedupKey [32]byte) (bool, error) { + return _AutomationRegistryLogicB.Contract.HasDedupKey(&_AutomationRegistryLogicB.CallOpts, dedupKey) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistryLogicB.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 (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Owner() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.Owner(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) Owner() (common.Address, error) { + return _AutomationRegistryLogicB.Contract.Owner(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "upkeepTranscoderVersion") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) UpkeepTranscoderVersion() (uint8, error) { + return _AutomationRegistryLogicB.Contract.UpkeepTranscoderVersion(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) UpkeepTranscoderVersion() (uint8, error) { + return _AutomationRegistryLogicB.Contract.UpkeepTranscoderVersion(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCaller) UpkeepVersion(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _AutomationRegistryLogicB.contract.Call(opts, &out, "upkeepVersion") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) UpkeepVersion() (uint8, error) { + return _AutomationRegistryLogicB.Contract.UpkeepVersion(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBCallerSession) UpkeepVersion() (uint8, error) { + return _AutomationRegistryLogicB.Contract.UpkeepVersion(&_AutomationRegistryLogicB.CallOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "acceptOwnership") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptOwnership(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptOwnership(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "acceptPayeeship", transmitter) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptPayeeship(transmitter common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "acceptUpkeepAdmin", id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) AcceptUpkeepAdmin(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.AcceptUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) Pause(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "pause") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Pause() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.Pause(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) Pause() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.Pause(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "pauseUpkeep", id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.PauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) PauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.PauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) RecoverFunds(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "recoverFunds") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) RecoverFunds() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.RecoverFunds(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) RecoverFunds() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.RecoverFunds(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setAdminPrivilegeConfig", admin, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetAdminPrivilegeConfig(admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetAdminPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, admin, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetAdminPrivilegeConfig(admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetAdminPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, admin, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetPayees(opts *bind.TransactOpts, payees []common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setPayees", payees) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetPayees(payees []common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetPayees(&_AutomationRegistryLogicB.TransactOpts, payees) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetPayees(payees []common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetPayees(&_AutomationRegistryLogicB.TransactOpts, payees) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetPeerRegistryMigrationPermission(opts *bind.TransactOpts, peer common.Address, permission uint8) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setPeerRegistryMigrationPermission", peer, permission) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetPeerRegistryMigrationPermission(peer common.Address, permission uint8) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.TransactOpts, peer, permission) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetPeerRegistryMigrationPermission(peer common.Address, permission uint8) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetPeerRegistryMigrationPermission(&_AutomationRegistryLogicB.TransactOpts, peer, permission) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepCheckData", id, newCheckData) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepCheckData(&_AutomationRegistryLogicB.TransactOpts, id, newCheckData) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepCheckData(id *big.Int, newCheckData []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepCheckData(&_AutomationRegistryLogicB.TransactOpts, id, newCheckData) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepGasLimit(opts *bind.TransactOpts, id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepGasLimit", id, gasLimit) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepGasLimit(&_AutomationRegistryLogicB.TransactOpts, id, gasLimit) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepGasLimit(id *big.Int, gasLimit uint32) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepGasLimit(&_AutomationRegistryLogicB.TransactOpts, id, gasLimit) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepOffchainConfig", id, config) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepOffchainConfig(&_AutomationRegistryLogicB.TransactOpts, id, config) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepOffchainConfig(id *big.Int, config []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepOffchainConfig(&_AutomationRegistryLogicB.TransactOpts, id, config) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) SetUpkeepPrivilegeConfig(opts *bind.TransactOpts, upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "setUpkeepPrivilegeConfig", upkeepId, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) SetUpkeepPrivilegeConfig(upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, upkeepId, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) SetUpkeepPrivilegeConfig(upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.SetUpkeepPrivilegeConfig(&_AutomationRegistryLogicB.TransactOpts, upkeepId, newPrivilegeConfig) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "transferOwnership", to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferOwnership(&_AutomationRegistryLogicB.TransactOpts, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferOwnership(&_AutomationRegistryLogicB.TransactOpts, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "transferPayeeship", transmitter, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferPayeeship(transmitter common.Address, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferPayeeship(&_AutomationRegistryLogicB.TransactOpts, transmitter, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "transferUpkeepAdmin", id, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) TransferUpkeepAdmin(id *big.Int, proposed common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.TransferUpkeepAdmin(&_AutomationRegistryLogicB.TransactOpts, id, proposed) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) Unpause(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "unpause") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) Unpause() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.Unpause(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) Unpause() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.Unpause(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "unpauseUpkeep", id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.UnpauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) UnpauseUpkeep(id *big.Int) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.UnpauseUpkeep(&_AutomationRegistryLogicB.TransactOpts, id) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawFunds", id, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawFunds(&_AutomationRegistryLogicB.TransactOpts, id, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawFunds(id *big.Int, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawFunds(&_AutomationRegistryLogicB.TransactOpts, id, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawOwnerFunds(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawOwnerFunds") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawOwnerFunds() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawOwnerFunds(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawOwnerFunds() (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawOwnerFunds(&_AutomationRegistryLogicB.TransactOpts) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactor) WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.contract.Transact(opts, "withdrawPayment", from, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawPayment(&_AutomationRegistryLogicB.TransactOpts, from, to) +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBTransactorSession) WithdrawPayment(from common.Address, to common.Address) (*types.Transaction, error) { + return _AutomationRegistryLogicB.Contract.WithdrawPayment(&_AutomationRegistryLogicB.TransactOpts, from, to) +} + +type AutomationRegistryLogicBAdminPrivilegeConfigSetIterator struct { + Event *AutomationRegistryLogicBAdminPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + 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(AutomationRegistryLogicBAdminPrivilegeConfigSet) + 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 *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBAdminPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBAdminPrivilegeConfigSet struct { + Admin common.Address + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicBAdminPrivilegeConfigSetIterator, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBAdminPrivilegeConfigSetIterator{contract: _AutomationRegistryLogicB.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "AdminPrivilegeConfigSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBAdminPrivilegeConfigSet, error) { + event := new(AutomationRegistryLogicBAdminPrivilegeConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBCancelledUpkeepReportIterator struct { + Event *AutomationRegistryLogicBCancelledUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBCancelledUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBCancelledUpkeepReport) + 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(AutomationRegistryLogicBCancelledUpkeepReport) + 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 *AutomationRegistryLogicBCancelledUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBCancelledUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBCancelledUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBCancelledUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBCancelledUpkeepReportIterator{contract: _AutomationRegistryLogicB.contract, event: "CancelledUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBCancelledUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "CancelledUpkeepReport", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryLogicBCancelledUpkeepReport, error) { + event := new(AutomationRegistryLogicBCancelledUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "CancelledUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBDedupKeyAddedIterator struct { + Event *AutomationRegistryLogicBDedupKeyAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBDedupKeyAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBDedupKeyAdded) + 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(AutomationRegistryLogicBDedupKeyAdded) + 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 *AutomationRegistryLogicBDedupKeyAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBDedupKeyAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBDedupKeyAdded struct { + DedupKey [32]byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryLogicBDedupKeyAddedIterator, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBDedupKeyAddedIterator{contract: _AutomationRegistryLogicB.contract, event: "DedupKeyAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBDedupKeyAdded) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "DedupKeyAdded", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseDedupKeyAdded(log types.Log) (*AutomationRegistryLogicBDedupKeyAdded, error) { + event := new(AutomationRegistryLogicBDedupKeyAdded) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "DedupKeyAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBFundsAddedIterator struct { + Event *AutomationRegistryLogicBFundsAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBFundsAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBFundsAdded) + 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(AutomationRegistryLogicBFundsAdded) + 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 *AutomationRegistryLogicBFundsAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBFundsAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBFundsAdded struct { + Id *big.Int + From common.Address + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryLogicBFundsAddedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBFundsAddedIterator{contract: _AutomationRegistryLogicB.contract, event: "FundsAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBFundsAdded) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "FundsAdded", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseFundsAdded(log types.Log) (*AutomationRegistryLogicBFundsAdded, error) { + event := new(AutomationRegistryLogicBFundsAdded) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "FundsAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBFundsWithdrawnIterator struct { + Event *AutomationRegistryLogicBFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBFundsWithdrawn) + 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(AutomationRegistryLogicBFundsWithdrawn) + 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 *AutomationRegistryLogicBFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBFundsWithdrawn struct { + Id *big.Int + Amount *big.Int + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBFundsWithdrawnIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBFundsWithdrawnIterator{contract: _AutomationRegistryLogicB.contract, event: "FundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFundsWithdrawn, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBFundsWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "FundsWithdrawn", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseFundsWithdrawn(log types.Log) (*AutomationRegistryLogicBFundsWithdrawn, error) { + event := new(AutomationRegistryLogicBFundsWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "FundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator struct { + Event *AutomationRegistryLogicBInsufficientFundsUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBInsufficientFundsUpkeepReport) + 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(AutomationRegistryLogicBInsufficientFundsUpkeepReport) + 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 *AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBInsufficientFundsUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator{contract: _AutomationRegistryLogicB.contract, event: "InsufficientFundsUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBInsufficientFundsUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryLogicBInsufficientFundsUpkeepReport, error) { + event := new(AutomationRegistryLogicBInsufficientFundsUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBOwnerFundsWithdrawnIterator struct { + Event *AutomationRegistryLogicBOwnerFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBOwnerFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBOwnerFundsWithdrawn) + 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(AutomationRegistryLogicBOwnerFundsWithdrawn) + 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 *AutomationRegistryLogicBOwnerFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBOwnerFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBOwnerFundsWithdrawn struct { + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryLogicBOwnerFundsWithdrawnIterator, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBOwnerFundsWithdrawnIterator{contract: _AutomationRegistryLogicB.contract, event: "OwnerFundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnerFundsWithdrawn) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBOwnerFundsWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "OwnerFundsWithdrawn", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryLogicBOwnerFundsWithdrawn, error) { + event := new(AutomationRegistryLogicBOwnerFundsWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "OwnerFundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBOwnershipTransferRequestedIterator struct { + Event *AutomationRegistryLogicBOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBOwnershipTransferRequested) + 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(AutomationRegistryLogicBOwnershipTransferRequested) + 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 *AutomationRegistryLogicBOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicBOwnershipTransferRequestedIterator, 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBOwnershipTransferRequestedIterator{contract: _AutomationRegistryLogicB.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnershipTransferRequested, 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 := _AutomationRegistryLogicB.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(AutomationRegistryLogicBOwnershipTransferRequested) + if err := _AutomationRegistryLogicB.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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryLogicBOwnershipTransferRequested, error) { + event := new(AutomationRegistryLogicBOwnershipTransferRequested) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBOwnershipTransferredIterator struct { + Event *AutomationRegistryLogicBOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBOwnershipTransferred) + 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(AutomationRegistryLogicBOwnershipTransferred) + 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 *AutomationRegistryLogicBOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicBOwnershipTransferredIterator, 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBOwnershipTransferredIterator{contract: _AutomationRegistryLogicB.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnershipTransferred, 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 := _AutomationRegistryLogicB.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(AutomationRegistryLogicBOwnershipTransferred) + if err := _AutomationRegistryLogicB.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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseOwnershipTransferred(log types.Log) (*AutomationRegistryLogicBOwnershipTransferred, error) { + event := new(AutomationRegistryLogicBOwnershipTransferred) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBPausedIterator struct { + Event *AutomationRegistryLogicBPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBPaused) + 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(AutomationRegistryLogicBPaused) + 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 *AutomationRegistryLogicBPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBPaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryLogicBPausedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "Paused") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBPausedIterator{contract: _AutomationRegistryLogicB.contract, event: "Paused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "Paused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBPaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "Paused", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParsePaused(log types.Log) (*AutomationRegistryLogicBPaused, error) { + event := new(AutomationRegistryLogicBPaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "Paused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBPayeesUpdatedIterator struct { + Event *AutomationRegistryLogicBPayeesUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBPayeesUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBPayeesUpdated) + 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(AutomationRegistryLogicBPayeesUpdated) + 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 *AutomationRegistryLogicBPayeesUpdatedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBPayeesUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBPayeesUpdated struct { + Transmitters []common.Address + Payees []common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryLogicBPayeesUpdatedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBPayeesUpdatedIterator{contract: _AutomationRegistryLogicB.contract, event: "PayeesUpdated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeesUpdated) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBPayeesUpdated) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeesUpdated", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParsePayeesUpdated(log types.Log) (*AutomationRegistryLogicBPayeesUpdated, error) { + event := new(AutomationRegistryLogicBPayeesUpdated) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeesUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBPayeeshipTransferRequestedIterator struct { + Event *AutomationRegistryLogicBPayeeshipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBPayeeshipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBPayeeshipTransferRequested) + 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(AutomationRegistryLogicBPayeeshipTransferRequested) + 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 *AutomationRegistryLogicBPayeeshipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBPayeeshipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBPayeeshipTransferRequested struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicBPayeeshipTransferRequestedIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "PayeeshipTransferRequested", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBPayeeshipTransferRequestedIterator{contract: _AutomationRegistryLogicB.contract, event: "PayeeshipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicB.contract.WatchLogs(opts, "PayeeshipTransferRequested", transmitterRule, 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(AutomationRegistryLogicBPayeeshipTransferRequested) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeeshipTransferRequested", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryLogicBPayeeshipTransferRequested, error) { + event := new(AutomationRegistryLogicBPayeeshipTransferRequested) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeeshipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBPayeeshipTransferredIterator struct { + Event *AutomationRegistryLogicBPayeeshipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBPayeeshipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBPayeeshipTransferred) + 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(AutomationRegistryLogicBPayeeshipTransferred) + 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 *AutomationRegistryLogicBPayeeshipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBPayeeshipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBPayeeshipTransferred struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicBPayeeshipTransferredIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "PayeeshipTransferred", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBPayeeshipTransferredIterator{contract: _AutomationRegistryLogicB.contract, event: "PayeeshipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistryLogicB.contract.WatchLogs(opts, "PayeeshipTransferred", transmitterRule, 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(AutomationRegistryLogicBPayeeshipTransferred) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeeshipTransferred", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryLogicBPayeeshipTransferred, error) { + event := new(AutomationRegistryLogicBPayeeshipTransferred) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PayeeshipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBPaymentWithdrawnIterator struct { + Event *AutomationRegistryLogicBPaymentWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBPaymentWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBPaymentWithdrawn) + 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(AutomationRegistryLogicBPaymentWithdrawn) + 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 *AutomationRegistryLogicBPaymentWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBPaymentWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBPaymentWithdrawn struct { + Transmitter common.Address + Amount *big.Int + To common.Address + Payee common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryLogicBPaymentWithdrawnIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBPaymentWithdrawnIterator{contract: _AutomationRegistryLogicB.contract, event: "PaymentWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, 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(AutomationRegistryLogicBPaymentWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PaymentWithdrawn", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryLogicBPaymentWithdrawn, error) { + event := new(AutomationRegistryLogicBPaymentWithdrawn) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "PaymentWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBReorgedUpkeepReportIterator struct { + Event *AutomationRegistryLogicBReorgedUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBReorgedUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBReorgedUpkeepReport) + 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(AutomationRegistryLogicBReorgedUpkeepReport) + 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 *AutomationRegistryLogicBReorgedUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBReorgedUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBReorgedUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBReorgedUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBReorgedUpkeepReportIterator{contract: _AutomationRegistryLogicB.contract, event: "ReorgedUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBReorgedUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "ReorgedUpkeepReport", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryLogicBReorgedUpkeepReport, error) { + event := new(AutomationRegistryLogicBReorgedUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "ReorgedUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBStaleUpkeepReportIterator struct { + Event *AutomationRegistryLogicBStaleUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBStaleUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBStaleUpkeepReport) + 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(AutomationRegistryLogicBStaleUpkeepReport) + 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 *AutomationRegistryLogicBStaleUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBStaleUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBStaleUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBStaleUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBStaleUpkeepReportIterator{contract: _AutomationRegistryLogicB.contract, event: "StaleUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBStaleUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBStaleUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "StaleUpkeepReport", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryLogicBStaleUpkeepReport, error) { + event := new(AutomationRegistryLogicBStaleUpkeepReport) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "StaleUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUnpausedIterator struct { + Event *AutomationRegistryLogicBUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUnpaused) + 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(AutomationRegistryLogicBUnpaused) + 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 *AutomationRegistryLogicBUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUnpaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryLogicBUnpausedIterator, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUnpausedIterator{contract: _AutomationRegistryLogicB.contract, event: "Unpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUnpaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUnpaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "Unpaused", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUnpaused(log types.Log) (*AutomationRegistryLogicBUnpaused, error) { + event := new(AutomationRegistryLogicBUnpaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "Unpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator struct { + Event *AutomationRegistryLogicBUpkeepAdminTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepAdminTransferRequested) + 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(AutomationRegistryLogicBUpkeepAdminTransferRequested) + 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 *AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepAdminTransferRequested struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepAdminTransferRequested", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepAdminTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepAdminTransferRequested", idRule, 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(AutomationRegistryLogicBUpkeepAdminTransferRequested) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepAdminTransferRequested", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryLogicBUpkeepAdminTransferRequested, error) { + event := new(AutomationRegistryLogicBUpkeepAdminTransferRequested) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepAdminTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepAdminTransferredIterator struct { + Event *AutomationRegistryLogicBUpkeepAdminTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepAdminTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepAdminTransferred) + 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(AutomationRegistryLogicBUpkeepAdminTransferred) + 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 *AutomationRegistryLogicBUpkeepAdminTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepAdminTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepAdminTransferred struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicBUpkeepAdminTransferredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepAdminTransferred", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepAdminTransferredIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepAdminTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepAdminTransferred", idRule, 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(AutomationRegistryLogicBUpkeepAdminTransferred) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepAdminTransferred", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryLogicBUpkeepAdminTransferred, error) { + event := new(AutomationRegistryLogicBUpkeepAdminTransferred) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepAdminTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepCanceledIterator struct { + Event *AutomationRegistryLogicBUpkeepCanceled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepCanceledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepCanceled) + 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(AutomationRegistryLogicBUpkeepCanceled) + 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 *AutomationRegistryLogicBUpkeepCanceledIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepCanceledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepCanceled struct { + Id *big.Int + AtBlockHeight uint64 + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryLogicBUpkeepCanceledIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepCanceledIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepCanceled", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepCanceled) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepCanceled", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepCanceled(log types.Log) (*AutomationRegistryLogicBUpkeepCanceled, error) { + event := new(AutomationRegistryLogicBUpkeepCanceled) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepCanceled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepCheckDataSetIterator struct { + Event *AutomationRegistryLogicBUpkeepCheckDataSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepCheckDataSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepCheckDataSet) + 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(AutomationRegistryLogicBUpkeepCheckDataSet) + 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 *AutomationRegistryLogicBUpkeepCheckDataSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepCheckDataSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepCheckDataSet struct { + Id *big.Int + NewCheckData []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepCheckDataSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepCheckDataSetIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepCheckDataSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepCheckDataSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepCheckDataSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryLogicBUpkeepCheckDataSet, error) { + event := new(AutomationRegistryLogicBUpkeepCheckDataSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepCheckDataSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepGasLimitSetIterator struct { + Event *AutomationRegistryLogicBUpkeepGasLimitSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepGasLimitSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepGasLimitSet) + 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(AutomationRegistryLogicBUpkeepGasLimitSet) + 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 *AutomationRegistryLogicBUpkeepGasLimitSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepGasLimitSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepGasLimitSet struct { + Id *big.Int + GasLimit *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepGasLimitSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepGasLimitSetIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepGasLimitSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepGasLimitSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepGasLimitSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryLogicBUpkeepGasLimitSet, error) { + event := new(AutomationRegistryLogicBUpkeepGasLimitSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepGasLimitSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepMigratedIterator struct { + Event *AutomationRegistryLogicBUpkeepMigrated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepMigratedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepMigrated) + 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(AutomationRegistryLogicBUpkeepMigrated) + 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 *AutomationRegistryLogicBUpkeepMigratedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepMigratedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepMigrated struct { + Id *big.Int + RemainingBalance *big.Int + Destination common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepMigratedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepMigratedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepMigrated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepMigrated, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepMigrated) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepMigrated", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepMigrated(log types.Log) (*AutomationRegistryLogicBUpkeepMigrated, error) { + event := new(AutomationRegistryLogicBUpkeepMigrated) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepMigrated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepOffchainConfigSetIterator struct { + Event *AutomationRegistryLogicBUpkeepOffchainConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepOffchainConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepOffchainConfigSet) + 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(AutomationRegistryLogicBUpkeepOffchainConfigSet) + 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 *AutomationRegistryLogicBUpkeepOffchainConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepOffchainConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepOffchainConfigSet struct { + Id *big.Int + OffchainConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepOffchainConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepOffchainConfigSetIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepOffchainConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepOffchainConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepOffchainConfigSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepOffchainConfigSet, error) { + event := new(AutomationRegistryLogicBUpkeepOffchainConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepOffchainConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepPausedIterator struct { + Event *AutomationRegistryLogicBUpkeepPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepPaused) + 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(AutomationRegistryLogicBUpkeepPaused) + 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 *AutomationRegistryLogicBUpkeepPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepPaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepPausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepPausedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepPaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepPaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPaused", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepPaused(log types.Log) (*AutomationRegistryLogicBUpkeepPaused, error) { + event := new(AutomationRegistryLogicBUpkeepPaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepPerformedIterator struct { + Event *AutomationRegistryLogicBUpkeepPerformed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepPerformedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepPerformed) + 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(AutomationRegistryLogicBUpkeepPerformed) + 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 *AutomationRegistryLogicBUpkeepPerformedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepPerformedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepPerformed struct { + Id *big.Int + Success bool + TotalPayment *big.Int + GasUsed *big.Int + GasOverhead *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryLogicBUpkeepPerformedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepPerformedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepPerformed", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepPerformed) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPerformed", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepPerformed(log types.Log) (*AutomationRegistryLogicBUpkeepPerformed, error) { + event := new(AutomationRegistryLogicBUpkeepPerformed) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPerformed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator struct { + Event *AutomationRegistryLogicBUpkeepPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepPrivilegeConfigSet) + 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(AutomationRegistryLogicBUpkeepPrivilegeConfigSet) + 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 *AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepPrivilegeConfigSet struct { + Id *big.Int + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepPrivilegeConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepPrivilegeConfigSet, error) { + event := new(AutomationRegistryLogicBUpkeepPrivilegeConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepReceivedIterator struct { + Event *AutomationRegistryLogicBUpkeepReceived + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepReceivedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepReceived) + 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(AutomationRegistryLogicBUpkeepReceived) + 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 *AutomationRegistryLogicBUpkeepReceivedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepReceivedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepReceived struct { + Id *big.Int + StartingBalance *big.Int + ImportedFrom common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepReceivedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepReceivedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepReceived", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepReceived, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepReceived) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepReceived", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepReceived(log types.Log) (*AutomationRegistryLogicBUpkeepReceived, error) { + event := new(AutomationRegistryLogicBUpkeepReceived) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepReceived", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepRegisteredIterator struct { + Event *AutomationRegistryLogicBUpkeepRegistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepRegisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepRegistered) + 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(AutomationRegistryLogicBUpkeepRegistered) + 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 *AutomationRegistryLogicBUpkeepRegisteredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepRegistered struct { + Id *big.Int + PerformGas uint32 + Admin common.Address + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepRegisteredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepRegisteredIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepRegistered", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepRegistered, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepRegistered) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepRegistered", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepRegistered(log types.Log) (*AutomationRegistryLogicBUpkeepRegistered, error) { + event := new(AutomationRegistryLogicBUpkeepRegistered) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepTriggerConfigSetIterator struct { + Event *AutomationRegistryLogicBUpkeepTriggerConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepTriggerConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepTriggerConfigSet) + 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(AutomationRegistryLogicBUpkeepTriggerConfigSet) + 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 *AutomationRegistryLogicBUpkeepTriggerConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepTriggerConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepTriggerConfigSet struct { + Id *big.Int + TriggerConfig []byte + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepTriggerConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepTriggerConfigSetIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepTriggerConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepTriggerConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepTriggerConfigSet", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepTriggerConfigSet, error) { + event := new(AutomationRegistryLogicBUpkeepTriggerConfigSet) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepTriggerConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryLogicBUpkeepUnpausedIterator struct { + Event *AutomationRegistryLogicBUpkeepUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryLogicBUpkeepUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryLogicBUpkeepUnpaused) + 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(AutomationRegistryLogicBUpkeepUnpaused) + 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 *AutomationRegistryLogicBUpkeepUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryLogicBUpkeepUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryLogicBUpkeepUnpaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepUnpausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.FilterLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryLogicBUpkeepUnpausedIterator{contract: _AutomationRegistryLogicB.contract, event: "UpkeepUnpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepUnpaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistryLogicB.contract.WatchLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryLogicBUpkeepUnpaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepUnpaused", 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 (_AutomationRegistryLogicB *AutomationRegistryLogicBFilterer) ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryLogicBUpkeepUnpaused, error) { + event := new(AutomationRegistryLogicBUpkeepUnpaused) + if err := _AutomationRegistryLogicB.contract.UnpackLog(event, "UpkeepUnpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type GetSignerInfo struct { + Active bool + Index uint8 +} +type GetState struct { + State AutomationRegistryBase22State + Config AutomationRegistryBase22OnchainConfig + Signers []common.Address + Transmitters []common.Address + F uint8 +} +type GetTransmitterInfo struct { + Active bool + Index uint8 + Balance *big.Int + LastCollected *big.Int + Payee common.Address +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicB) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _AutomationRegistryLogicB.abi.Events["AdminPrivilegeConfigSet"].ID: + return _AutomationRegistryLogicB.ParseAdminPrivilegeConfigSet(log) + case _AutomationRegistryLogicB.abi.Events["CancelledUpkeepReport"].ID: + return _AutomationRegistryLogicB.ParseCancelledUpkeepReport(log) + case _AutomationRegistryLogicB.abi.Events["DedupKeyAdded"].ID: + return _AutomationRegistryLogicB.ParseDedupKeyAdded(log) + case _AutomationRegistryLogicB.abi.Events["FundsAdded"].ID: + return _AutomationRegistryLogicB.ParseFundsAdded(log) + case _AutomationRegistryLogicB.abi.Events["FundsWithdrawn"].ID: + return _AutomationRegistryLogicB.ParseFundsWithdrawn(log) + case _AutomationRegistryLogicB.abi.Events["InsufficientFundsUpkeepReport"].ID: + return _AutomationRegistryLogicB.ParseInsufficientFundsUpkeepReport(log) + case _AutomationRegistryLogicB.abi.Events["OwnerFundsWithdrawn"].ID: + return _AutomationRegistryLogicB.ParseOwnerFundsWithdrawn(log) + case _AutomationRegistryLogicB.abi.Events["OwnershipTransferRequested"].ID: + return _AutomationRegistryLogicB.ParseOwnershipTransferRequested(log) + case _AutomationRegistryLogicB.abi.Events["OwnershipTransferred"].ID: + return _AutomationRegistryLogicB.ParseOwnershipTransferred(log) + case _AutomationRegistryLogicB.abi.Events["Paused"].ID: + return _AutomationRegistryLogicB.ParsePaused(log) + case _AutomationRegistryLogicB.abi.Events["PayeesUpdated"].ID: + return _AutomationRegistryLogicB.ParsePayeesUpdated(log) + case _AutomationRegistryLogicB.abi.Events["PayeeshipTransferRequested"].ID: + return _AutomationRegistryLogicB.ParsePayeeshipTransferRequested(log) + case _AutomationRegistryLogicB.abi.Events["PayeeshipTransferred"].ID: + return _AutomationRegistryLogicB.ParsePayeeshipTransferred(log) + case _AutomationRegistryLogicB.abi.Events["PaymentWithdrawn"].ID: + return _AutomationRegistryLogicB.ParsePaymentWithdrawn(log) + case _AutomationRegistryLogicB.abi.Events["ReorgedUpkeepReport"].ID: + return _AutomationRegistryLogicB.ParseReorgedUpkeepReport(log) + case _AutomationRegistryLogicB.abi.Events["StaleUpkeepReport"].ID: + return _AutomationRegistryLogicB.ParseStaleUpkeepReport(log) + case _AutomationRegistryLogicB.abi.Events["Unpaused"].ID: + return _AutomationRegistryLogicB.ParseUnpaused(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepAdminTransferRequested"].ID: + return _AutomationRegistryLogicB.ParseUpkeepAdminTransferRequested(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepAdminTransferred"].ID: + return _AutomationRegistryLogicB.ParseUpkeepAdminTransferred(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepCanceled"].ID: + return _AutomationRegistryLogicB.ParseUpkeepCanceled(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepCheckDataSet"].ID: + return _AutomationRegistryLogicB.ParseUpkeepCheckDataSet(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepGasLimitSet"].ID: + return _AutomationRegistryLogicB.ParseUpkeepGasLimitSet(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepMigrated"].ID: + return _AutomationRegistryLogicB.ParseUpkeepMigrated(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepOffchainConfigSet"].ID: + return _AutomationRegistryLogicB.ParseUpkeepOffchainConfigSet(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepPaused"].ID: + return _AutomationRegistryLogicB.ParseUpkeepPaused(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepPerformed"].ID: + return _AutomationRegistryLogicB.ParseUpkeepPerformed(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepPrivilegeConfigSet"].ID: + return _AutomationRegistryLogicB.ParseUpkeepPrivilegeConfigSet(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepReceived"].ID: + return _AutomationRegistryLogicB.ParseUpkeepReceived(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepRegistered"].ID: + return _AutomationRegistryLogicB.ParseUpkeepRegistered(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepTriggerConfigSet"].ID: + return _AutomationRegistryLogicB.ParseUpkeepTriggerConfigSet(log) + case _AutomationRegistryLogicB.abi.Events["UpkeepUnpaused"].ID: + return _AutomationRegistryLogicB.ParseUpkeepUnpaused(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (AutomationRegistryLogicBAdminPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") +} + +func (AutomationRegistryLogicBCancelledUpkeepReport) Topic() common.Hash { + return common.HexToHash("0xc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636") +} + +func (AutomationRegistryLogicBDedupKeyAdded) Topic() common.Hash { + return common.HexToHash("0xa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f2") +} + +func (AutomationRegistryLogicBFundsAdded) Topic() common.Hash { + return common.HexToHash("0xafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203") +} + +func (AutomationRegistryLogicBFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0xf3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318") +} + +func (AutomationRegistryLogicBInsufficientFundsUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") +} + +func (AutomationRegistryLogicBOwnerFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0x1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f1") +} + +func (AutomationRegistryLogicBOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (AutomationRegistryLogicBOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (AutomationRegistryLogicBPaused) Topic() common.Hash { + return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258") +} + +func (AutomationRegistryLogicBPayeesUpdated) Topic() common.Hash { + return common.HexToHash("0xa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725") +} + +func (AutomationRegistryLogicBPayeeshipTransferRequested) Topic() common.Hash { + return common.HexToHash("0x84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e38367") +} + +func (AutomationRegistryLogicBPayeeshipTransferred) Topic() common.Hash { + return common.HexToHash("0x78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b3") +} + +func (AutomationRegistryLogicBPaymentWithdrawn) Topic() common.Hash { + return common.HexToHash("0x9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698") +} + +func (AutomationRegistryLogicBReorgedUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301") +} + +func (AutomationRegistryLogicBStaleUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8") +} + +func (AutomationRegistryLogicBUnpaused) Topic() common.Hash { + return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa") +} + +func (AutomationRegistryLogicBUpkeepAdminTransferRequested) Topic() common.Hash { + return common.HexToHash("0xb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b35") +} + +func (AutomationRegistryLogicBUpkeepAdminTransferred) Topic() common.Hash { + return common.HexToHash("0x5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c") +} + +func (AutomationRegistryLogicBUpkeepCanceled) Topic() common.Hash { + return common.HexToHash("0x91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f791181") +} + +func (AutomationRegistryLogicBUpkeepCheckDataSet) Topic() common.Hash { + return common.HexToHash("0xcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d") +} + +func (AutomationRegistryLogicBUpkeepGasLimitSet) Topic() common.Hash { + return common.HexToHash("0xc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c") +} + +func (AutomationRegistryLogicBUpkeepMigrated) Topic() common.Hash { + return common.HexToHash("0xb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff") +} + +func (AutomationRegistryLogicBUpkeepOffchainConfigSet) Topic() common.Hash { + return common.HexToHash("0x3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850") +} + +func (AutomationRegistryLogicBUpkeepPaused) Topic() common.Hash { + return common.HexToHash("0x8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f") +} + +func (AutomationRegistryLogicBUpkeepPerformed) Topic() common.Hash { + return common.HexToHash("0xad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b") +} + +func (AutomationRegistryLogicBUpkeepPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae7769") +} + +func (AutomationRegistryLogicBUpkeepReceived) Topic() common.Hash { + return common.HexToHash("0x74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71") +} + +func (AutomationRegistryLogicBUpkeepRegistered) Topic() common.Hash { + return common.HexToHash("0xbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d012") +} + +func (AutomationRegistryLogicBUpkeepTriggerConfigSet) Topic() common.Hash { + return common.HexToHash("0x2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664") +} + +func (AutomationRegistryLogicBUpkeepUnpaused) Topic() common.Hash { + return common.HexToHash("0x7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a47456") +} + +func (_AutomationRegistryLogicB *AutomationRegistryLogicB) Address() common.Address { + return _AutomationRegistryLogicB.address +} + +type AutomationRegistryLogicBInterface interface { + GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) + + GetAdminPrivilegeConfig(opts *bind.CallOpts, admin common.Address) ([]byte, error) + + GetAutomationForwarderLogic(opts *bind.CallOpts) (common.Address, error) + + GetBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetCancellationDelay(opts *bind.CallOpts) (*big.Int, error) + + GetConditionalGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetFastGasFeedAddress(opts *bind.CallOpts) (common.Address, error) + + GetForwarder(opts *bind.CallOpts, upkeepID *big.Int) (common.Address, error) + + GetLinkAddress(opts *bind.CallOpts) (common.Address, error) + + GetLinkNativeFeedAddress(opts *bind.CallOpts) (common.Address, error) + + GetLogGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetMaxPaymentForGas(opts *bind.CallOpts, triggerType uint8, gasLimit uint32) (*big.Int, error) + + GetMinBalance(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetMinBalanceForUpkeep(opts *bind.CallOpts, id *big.Int) (*big.Int, error) + + GetMode(opts *bind.CallOpts) (uint8, error) + + GetPeerRegistryMigrationPermission(opts *bind.CallOpts, peer common.Address) (uint8, error) + + GetPerPerformByteGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetPerSignerGasOverhead(opts *bind.CallOpts) (*big.Int, error) + + GetSignerInfo(opts *bind.CallOpts, query common.Address) (GetSignerInfo, + + error) + + GetState(opts *bind.CallOpts) (GetState, + + error) + + GetTransmitterInfo(opts *bind.CallOpts, query common.Address) (GetTransmitterInfo, + + error) + + GetTriggerType(opts *bind.CallOpts, upkeepId *big.Int) (uint8, error) + + GetUpkeep(opts *bind.CallOpts, id *big.Int) (AutomationRegistryBase22UpkeepInfo, error) + + GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + + GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) + + HasDedupKey(opts *bind.CallOpts, dedupKey [32]byte) (bool, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + UpkeepTranscoderVersion(opts *bind.CallOpts) (uint8, error) + + UpkeepVersion(opts *bind.CallOpts) (uint8, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) + + AcceptUpkeepAdmin(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + Pause(opts *bind.TransactOpts) (*types.Transaction, error) + + PauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + RecoverFunds(opts *bind.TransactOpts) (*types.Transaction, error) + + SetAdminPrivilegeConfig(opts *bind.TransactOpts, admin common.Address, newPrivilegeConfig []byte) (*types.Transaction, error) + + SetPayees(opts *bind.TransactOpts, payees []common.Address) (*types.Transaction, error) + + SetPeerRegistryMigrationPermission(opts *bind.TransactOpts, peer common.Address, permission uint8) (*types.Transaction, error) + + SetUpkeepCheckData(opts *bind.TransactOpts, id *big.Int, newCheckData []byte) (*types.Transaction, error) + + SetUpkeepGasLimit(opts *bind.TransactOpts, id *big.Int, gasLimit uint32) (*types.Transaction, error) + + SetUpkeepOffchainConfig(opts *bind.TransactOpts, id *big.Int, config []byte) (*types.Transaction, error) + + SetUpkeepPrivilegeConfig(opts *bind.TransactOpts, upkeepId *big.Int, newPrivilegeConfig []byte) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) + + TransferUpkeepAdmin(opts *bind.TransactOpts, id *big.Int, proposed common.Address) (*types.Transaction, error) + + Unpause(opts *bind.TransactOpts) (*types.Transaction, error) + + UnpauseUpkeep(opts *bind.TransactOpts, id *big.Int) (*types.Transaction, error) + + WithdrawFunds(opts *bind.TransactOpts, id *big.Int, to common.Address) (*types.Transaction, error) + + WithdrawOwnerFunds(opts *bind.TransactOpts) (*types.Transaction, error) + + WithdrawPayment(opts *bind.TransactOpts, from common.Address, to common.Address) (*types.Transaction, error) + + FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryLogicBAdminPrivilegeConfigSetIterator, error) + + WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) + + ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBAdminPrivilegeConfigSet, error) + + FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBCancelledUpkeepReportIterator, error) + + WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryLogicBCancelledUpkeepReport, error) + + FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryLogicBDedupKeyAddedIterator, error) + + WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) + + ParseDedupKeyAdded(log types.Log) (*AutomationRegistryLogicBDedupKeyAdded, error) + + FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryLogicBFundsAddedIterator, error) + + WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) + + ParseFundsAdded(log types.Log) (*AutomationRegistryLogicBFundsAdded, error) + + FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBFundsWithdrawnIterator, error) + + WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBFundsWithdrawn, id []*big.Int) (event.Subscription, error) + + ParseFundsWithdrawn(log types.Log) (*AutomationRegistryLogicBFundsWithdrawn, error) + + FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBInsufficientFundsUpkeepReportIterator, error) + + WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryLogicBInsufficientFundsUpkeepReport, error) + + FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryLogicBOwnerFundsWithdrawnIterator, error) + + WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnerFundsWithdrawn) (event.Subscription, error) + + ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryLogicBOwnerFundsWithdrawn, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicBOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryLogicBOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryLogicBOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*AutomationRegistryLogicBOwnershipTransferred, error) + + FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryLogicBPausedIterator, error) + + WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPaused) (event.Subscription, error) + + ParsePaused(log types.Log) (*AutomationRegistryLogicBPaused, error) + + FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryLogicBPayeesUpdatedIterator, error) + + WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeesUpdated) (event.Subscription, error) + + ParsePayeesUpdated(log types.Log) (*AutomationRegistryLogicBPayeesUpdated, error) + + FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicBPayeeshipTransferRequestedIterator, error) + + WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryLogicBPayeeshipTransferRequested, error) + + FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryLogicBPayeeshipTransferredIterator, error) + + WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryLogicBPayeeshipTransferred, error) + + FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryLogicBPaymentWithdrawnIterator, error) + + WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) + + ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryLogicBPaymentWithdrawn, error) + + FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBReorgedUpkeepReportIterator, error) + + WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryLogicBReorgedUpkeepReport, error) + + FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBStaleUpkeepReportIterator, error) + + WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBStaleUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryLogicBStaleUpkeepReport, error) + + FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryLogicBUnpausedIterator, error) + + WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUnpaused) (event.Subscription, error) + + ParseUnpaused(log types.Log) (*AutomationRegistryLogicBUnpaused, error) + + FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicBUpkeepAdminTransferRequestedIterator, error) + + WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryLogicBUpkeepAdminTransferRequested, error) + + FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryLogicBUpkeepAdminTransferredIterator, error) + + WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryLogicBUpkeepAdminTransferred, error) + + FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryLogicBUpkeepCanceledIterator, error) + + WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) + + ParseUpkeepCanceled(log types.Log) (*AutomationRegistryLogicBUpkeepCanceled, error) + + FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepCheckDataSetIterator, error) + + WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryLogicBUpkeepCheckDataSet, error) + + FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepGasLimitSetIterator, error) + + WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryLogicBUpkeepGasLimitSet, error) + + FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepMigratedIterator, error) + + WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepMigrated, id []*big.Int) (event.Subscription, error) + + ParseUpkeepMigrated(log types.Log) (*AutomationRegistryLogicBUpkeepMigrated, error) + + FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepOffchainConfigSetIterator, error) + + WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepOffchainConfigSet, error) + + FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepPausedIterator, error) + + WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPaused(log types.Log) (*AutomationRegistryLogicBUpkeepPaused, error) + + FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryLogicBUpkeepPerformedIterator, error) + + WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) + + ParseUpkeepPerformed(log types.Log) (*AutomationRegistryLogicBUpkeepPerformed, error) + + FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepPrivilegeConfigSetIterator, error) + + WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepPrivilegeConfigSet, error) + + FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepReceivedIterator, error) + + WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepReceived, id []*big.Int) (event.Subscription, error) + + ParseUpkeepReceived(log types.Log) (*AutomationRegistryLogicBUpkeepReceived, error) + + FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepRegisteredIterator, error) + + WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepRegistered, id []*big.Int) (event.Subscription, error) + + ParseUpkeepRegistered(log types.Log) (*AutomationRegistryLogicBUpkeepRegistered, error) + + FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepTriggerConfigSetIterator, error) + + WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryLogicBUpkeepTriggerConfigSet, error) + + FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryLogicBUpkeepUnpausedIterator, error) + + WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryLogicBUpkeepUnpaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryLogicBUpkeepUnpaused, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/keeper_registry_wrapper_2_2/keeper_registry_wrapper_2_2.go b/core/gethwrappers/generated/keeper_registry_wrapper_2_2/keeper_registry_wrapper_2_2.go new file mode 100644 index 00000000000..c85e5e06ae2 --- /dev/null +++ b/core/gethwrappers/generated/keeper_registry_wrapper_2_2/keeper_registry_wrapper_2_2.go @@ -0,0 +1,5170 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package keeper_registry_wrapper_2_2 + +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 AutomationRegistryBase22OnchainConfig struct { + PaymentPremiumPPB uint32 + FlatFeeMicroLink uint32 + CheckGasLimit uint32 + StalenessSeconds *big.Int + GasCeilingMultiplier uint16 + MinUpkeepSpend *big.Int + MaxPerformGas uint32 + MaxCheckDataSize uint32 + MaxPerformDataSize uint32 + MaxRevertDataSize uint32 + FallbackGasPrice *big.Int + FallbackLinkPrice *big.Int + Transcoder common.Address + Registrars []common.Address + UpkeepPrivilegeManager common.Address + ReorgProtectionEnabled bool +} + +var AutomationRegistryMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"contractAutomationRegistryLogicB2_2\",\"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\":[],\"name\":\"InsufficientFunds\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidDataLength\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPayee\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRecipient\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidReport\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTransmitter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTrigger\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTriggerType\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxCheckDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MaxPerformDataSizeCanOnlyIncrease\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MigrationNotPermitted\",\"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\":\"OnlyPausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlySimulatedBackend\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyUnpausedUpkeep\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ParameterLengthError\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentGreaterThanAllLINK\",\"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\":\"UpkeepAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepCancelled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotCanceled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UpkeepNotNeeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValueNotChanged\",\"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\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"trigger\",\"type\":\"bytes\"}],\"name\":\"CancelledUpkeepReport\",\"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\":\"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\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"OwnerFundsWithdrawn\",\"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\":\"nonpayable\",\"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\":\"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\":\"bool\",\"name\":\"reorgProtectionEnabled\",\"type\":\"bool\"}],\"internalType\":\"structAutomationRegistryBase2_2.OnchainConfig\",\"name\":\"onchainConfig\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfigTypeSafe\",\"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\":\"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: "0x6101406040523480156200001257600080fd5b50604051620055da380380620055da8339810160408190526200003591620003df565b80816001600160a01b0316634b4fd03b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000406565b826001600160a01b031663ca30e6036040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000da573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001009190620003df565b836001600160a01b031663b10b673c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200013f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001659190620003df565b846001600160a01b0316636709d0e56040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ca9190620003df565b856001600160a01b0316635425d8ac6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000209573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022f9190620003df565b3380600081620002865760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620002b957620002b9816200031b565b505050846002811115620002d157620002d162000429565b60e0816002811115620002e857620002e862000429565b9052506001600160a01b0393841660805291831660a052821660c0528116610100529190911661012052506200043f9050565b336001600160a01b03821603620003755760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016200027d565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6001600160a01b0381168114620003dc57600080fd5b50565b600060208284031215620003f257600080fd5b8151620003ff81620003c6565b9392505050565b6000602082840312156200041957600080fd5b815160038110620003ff57600080fd5b634e487b7160e01b600052602160045260246000fd5b60805160a05160c05160e0516101005161012051615139620004a16000396000818160d6015261016f0152600050506000818161253d01528181613447015281816135da0152613af701526000505060005050600061134a01526151396000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c8063a4c0ed3611610081578063b1dc65a41161005b578063b1dc65a4146102e0578063e3d0e712146102f3578063f2fde38b14610306576100d4565b8063a4c0ed3614610262578063aed2e92914610275578063afcb95d71461029f576100d4565b806379ba5097116100b257806379ba5097146101c757806381ff7048146101cf5780638da5cb5b14610244576100d4565b8063181f5a771461011b578063349e8cca1461016d5780636cad5469146101b4575b7f00000000000000000000000000000000000000000000000000000000000000003660008037600080366000845af43d6000803e808015610114573d6000f35b3d6000fd5b005b6101576040518060400160405280601881526020017f4175746f6d6174696f6e526567697374727920322e322e30000000000000000081525081565b6040516101649190613d76565b60405180910390f35b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b6101196101c23660046141a5565b610319565b610119611230565b61022160155460115463ffffffff780100000000000000000000000000000000000000000000000083048116937c01000000000000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610164565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b6101196102703660046142bb565b611332565b610288610283366004614317565b61154e565b604080519215158352602083019190915201610164565b601154601254604080516000815260208101939093527401000000000000000000000000000000000000000090910463ffffffff1690820152606001610164565b6101196102ee3660046143a8565b6116c6565b61011961030136600461445f565b61226f565b6101196103143660046144ee565b612298565b6103216122ac565b601f8651111561035d576040517f25d0209c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff1660000361039a576040517fe77dba5600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845186511415806103b957506103b184600361453a565b60ff16865111155b156103f0576040517f1d2d1c5800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601254600e546bffffffffffffffffffffffff9091169060005b816bffffffffffffffffffffffff168110156104725761045f600e828154811061043657610436614563565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16848461232f565b508061046a81614592565b91505061040a565b5060008060005b836bffffffffffffffffffffffff1681101561057b57600d81815481106104a2576104a2614563565b600091825260209091200154600e805473ffffffffffffffffffffffffffffffffffffffff909216945090829081106104dd576104dd614563565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff8681168452600c8352604080852080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001690559116808452600b90925290912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905591508061057381614592565b915050610479565b50610588600d6000613c4b565b610594600e6000613c4b565b604080516080810182526000808252602082018190529181018290526060810182905290805b8c518110156109fd57600c60008e83815181106105d9576105d9614563565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528101919091526040016000205460ff1615610644576040517f77cea0fa00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168d828151811061066e5761066e614563565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16036106c3576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405180604001604052806001151581526020018260ff16815250600c60008f84815181106106f4576106f4614563565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff1682528181019290925260400160002082518154939092015160ff16610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909316929092171790558b518c908290811061079c5761079c614563565b60200260200101519150600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361080c576040517f58a70a0a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82166000908152600b60209081526040918290208251608081018452905460ff80821615801584526101008304909116938301939093526bffffffffffffffffffffffff6201000082048116948301949094526e010000000000000000000000000000900490921660608301529093506108c7576040517f6a7281ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001835260ff80821660208086019182526bffffffffffffffffffffffff808b166060880190815273ffffffffffffffffffffffffffffffffffffffff87166000908152600b909352604092839020885181549551948a0151925184166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff939094166201000002929092167fffffffffffff000000000000000000000000000000000000000000000000ffff94909616610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090951694909417179190911692909217919091179055806109f581614592565b9150506105ba565b50508a51610a139150600d9060208d0190613c69565b508851610a2790600e9060208c0190613c69565b50604051806101400160405280856bffffffffffffffffffffffff168152602001886000015163ffffffff168152602001886020015163ffffffff168152602001600063ffffffff168152602001886060015162ffffff168152602001886080015161ffff1681526020018960ff1681526020016012600001601e9054906101000a900460ff16151581526020016012600001601f9054906101000a900460ff1615158152602001886101e001511515815250601260008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060408201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160146101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160186101000a81548162ffffff021916908362ffffff16021790555060a082015181600001601b6101000a81548161ffff021916908361ffff16021790555060c082015181600001601d6101000a81548160ff021916908360ff16021790555060e082015181600001601e6101000a81548160ff02191690831515021790555061010082015181600001601f6101000a81548160ff0219169083151502179055506101208201518160010160006101000a81548160ff0219169083151502179055509050506040518061018001604052808860a001516bffffffffffffffffffffffff16815260200188610180015173ffffffffffffffffffffffffffffffffffffffff168152602001601460010160009054906101000a90046bffffffffffffffffffffffff166bffffffffffffffffffffffff168152602001886040015163ffffffff1681526020018860c0015163ffffffff168152602001601460010160149054906101000a900463ffffffff1663ffffffff168152602001601460010160189054906101000a900463ffffffff1663ffffffff1681526020016014600101601c9054906101000a900463ffffffff1663ffffffff1681526020018860e0015163ffffffff16815260200188610100015163ffffffff16815260200188610120015163ffffffff168152602001886101c0015173ffffffffffffffffffffffffffffffffffffffff16815250601460008201518160000160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550602082015181600001600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060408201518160010160006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550606082015181600101600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160010160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160010160146101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160010160186101000a81548163ffffffff021916908363ffffffff16021790555060e082015181600101601c6101000a81548163ffffffff021916908363ffffffff1602179055506101008201518160020160006101000a81548163ffffffff021916908363ffffffff1602179055506101208201518160020160046101000a81548163ffffffff021916908363ffffffff1602179055506101408201518160020160086101000a81548163ffffffff021916908363ffffffff16021790555061016082015181600201600c6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555090505086610140015160178190555086610160015160188190555060006014600101601c9054906101000a900463ffffffff169050611017612537565b601580547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff938416021780825560019260189161109291859178010000000000000000000000000000000000000000000000009004166145ca565b92506101000a81548163ffffffff021916908363ffffffff1602179055506000886040516020016110c39190614638565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905260155490915061112c90469030907801000000000000000000000000000000000000000000000000900463ffffffff168f8f8f878f8f6125ec565b60115560005b61113c6009612696565b81101561116c576111596111516009836126a6565b6009906126b9565b508061116481614592565b915050611132565b5060005b896101a00151518110156111c3576111b08a6101a00151828151811061119857611198614563565b602002602001015160096126db90919063ffffffff16565b50806111bb81614592565b915050611170565b507f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e0582601154601460010160189054906101000a900463ffffffff168f8f8f878f8f60405161121a999897969594939291906147b3565b60405180910390a1505050505050505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146112b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146113a1576040517fc8bad78d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146113db576040517fdfe9309000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006113e982840184614849565b60008181526004602052604090205490915065010000000000900463ffffffff90811614611443576040517f9c0083a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526004602052604090206001015461147e9085906c0100000000000000000000000090046bffffffffffffffffffffffff16614862565b600082815260046020526040902060010180546bffffffffffffffffffffffff929092166c01000000000000000000000000027fffffffffffffffff000000000000000000000000ffffffffffffffffffffffff9092169190911790556019546114e9908590614887565b6019556040516bffffffffffffffffffffffff8516815273ffffffffffffffffffffffffffffffffffffffff86169082907fafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa7348915062039060200160405180910390a35050505050565b6000806115596126fd565b6012547e01000000000000000000000000000000000000000000000000000000000000900460ff16156115b8576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085815260046020908152604091829020825160e081018452815460ff811615158252610100810463ffffffff908116838601819052650100000000008304821684880152690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff16606084018190526001909401546bffffffffffffffffffffffff80821660808601526c0100000000000000000000000082041660a0850152780100000000000000000000000000000000000000000000000090041660c08301528451601f890185900485028101850190955287855290936116b793899089908190840183828082843760009201919091525061273592505050565b9093509150505b935093915050565b60005a60408051610140810182526012546bffffffffffffffffffffffff8116825263ffffffff6c010000000000000000000000008204811660208401527001000000000000000000000000000000008204811693830193909352740100000000000000000000000000000000000000008104909216606082015262ffffff7801000000000000000000000000000000000000000000000000830416608082015261ffff7b0100000000000000000000000000000000000000000000000000000083041660a082015260ff7d0100000000000000000000000000000000000000000000000000000000008304811660c08301527e010000000000000000000000000000000000000000000000000000000000008304811615801560e08401527f010000000000000000000000000000000000000000000000000000000000000090930481161515610100830152601354161515610120820152919250611858576040517f24522f3400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600b602052604090205460ff166118a1576040517f1099ed7500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6011548a35146118dd576040517fdfdcf8e700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c08101516118ed90600161489a565b60ff16861415806118fe5750858414155b15611935576040517f0244f71a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119458a8a8a8a8a8a8a8a61295e565b60006119518a8a612bc7565b9050600081604001515167ffffffffffffffff81111561197357611973613d89565b604051908082528060200260200182016040528015611a3757816020015b604080516101e0810182526000610100820181815261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c0830182905282526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816119915790505b5090506000805b836040015151811015611e81576004600085604001518381518110611a6557611a65614563565b6020908102919091018101518252818101929092526040908101600020815160e081018352815460ff811615158252610100810463ffffffff90811695830195909552650100000000008104851693820193909352690100000000000000000090920473ffffffffffffffffffffffffffffffffffffffff166060830152600101546bffffffffffffffffffffffff80821660808401526c0100000000000000000000000082041660a08301527801000000000000000000000000000000000000000000000000900490911660c08201528351849083908110611b4a57611b4a614563565b602002602001015160000181905250611b7f84604001518281518110611b7257611b72614563565b6020026020010151612c80565b838281518110611b9157611b91614563565b6020026020010151608001906001811115611bae57611bae6148b3565b90816001811115611bc157611bc16148b3565b81525050611c3585848381518110611bdb57611bdb614563565b60200260200101516080015186606001518481518110611bfd57611bfd614563565b60200260200101518760a001518581518110611c1b57611c1b614563565b602002602001015151886000015189602001516001612d2b565b838281518110611c4757611c47614563565b6020026020010151604001906bffffffffffffffffffffffff1690816bffffffffffffffffffffffff1681525050611cd484604001518281518110611c8e57611c8e614563565b602002602001015185608001518381518110611cac57611cac614563565b6020026020010151858481518110611cc657611cc6614563565b602002602001015188612d76565b848381518110611ce657611ce6614563565b6020026020010151602001858481518110611d0357611d03614563565b602002602001015160e0018281525082151515158152505050828181518110611d2e57611d2e614563565b60200260200101516020015115611d5157611d4a6001836148e2565b9150611d56565b611e6f565b611dbc838281518110611d6b57611d6b614563565b6020026020010151600001516060015185606001518381518110611d9157611d91614563565b60200260200101518660a001518481518110611daf57611daf614563565b6020026020010151612735565b848381518110611dce57611dce614563565b6020026020010151606001858481518110611deb57611deb614563565b602002602001015160a0018281525082151515158152505050828181518110611e1657611e16614563565b602002602001015160a0015186611e2d91906148fd565b9550611e6f84604001518281518110611e4857611e48614563565b6020026020010151848381518110611e6257611e62614563565b6020026020010151612ef9565b80611e7981614592565b915050611a3e565b508061ffff16600003611e98575050505050612265565b60c0840151611ea890600161489a565b611eb79060ff1661044c614910565b616b6c611ec58d6010614910565b5a611ed090896148fd565b611eda9190614887565b611ee49190614887565b611eee9190614887565b9450611b58611f0161ffff83168761497c565b611f0b9190614887565b945060008060008060005b87604001515181101561210c57868181518110611f3557611f35614563565b602002602001015160200151156120fa57611f918a888381518110611f5c57611f5c614563565b6020026020010151608001518a60a001518481518110611f7e57611f7e614563565b6020026020010151518c60c0015161300b565b878281518110611fa357611fa3614563565b602002602001015160c0018181525050611fff8989604001518381518110611fcd57611fcd614563565b6020026020010151898481518110611fe757611fe7614563565b60200260200101518b600001518c602001518b61302b565b909350915061200e8285614862565b935061201a8386614862565b945086818151811061202e5761202e614563565b60200260200101516060015115158860400151828151811061205257612052614563565b60200260200101517fad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b84866120879190614862565b8a858151811061209957612099614563565b602002602001015160a001518b86815181106120b7576120b7614563565b602002602001015160c001518d6080015187815181106120d9576120d9614563565b60200260200101516040516120f19493929190614990565b60405180910390a35b8061210481614592565b915050611f16565b5050336000908152600b6020526040902080548492506002906121449084906201000090046bffffffffffffffffffffffff16614862565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080601260000160008282829054906101000a90046bffffffffffffffffffffffff1661219e9190614862565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555060008f6001600381106121e1576121e1614563565b602002013560001c9050600060088264ffffffffff16901c9050876060015163ffffffff168163ffffffff16111561225b57601280547fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000063ffffffff8416021790555b5050505050505050505b5050505050505050565b612290868686868060200190518101906122899190614a73565b8686610319565b505050505050565b6122a06122ac565b6122a98161311e565b50565b60005473ffffffffffffffffffffffffffffffffffffffff16331461232d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016112ad565b565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600b602090815260408083208151608081018352905460ff80821615801584526101008304909116948301949094526bffffffffffffffffffffffff6201000082048116938301939093526e010000000000000000000000000000900490911660608201529061252b5760008160600151856123c79190614be1565b905060006123d58583614c06565b905080836040018181516123e99190614862565b6bffffffffffffffffffffffff169052506124048582614c31565b836060018181516124159190614862565b6bffffffffffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff89166000908152600b602090815260409182902087518154928901519389015160608a015186166e010000000000000000000000000000027fffffffffffff000000000000000000000000ffffffffffffffffffffffffffff919096166201000002167fffffffffffff000000000000000000000000000000000000000000000000ffff60ff95909516610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff921515929092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000909416939093171792909216179190911790555050505b60400151949350505050565b600060017f0000000000000000000000000000000000000000000000000000000000000000600281111561256d5761256d6148b3565b036125e757606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125e29190614c65565b905090565b504390565b6000808a8a8a8a8a8a8a8a8a60405160200161261099989796959493929190614c7e565b604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179b9a5050505050505050505050565b60006126a0825490565b92915050565b60006126b28383613213565b9392505050565b60006126b28373ffffffffffffffffffffffffffffffffffffffff841661323d565b60006126b28373ffffffffffffffffffffffffffffffffffffffff8416613337565b321561232d576040517fb60ac5db00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60125460009081907f0100000000000000000000000000000000000000000000000000000000000000900460ff161561279a576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01000000000000000000000000000000000000000000000000000000000000001790556040517f4585e33b0000000000000000000000000000000000000000000000000000000090612816908590602401613d76565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290517f79188d1600000000000000000000000000000000000000000000000000000000815290935073ffffffffffffffffffffffffffffffffffffffff8616906379188d16906128e99087908790600401614d13565b60408051808303816000875af1158015612907573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292b9190614d2c565b601280547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16905590969095509350505050565b60008787604051612970929190614d5a565b604051908190038120612987918b90602001614d6a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201208383019092526000808452908301819052909250906000805b88811015612b5e576001858783602081106129f3576129f3614563565b612a0091901a601b61489a565b8c8c85818110612a1257612a12614563565b905060200201358b8b86818110612a2b57612a2b614563565b9050602002013560405160008152602001604052604051612a68949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015612a8a573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff81166000908152600c602090815290849020838501909452925460ff8082161515808552610100909204169383019390935290955093509050612b38576040517f0f4c073700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015160080260ff166001901b840193508080612b5690614592565b9150506129d6565b50827e01010101010101010101010101010101010101010101010101010101010101841614612bb9576040517fc103be2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050505050505050505050565b612c006040518060c001604052806000815260200160008152602001606081526020016060815260200160608152602001606081525090565b6000612c0e83850185614e5b565b6040810151516060820151519192509081141580612c3157508082608001515114155b80612c415750808260a001515114155b15612c78576040517fb55ac75400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b509392505050565b6000818160045b600f811015612d0d577fff000000000000000000000000000000000000000000000000000000000000008216838260208110612cc557612cc5614563565b1a60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614612cfb57506000949350505050565b80612d0581614592565b915050612c87565b5081600f1a6001811115612d2357612d236148b3565b949350505050565b600080612d3d88878b60c00151613386565b9050600080612d588b8a63ffffffff16858a8a60018b613412565b9092509050612d678183614862565b9b9a5050505050505050505050565b600080808085608001516001811115612d9157612d916148b3565b03612db657612da28787878761386b565b612db157600092509050612ef0565b612e2d565b600185608001516001811115612dce57612dce6148b3565b03612dfb576000612de088888761396d565b9250905080612df55750600092509050612ef0565b50612e2d565b6040517ff2b2d41200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e35612537565b85516040015163ffffffff1611612e8957867fc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd563687604051612e769190613d76565b60405180910390a2600092509050612ef0565b84604001516bffffffffffffffffffffffff16856000015160a001516bffffffffffffffffffffffff161015612ee957867f377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e0287604051612e769190613d76565b6001925090505b94509492505050565b600081608001516001811115612f1157612f116148b3565b03612f8357612f1e612537565b6000838152600460205260409020600101805463ffffffff929092167801000000000000000000000000000000000000000000000000027fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790555050565b600181608001516001811115612f9b57612f9b6148b3565b036130075760e08101805160009081526008602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055915191517fa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f29190a25b5050565b6000613018848484613386565b905080851015612d235750929392505050565b600080613046888760a001518860c001518888886001613412565b909250905060006130578284614862565b600089815260046020526040902060010180549192508291600c9061309b9084906c0100000000000000000000000090046bffffffffffffffffffffffff16614be1565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008a8152600460205260408120600101805485945090926130e491859116614862565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555050965096945050505050565b3373ffffffffffffffffffffffffffffffffffffffff82160361319d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016112ad565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600082600001828154811061322a5761322a614563565b9060005260206000200154905092915050565b600081815260018301602052604081205480156133265760006132616001836148fd565b8554909150600090613275906001906148fd565b90508181146132da57600086600001828154811061329557613295614563565b90600052602060002001549050808760000184815481106132b8576132b8614563565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806132eb576132eb614f48565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506126a0565b60009150506126a0565b5092915050565b600081815260018301602052604081205461337e575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556126a0565b5060006126a0565b6000808085600181111561339c5761339c6148b3565b036133ab575062015f906133ca565b60018560018111156133bf576133bf6148b3565b03612dfb57506201adb05b6133db63ffffffff85166014614910565b6133e684600161489a565b6133f59060ff16611d4c614910565b6133ff9083614887565b6134099190614887565b95945050505050565b60008060008960a0015161ffff168761342b9190614910565b90508380156134395750803a105b1561344157503a5b600060027f00000000000000000000000000000000000000000000000000000000000000006002811115613477576134776148b3565b036135d65760408051600081526020810190915285156134d5576000366040518060800160405280604881526020016150e5604891396040516020016134bf93929190614f77565b604051602081830303815290604052905061353d565b6016546134f190640100000000900463ffffffff166004614f9e565b63ffffffff1667ffffffffffffffff81111561350f5761350f613d89565b6040519080825280601f01601f191660200182016040528015613539576020820181803683370190505b5090505b6040517f49948e0e00000000000000000000000000000000000000000000000000000000815273420000000000000000000000000000000000000f906349948e0e9061358d908490600401613d76565b602060405180830381865afa1580156135aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ce9190614c65565b915050613730565b60017f0000000000000000000000000000000000000000000000000000000000000000600281111561360a5761360a6148b3565b0361373057841561368c57606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613661573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136859190614c65565b9050613730565b6000606c73ffffffffffffffffffffffffffffffffffffffff166341b247a86040518163ffffffff1660e01b815260040160c060405180830381865afa1580156136da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136fe9190614fc1565b505060165492945061372193505050640100000000900463ffffffff1682614910565b61372c906010614910565b9150505b8461374c57808b60a0015161ffff166137499190614910565b90505b61375a61ffff87168261497c565b90506000878261376a8c8e614887565b6137749086614910565b61377e9190614887565b61379090670de0b6b3a7640000614910565b61379a919061497c565b905060008c6040015163ffffffff1664e8d4a510006137b99190614910565b898e6020015163ffffffff16858f886137d29190614910565b6137dc9190614887565b6137ea90633b9aca00614910565b6137f49190614910565b6137fe919061497c565b6138089190614887565b90506b033b2e3c9fd0803ce80000006138218284614887565b1115613859576040517f2ad7547a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b909c909b509950505050505050505050565b60008084806020019051810190613882919061500b565b845160c00151815191925063ffffffff908116911610156138df57857f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8866040516138cd9190613d76565b60405180910390a26000915050612d23565b826101200151801561391357506020810151158015906139135750602081015181516139109063ffffffff16613af1565b14155b8061392c5750613921612537565b815163ffffffff1610155b1561396157857f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301866040516138cd9190613d76565b50600195945050505050565b6000806000848060200190518101906139869190615063565b90506000868260000151836020015184604001516040516020016139e894939291909384526020840192909252604083015260e01b7fffffffff0000000000000000000000000000000000000000000000000000000016606082015260640190565b6040516020818303038152906040528051906020012090508461012001518015613a365750608082015115801590613a3657508160800151613a33836060015163ffffffff16613af1565b14155b80613a525750613a44612537565b826060015163ffffffff1610155b15613a9c57867f6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc30187604051613a879190613d76565b60405180910390a26000935091506116be9050565b60008181526008602052604090205460ff1615613ae357867f405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e887604051613a879190613d76565b600197909650945050505050565b600060017f00000000000000000000000000000000000000000000000000000000000000006002811115613b2757613b276148b3565b03613c41576000606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b9e9190614c65565b90508083101580613bb95750610100613bb784836148fd565b115b15613bc75750600092915050565b6040517f2b407a8200000000000000000000000000000000000000000000000000000000815260048101849052606490632b407a8290602401602060405180830381865afa158015613c1d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126b29190614c65565b504090565b919050565b50805460008255906000526020600020908101906122a99190613cf3565b828054828255906000526020600020908101928215613ce3579160200282015b82811115613ce357825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190613c89565b50613cef929150613cf3565b5090565b5b80821115613cef5760008155600101613cf4565b60005b83811015613d23578181015183820152602001613d0b565b50506000910152565b60008151808452613d44816020860160208601613d08565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006126b26020830184613d2c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610200810167ffffffffffffffff81118282101715613ddc57613ddc613d89565b60405290565b60405160c0810167ffffffffffffffff81118282101715613ddc57613ddc613d89565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613e4c57613e4c613d89565b604052919050565b600067ffffffffffffffff821115613e6e57613e6e613d89565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff811681146122a957600080fd5b8035613c4681613e78565b600082601f830112613eb657600080fd5b81356020613ecb613ec683613e54565b613e05565b82815260059290921b84018101918181019086841115613eea57600080fd5b8286015b84811015613f0e578035613f0181613e78565b8352918301918301613eee565b509695505050505050565b803560ff81168114613c4657600080fd5b63ffffffff811681146122a957600080fd5b8035613c4681613f2a565b62ffffff811681146122a957600080fd5b8035613c4681613f47565b61ffff811681146122a957600080fd5b8035613c4681613f63565b6bffffffffffffffffffffffff811681146122a957600080fd5b8035613c4681613f7e565b80151581146122a957600080fd5b8035613c4681613fa3565b60006102008284031215613fcf57600080fd5b613fd7613db8565b9050613fe282613f3c565b8152613ff060208301613f3c565b602082015261400160408301613f3c565b604082015261401260608301613f58565b606082015261402360808301613f73565b608082015261403460a08301613f98565b60a082015261404560c08301613f3c565b60c082015261405660e08301613f3c565b60e0820152610100614069818401613f3c565b9082015261012061407b838201613f3c565b90820152610140828101359082015261016080830135908201526101806140a3818401613e9a565b908201526101a08281013567ffffffffffffffff8111156140c357600080fd5b6140cf85828601613ea5565b8284015250506101c06140e3818401613e9a565b908201526101e06140f5838201613fb1565b9082015292915050565b803567ffffffffffffffff81168114613c4657600080fd5b600082601f83011261412857600080fd5b813567ffffffffffffffff81111561414257614142613d89565b61417360207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613e05565b81815284602083860101111561418857600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060008060c087890312156141be57600080fd5b863567ffffffffffffffff808211156141d657600080fd5b6141e28a838b01613ea5565b975060208901359150808211156141f857600080fd5b6142048a838b01613ea5565b965061421260408a01613f19565b9550606089013591508082111561422857600080fd5b6142348a838b01613fbc565b945061424260808a016140ff565b935060a089013591508082111561425857600080fd5b5061426589828a01614117565b9150509295509295509295565b60008083601f84011261428457600080fd5b50813567ffffffffffffffff81111561429c57600080fd5b6020830191508360208285010111156142b457600080fd5b9250929050565b600080600080606085870312156142d157600080fd5b84356142dc81613e78565b935060208501359250604085013567ffffffffffffffff8111156142ff57600080fd5b61430b87828801614272565b95989497509550505050565b60008060006040848603121561432c57600080fd5b83359250602084013567ffffffffffffffff81111561434a57600080fd5b61435686828701614272565b9497909650939450505050565b60008083601f84011261437557600080fd5b50813567ffffffffffffffff81111561438d57600080fd5b6020830191508360208260051b85010111156142b457600080fd5b60008060008060008060008060e0898b0312156143c457600080fd5b606089018a8111156143d557600080fd5b8998503567ffffffffffffffff808211156143ef57600080fd5b6143fb8c838d01614272565b909950975060808b013591508082111561441457600080fd5b6144208c838d01614363565b909750955060a08b013591508082111561443957600080fd5b506144468b828c01614363565b999c989b50969995989497949560c00135949350505050565b60008060008060008060c0878903121561447857600080fd5b863567ffffffffffffffff8082111561449057600080fd5b61449c8a838b01613ea5565b975060208901359150808211156144b257600080fd5b6144be8a838b01613ea5565b96506144cc60408a01613f19565b955060608901359150808211156144e257600080fd5b6142348a838b01614117565b60006020828403121561450057600080fd5b81356126b281613e78565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600060ff821660ff84168160ff048111821515161561455b5761455b61450b565b029392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036145c3576145c361450b565b5060010190565b63ffffffff8181168382160190808211156133305761333061450b565b600081518084526020808501945080840160005b8381101561462d57815173ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016145fb565b509495945050505050565b6020815261464f60208201835163ffffffff169052565b60006020830151614668604084018263ffffffff169052565b50604083015163ffffffff8116606084015250606083015162ffffff8116608084015250608083015161ffff811660a08401525060a08301516bffffffffffffffffffffffff811660c08401525060c083015163ffffffff811660e08401525060e08301516101006146e18185018363ffffffff169052565b84015190506101206146fa8482018363ffffffff169052565b84015190506101406147138482018363ffffffff169052565b840151610160848101919091528401516101808085019190915284015190506101a06147568185018373ffffffffffffffffffffffffffffffffffffffff169052565b808501519150506102006101c081818601526147766102208601846145e7565b908601519092506101e06147a18682018373ffffffffffffffffffffffffffffffffffffffff169052565b90950151151593019290925250919050565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526147e38184018a6145e7565b905082810360808401526147f781896145e7565b905060ff871660a084015282810360c08401526148148187613d2c565b905067ffffffffffffffff851660e08401528281036101008401526148398185613d2c565b9c9b505050505050505050505050565b60006020828403121561485b57600080fd5b5035919050565b6bffffffffffffffffffffffff8181168382160190808211156133305761333061450b565b808201808211156126a0576126a061450b565b60ff81811683821601908111156126a0576126a061450b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b61ffff8181168382160190808211156133305761333061450b565b818103818111156126a0576126a061450b565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156149485761494861450b565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261498b5761498b61494d565b500490565b6bffffffffffffffffffffffff851681528360208201528260408201526080606082015260006149c36080830184613d2c565b9695505050505050565b8051613c4681613f2a565b8051613c4681613f47565b8051613c4681613f63565b8051613c4681613f7e565b8051613c4681613e78565b600082601f830112614a1557600080fd5b81516020614a25613ec683613e54565b82815260059290921b84018101918181019086841115614a4457600080fd5b8286015b84811015613f0e578051614a5b81613e78565b8352918301918301614a48565b8051613c4681613fa3565b600060208284031215614a8557600080fd5b815167ffffffffffffffff80821115614a9d57600080fd5b908301906102008286031215614ab257600080fd5b614aba613db8565b614ac3836149cd565b8152614ad1602084016149cd565b6020820152614ae2604084016149cd565b6040820152614af3606084016149d8565b6060820152614b04608084016149e3565b6080820152614b1560a084016149ee565b60a0820152614b2660c084016149cd565b60c0820152614b3760e084016149cd565b60e0820152610100614b4a8185016149cd565b90820152610120614b5c8482016149cd565b9082015261014083810151908201526101608084015190820152610180614b848185016149f9565b908201526101a08381015183811115614b9c57600080fd5b614ba888828701614a04565b8284015250506101c09150614bbe8284016149f9565b828201526101e09150614bd2828401614a68565b91810191909152949350505050565b6bffffffffffffffffffffffff8281168282160390808211156133305761333061450b565b60006bffffffffffffffffffffffff80841680614c2557614c2561494d565b92169190910492915050565b60006bffffffffffffffffffffffff80831681851681830481118215151615614c5c57614c5c61450b565b02949350505050565b600060208284031215614c7757600080fd5b5051919050565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614cc58285018b6145e7565b91508382036080850152614cd9828a6145e7565b915060ff881660a085015283820360c0850152614cf68288613d2c565b90861660e085015283810361010085015290506148398185613d2c565b828152604060208201526000612d236040830184613d2c565b60008060408385031215614d3f57600080fd5b8251614d4a81613fa3565b6020939093015192949293505050565b8183823760009101908152919050565b8281526080810160608360208401379392505050565b600082601f830112614d9157600080fd5b81356020614da1613ec683613e54565b82815260059290921b84018101918181019086841115614dc057600080fd5b8286015b84811015613f0e5780358352918301918301614dc4565b600082601f830112614dec57600080fd5b81356020614dfc613ec683613e54565b82815260059290921b84018101918181019086841115614e1b57600080fd5b8286015b84811015613f0e57803567ffffffffffffffff811115614e3f5760008081fd5b614e4d8986838b0101614117565b845250918301918301614e1f565b600060208284031215614e6d57600080fd5b813567ffffffffffffffff80821115614e8557600080fd5b9083019060c08286031215614e9957600080fd5b614ea1613de2565b8235815260208301356020820152604083013582811115614ec157600080fd5b614ecd87828601614d80565b604083015250606083013582811115614ee557600080fd5b614ef187828601614d80565b606083015250608083013582811115614f0957600080fd5b614f1587828601614ddb565b60808301525060a083013582811115614f2d57600080fd5b614f3987828601614ddb565b60a08301525095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b828482376000838201600081528351614f94818360208801613d08565b0195945050505050565b600063ffffffff80831681851681830481118215151615614c5c57614c5c61450b565b60008060008060008060c08789031215614fda57600080fd5b865195506020870151945060408701519350606087015192506080870151915060a087015190509295509295509295565b60006040828403121561501d57600080fd5b6040516040810181811067ffffffffffffffff8211171561504057615040613d89565b604052825161504e81613f2a565b81526020928301519281019290925250919050565b600060a0828403121561507557600080fd5b60405160a0810181811067ffffffffffffffff8211171561509857615098613d89565b8060405250825181526020830151602082015260408301516150b981613f2a565b604082015260608301516150cc81613f2a565b6060820152608092830151928101929092525091905056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000810000a", +} + +var AutomationRegistryABI = AutomationRegistryMetaData.ABI + +var AutomationRegistryBin = AutomationRegistryMetaData.Bin + +func DeployAutomationRegistry(auth *bind.TransactOpts, backend bind.ContractBackend, logicA common.Address) (common.Address, *types.Transaction, *AutomationRegistry, error) { + parsed, err := AutomationRegistryMetaData.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(AutomationRegistryBin), backend, logicA) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &AutomationRegistry{address: address, abi: *parsed, AutomationRegistryCaller: AutomationRegistryCaller{contract: contract}, AutomationRegistryTransactor: AutomationRegistryTransactor{contract: contract}, AutomationRegistryFilterer: AutomationRegistryFilterer{contract: contract}}, nil +} + +type AutomationRegistry struct { + address common.Address + abi abi.ABI + AutomationRegistryCaller + AutomationRegistryTransactor + AutomationRegistryFilterer +} + +type AutomationRegistryCaller struct { + contract *bind.BoundContract +} + +type AutomationRegistryTransactor struct { + contract *bind.BoundContract +} + +type AutomationRegistryFilterer struct { + contract *bind.BoundContract +} + +type AutomationRegistrySession struct { + Contract *AutomationRegistry + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type AutomationRegistryCallerSession struct { + Contract *AutomationRegistryCaller + CallOpts bind.CallOpts +} + +type AutomationRegistryTransactorSession struct { + Contract *AutomationRegistryTransactor + TransactOpts bind.TransactOpts +} + +type AutomationRegistryRaw struct { + Contract *AutomationRegistry +} + +type AutomationRegistryCallerRaw struct { + Contract *AutomationRegistryCaller +} + +type AutomationRegistryTransactorRaw struct { + Contract *AutomationRegistryTransactor +} + +func NewAutomationRegistry(address common.Address, backend bind.ContractBackend) (*AutomationRegistry, error) { + abi, err := abi.JSON(strings.NewReader(AutomationRegistryABI)) + if err != nil { + return nil, err + } + contract, err := bindAutomationRegistry(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &AutomationRegistry{address: address, abi: abi, AutomationRegistryCaller: AutomationRegistryCaller{contract: contract}, AutomationRegistryTransactor: AutomationRegistryTransactor{contract: contract}, AutomationRegistryFilterer: AutomationRegistryFilterer{contract: contract}}, nil +} + +func NewAutomationRegistryCaller(address common.Address, caller bind.ContractCaller) (*AutomationRegistryCaller, error) { + contract, err := bindAutomationRegistry(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryCaller{contract: contract}, nil +} + +func NewAutomationRegistryTransactor(address common.Address, transactor bind.ContractTransactor) (*AutomationRegistryTransactor, error) { + contract, err := bindAutomationRegistry(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &AutomationRegistryTransactor{contract: contract}, nil +} + +func NewAutomationRegistryFilterer(address common.Address, filterer bind.ContractFilterer) (*AutomationRegistryFilterer, error) { + contract, err := bindAutomationRegistry(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &AutomationRegistryFilterer{contract: contract}, nil +} + +func bindAutomationRegistry(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := AutomationRegistryMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_AutomationRegistry *AutomationRegistryRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistry.Contract.AutomationRegistryCaller.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistry *AutomationRegistryRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistry.Contract.AutomationRegistryTransactor.contract.Transfer(opts) +} + +func (_AutomationRegistry *AutomationRegistryRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistry.Contract.AutomationRegistryTransactor.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistry *AutomationRegistryCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _AutomationRegistry.Contract.contract.Call(opts, result, method, params...) +} + +func (_AutomationRegistry *AutomationRegistryTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistry.Contract.contract.Transfer(opts) +} + +func (_AutomationRegistry *AutomationRegistryTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _AutomationRegistry.Contract.contract.Transact(opts, method, params...) +} + +func (_AutomationRegistry *AutomationRegistryCaller) FallbackTo(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistry.contract.Call(opts, &out, "fallbackTo") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_AutomationRegistry *AutomationRegistrySession) FallbackTo() (common.Address, error) { + return _AutomationRegistry.Contract.FallbackTo(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCallerSession) FallbackTo() (common.Address, error) { + return _AutomationRegistry.Contract.FallbackTo(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCaller) LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, + + error) { + var out []interface{} + err := _AutomationRegistry.contract.Call(opts, &out, "latestConfigDetails") + + outstruct := new(LatestConfigDetails) + if err != nil { + return *outstruct, err + } + + outstruct.ConfigCount = *abi.ConvertType(out[0], new(uint32)).(*uint32) + outstruct.BlockNumber = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.ConfigDigest = *abi.ConvertType(out[2], new([32]byte)).(*[32]byte) + + return *outstruct, err + +} + +func (_AutomationRegistry *AutomationRegistrySession) LatestConfigDetails() (LatestConfigDetails, + + error) { + return _AutomationRegistry.Contract.LatestConfigDetails(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCallerSession) LatestConfigDetails() (LatestConfigDetails, + + error) { + return _AutomationRegistry.Contract.LatestConfigDetails(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCaller) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, + + error) { + var out []interface{} + err := _AutomationRegistry.contract.Call(opts, &out, "latestConfigDigestAndEpoch") + + outstruct := new(LatestConfigDigestAndEpoch) + if err != nil { + return *outstruct, err + } + + outstruct.ScanLogs = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.ConfigDigest = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) + outstruct.Epoch = *abi.ConvertType(out[2], new(uint32)).(*uint32) + + return *outstruct, err + +} + +func (_AutomationRegistry *AutomationRegistrySession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, + + error) { + return _AutomationRegistry.Contract.LatestConfigDigestAndEpoch(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCallerSession) LatestConfigDigestAndEpoch() (LatestConfigDigestAndEpoch, + + error) { + return _AutomationRegistry.Contract.LatestConfigDigestAndEpoch(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _AutomationRegistry.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 (_AutomationRegistry *AutomationRegistrySession) Owner() (common.Address, error) { + return _AutomationRegistry.Contract.Owner(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCallerSession) Owner() (common.Address, error) { + return _AutomationRegistry.Contract.Owner(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCaller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _AutomationRegistry.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_AutomationRegistry *AutomationRegistrySession) TypeAndVersion() (string, error) { + return _AutomationRegistry.Contract.TypeAndVersion(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryCallerSession) TypeAndVersion() (string, error) { + return _AutomationRegistry.Contract.TypeAndVersion(&_AutomationRegistry.CallOpts) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "acceptOwnership") +} + +func (_AutomationRegistry *AutomationRegistrySession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistry.Contract.AcceptOwnership(&_AutomationRegistry.TransactOpts) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _AutomationRegistry.Contract.AcceptOwnership(&_AutomationRegistry.TransactOpts) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "onTokenTransfer", sender, amount, data) +} + +func (_AutomationRegistry *AutomationRegistrySession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.OnTokenTransfer(&_AutomationRegistry.TransactOpts, sender, amount, data) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) OnTokenTransfer(sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.OnTokenTransfer(&_AutomationRegistry.TransactOpts, sender, amount, data) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "setConfig", signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistrySession) SetConfig(signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SetConfig(&_AutomationRegistry.TransactOpts, signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) SetConfig(signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SetConfig(&_AutomationRegistry.TransactOpts, signers, transmitters, f, onchainConfigBytes, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) SetConfigTypeSafe(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "setConfigTypeSafe", signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistrySession) SetConfigTypeSafe(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SetConfigTypeSafe(&_AutomationRegistry.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) SetConfigTypeSafe(signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SetConfigTypeSafe(&_AutomationRegistry.TransactOpts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) SimulatePerformUpkeep(opts *bind.TransactOpts, id *big.Int, performData []byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "simulatePerformUpkeep", id, performData) +} + +func (_AutomationRegistry *AutomationRegistrySession) SimulatePerformUpkeep(id *big.Int, performData []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SimulatePerformUpkeep(&_AutomationRegistry.TransactOpts, id, performData) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) SimulatePerformUpkeep(id *big.Int, performData []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.SimulatePerformUpkeep(&_AutomationRegistry.TransactOpts, id, performData) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "transferOwnership", to) +} + +func (_AutomationRegistry *AutomationRegistrySession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistry.Contract.TransferOwnership(&_AutomationRegistry.TransactOpts, to) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _AutomationRegistry.Contract.TransferOwnership(&_AutomationRegistry.TransactOpts, to) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.Transact(opts, "transmit", reportContext, rawReport, rs, ss, rawVs) +} + +func (_AutomationRegistry *AutomationRegistrySession) Transmit(reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.Transmit(&_AutomationRegistry.TransactOpts, reportContext, rawReport, rs, ss, rawVs) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) Transmit(reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.Transmit(&_AutomationRegistry.TransactOpts, reportContext, rawReport, rs, ss, rawVs) +} + +func (_AutomationRegistry *AutomationRegistryTransactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) { + return _AutomationRegistry.contract.RawTransact(opts, calldata) +} + +func (_AutomationRegistry *AutomationRegistrySession) Fallback(calldata []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.Fallback(&_AutomationRegistry.TransactOpts, calldata) +} + +func (_AutomationRegistry *AutomationRegistryTransactorSession) Fallback(calldata []byte) (*types.Transaction, error) { + return _AutomationRegistry.Contract.Fallback(&_AutomationRegistry.TransactOpts, calldata) +} + +type AutomationRegistryAdminPrivilegeConfigSetIterator struct { + Event *AutomationRegistryAdminPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryAdminPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryAdminPrivilegeConfigSet) + 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(AutomationRegistryAdminPrivilegeConfigSet) + 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 *AutomationRegistryAdminPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryAdminPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryAdminPrivilegeConfigSet struct { + Admin common.Address + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryAdminPrivilegeConfigSetIterator, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return &AutomationRegistryAdminPrivilegeConfigSetIterator{contract: _AutomationRegistry.contract, event: "AdminPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) { + + var adminRule []interface{} + for _, adminItem := range admin { + adminRule = append(adminRule, adminItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "AdminPrivilegeConfigSet", adminRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryAdminPrivilegeConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "AdminPrivilegeConfigSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryAdminPrivilegeConfigSet, error) { + event := new(AutomationRegistryAdminPrivilegeConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "AdminPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryCancelledUpkeepReportIterator struct { + Event *AutomationRegistryCancelledUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryCancelledUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryCancelledUpkeepReport) + 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(AutomationRegistryCancelledUpkeepReport) + 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 *AutomationRegistryCancelledUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryCancelledUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryCancelledUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryCancelledUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryCancelledUpkeepReportIterator{contract: _AutomationRegistry.contract, event: "CancelledUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "CancelledUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryCancelledUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "CancelledUpkeepReport", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryCancelledUpkeepReport, error) { + event := new(AutomationRegistryCancelledUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "CancelledUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryConfigSetIterator struct { + Event *AutomationRegistryConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryConfigSet) + 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(AutomationRegistryConfigSet) + 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 *AutomationRegistryConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryConfigSet struct { + PreviousConfigBlockNumber uint32 + ConfigDigest [32]byte + ConfigCount uint64 + Signers []common.Address + Transmitters []common.Address + F uint8 + OnchainConfig []byte + OffchainConfigVersion uint64 + OffchainConfig []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterConfigSet(opts *bind.FilterOpts) (*AutomationRegistryConfigSetIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return &AutomationRegistryConfigSetIterator{contract: _AutomationRegistry.contract, event: "ConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryConfigSet) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "ConfigSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseConfigSet(log types.Log) (*AutomationRegistryConfigSet, error) { + event := new(AutomationRegistryConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "ConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryDedupKeyAddedIterator struct { + Event *AutomationRegistryDedupKeyAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryDedupKeyAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryDedupKeyAdded) + 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(AutomationRegistryDedupKeyAdded) + 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 *AutomationRegistryDedupKeyAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryDedupKeyAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryDedupKeyAdded struct { + DedupKey [32]byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryDedupKeyAddedIterator, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return &AutomationRegistryDedupKeyAddedIterator{contract: _AutomationRegistry.contract, event: "DedupKeyAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) { + + var dedupKeyRule []interface{} + for _, dedupKeyItem := range dedupKey { + dedupKeyRule = append(dedupKeyRule, dedupKeyItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "DedupKeyAdded", dedupKeyRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryDedupKeyAdded) + if err := _AutomationRegistry.contract.UnpackLog(event, "DedupKeyAdded", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseDedupKeyAdded(log types.Log) (*AutomationRegistryDedupKeyAdded, error) { + event := new(AutomationRegistryDedupKeyAdded) + if err := _AutomationRegistry.contract.UnpackLog(event, "DedupKeyAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryFundsAddedIterator struct { + Event *AutomationRegistryFundsAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryFundsAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryFundsAdded) + 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(AutomationRegistryFundsAdded) + 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 *AutomationRegistryFundsAddedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryFundsAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryFundsAdded struct { + Id *big.Int + From common.Address + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryFundsAddedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return &AutomationRegistryFundsAddedIterator{contract: _AutomationRegistry.contract, event: "FundsAdded", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var fromRule []interface{} + for _, fromItem := range from { + fromRule = append(fromRule, fromItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "FundsAdded", idRule, fromRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryFundsAdded) + if err := _AutomationRegistry.contract.UnpackLog(event, "FundsAdded", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseFundsAdded(log types.Log) (*AutomationRegistryFundsAdded, error) { + event := new(AutomationRegistryFundsAdded) + if err := _AutomationRegistry.contract.UnpackLog(event, "FundsAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryFundsWithdrawnIterator struct { + Event *AutomationRegistryFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryFundsWithdrawn) + 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(AutomationRegistryFundsWithdrawn) + 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 *AutomationRegistryFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryFundsWithdrawn struct { + Id *big.Int + Amount *big.Int + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryFundsWithdrawnIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryFundsWithdrawnIterator{contract: _AutomationRegistry.contract, event: "FundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFundsWithdrawn, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "FundsWithdrawn", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryFundsWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "FundsWithdrawn", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseFundsWithdrawn(log types.Log) (*AutomationRegistryFundsWithdrawn, error) { + event := new(AutomationRegistryFundsWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "FundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryInsufficientFundsUpkeepReportIterator struct { + Event *AutomationRegistryInsufficientFundsUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryInsufficientFundsUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryInsufficientFundsUpkeepReport) + 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(AutomationRegistryInsufficientFundsUpkeepReport) + 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 *AutomationRegistryInsufficientFundsUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryInsufficientFundsUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryInsufficientFundsUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryInsufficientFundsUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryInsufficientFundsUpkeepReportIterator{contract: _AutomationRegistry.contract, event: "InsufficientFundsUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "InsufficientFundsUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryInsufficientFundsUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryInsufficientFundsUpkeepReport, error) { + event := new(AutomationRegistryInsufficientFundsUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "InsufficientFundsUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryOwnerFundsWithdrawnIterator struct { + Event *AutomationRegistryOwnerFundsWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryOwnerFundsWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryOwnerFundsWithdrawn) + 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(AutomationRegistryOwnerFundsWithdrawn) + 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 *AutomationRegistryOwnerFundsWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryOwnerFundsWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryOwnerFundsWithdrawn struct { + Amount *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryOwnerFundsWithdrawnIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return &AutomationRegistryOwnerFundsWithdrawnIterator{contract: _AutomationRegistry.contract, event: "OwnerFundsWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnerFundsWithdrawn) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "OwnerFundsWithdrawn") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryOwnerFundsWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "OwnerFundsWithdrawn", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryOwnerFundsWithdrawn, error) { + event := new(AutomationRegistryOwnerFundsWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "OwnerFundsWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryOwnershipTransferRequestedIterator struct { + Event *AutomationRegistryOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryOwnershipTransferRequested) + 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(AutomationRegistryOwnershipTransferRequested) + 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 *AutomationRegistryOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryOwnershipTransferRequestedIterator, 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 := _AutomationRegistry.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryOwnershipTransferRequestedIterator{contract: _AutomationRegistry.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnershipTransferRequested, 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 := _AutomationRegistry.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(AutomationRegistryOwnershipTransferRequested) + if err := _AutomationRegistry.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 (_AutomationRegistry *AutomationRegistryFilterer) ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryOwnershipTransferRequested, error) { + event := new(AutomationRegistryOwnershipTransferRequested) + if err := _AutomationRegistry.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryOwnershipTransferredIterator struct { + Event *AutomationRegistryOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryOwnershipTransferred) + 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(AutomationRegistryOwnershipTransferred) + 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 *AutomationRegistryOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryOwnershipTransferredIterator, 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 := _AutomationRegistry.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryOwnershipTransferredIterator{contract: _AutomationRegistry.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnershipTransferred, 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 := _AutomationRegistry.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(AutomationRegistryOwnershipTransferred) + if err := _AutomationRegistry.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 (_AutomationRegistry *AutomationRegistryFilterer) ParseOwnershipTransferred(log types.Log) (*AutomationRegistryOwnershipTransferred, error) { + event := new(AutomationRegistryOwnershipTransferred) + if err := _AutomationRegistry.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryPausedIterator struct { + Event *AutomationRegistryPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryPaused) + 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(AutomationRegistryPaused) + 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 *AutomationRegistryPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryPaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryPausedIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "Paused") + if err != nil { + return nil, err + } + return &AutomationRegistryPausedIterator{contract: _AutomationRegistry.contract, event: "Paused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "Paused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryPaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "Paused", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParsePaused(log types.Log) (*AutomationRegistryPaused, error) { + event := new(AutomationRegistryPaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "Paused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryPayeesUpdatedIterator struct { + Event *AutomationRegistryPayeesUpdated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryPayeesUpdatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryPayeesUpdated) + 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(AutomationRegistryPayeesUpdated) + 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 *AutomationRegistryPayeesUpdatedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryPayeesUpdatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryPayeesUpdated struct { + Transmitters []common.Address + Payees []common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryPayeesUpdatedIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return &AutomationRegistryPayeesUpdatedIterator{contract: _AutomationRegistry.contract, event: "PayeesUpdated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeesUpdated) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "PayeesUpdated") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryPayeesUpdated) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeesUpdated", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParsePayeesUpdated(log types.Log) (*AutomationRegistryPayeesUpdated, error) { + event := new(AutomationRegistryPayeesUpdated) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeesUpdated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryPayeeshipTransferRequestedIterator struct { + Event *AutomationRegistryPayeeshipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryPayeeshipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryPayeeshipTransferRequested) + 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(AutomationRegistryPayeeshipTransferRequested) + 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 *AutomationRegistryPayeeshipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryPayeeshipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryPayeeshipTransferRequested struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryPayeeshipTransferRequestedIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistry.contract.FilterLogs(opts, "PayeeshipTransferRequested", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryPayeeshipTransferRequestedIterator{contract: _AutomationRegistry.contract, event: "PayeeshipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistry.contract.WatchLogs(opts, "PayeeshipTransferRequested", transmitterRule, 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(AutomationRegistryPayeeshipTransferRequested) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeeshipTransferRequested", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryPayeeshipTransferRequested, error) { + event := new(AutomationRegistryPayeeshipTransferRequested) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeeshipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryPayeeshipTransferredIterator struct { + Event *AutomationRegistryPayeeshipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryPayeeshipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryPayeeshipTransferred) + 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(AutomationRegistryPayeeshipTransferred) + 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 *AutomationRegistryPayeeshipTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryPayeeshipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryPayeeshipTransferred struct { + Transmitter common.Address + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryPayeeshipTransferredIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistry.contract.FilterLogs(opts, "PayeeshipTransferred", transmitterRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryPayeeshipTransferredIterator{contract: _AutomationRegistry.contract, event: "PayeeshipTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + 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 := _AutomationRegistry.contract.WatchLogs(opts, "PayeeshipTransferred", transmitterRule, 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(AutomationRegistryPayeeshipTransferred) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeeshipTransferred", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryPayeeshipTransferred, error) { + event := new(AutomationRegistryPayeeshipTransferred) + if err := _AutomationRegistry.contract.UnpackLog(event, "PayeeshipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryPaymentWithdrawnIterator struct { + Event *AutomationRegistryPaymentWithdrawn + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryPaymentWithdrawnIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryPaymentWithdrawn) + 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(AutomationRegistryPaymentWithdrawn) + 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 *AutomationRegistryPaymentWithdrawnIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryPaymentWithdrawnIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryPaymentWithdrawn struct { + Transmitter common.Address + Amount *big.Int + To common.Address + Payee common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryPaymentWithdrawnIterator, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryPaymentWithdrawnIterator{contract: _AutomationRegistry.contract, event: "PaymentWithdrawn", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) { + + var transmitterRule []interface{} + for _, transmitterItem := range transmitter { + transmitterRule = append(transmitterRule, transmitterItem) + } + var amountRule []interface{} + for _, amountItem := range amount { + amountRule = append(amountRule, amountItem) + } + var toRule []interface{} + for _, toItem := range to { + toRule = append(toRule, toItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "PaymentWithdrawn", transmitterRule, amountRule, 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(AutomationRegistryPaymentWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "PaymentWithdrawn", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryPaymentWithdrawn, error) { + event := new(AutomationRegistryPaymentWithdrawn) + if err := _AutomationRegistry.contract.UnpackLog(event, "PaymentWithdrawn", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryReorgedUpkeepReportIterator struct { + Event *AutomationRegistryReorgedUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryReorgedUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryReorgedUpkeepReport) + 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(AutomationRegistryReorgedUpkeepReport) + 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 *AutomationRegistryReorgedUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryReorgedUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryReorgedUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryReorgedUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryReorgedUpkeepReportIterator{contract: _AutomationRegistry.contract, event: "ReorgedUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "ReorgedUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryReorgedUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "ReorgedUpkeepReport", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryReorgedUpkeepReport, error) { + event := new(AutomationRegistryReorgedUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "ReorgedUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryStaleUpkeepReportIterator struct { + Event *AutomationRegistryStaleUpkeepReport + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryStaleUpkeepReportIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryStaleUpkeepReport) + 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(AutomationRegistryStaleUpkeepReport) + 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 *AutomationRegistryStaleUpkeepReportIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryStaleUpkeepReportIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryStaleUpkeepReport struct { + Id *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryStaleUpkeepReportIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryStaleUpkeepReportIterator{contract: _AutomationRegistry.contract, event: "StaleUpkeepReport", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryStaleUpkeepReport, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "StaleUpkeepReport", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryStaleUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "StaleUpkeepReport", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryStaleUpkeepReport, error) { + event := new(AutomationRegistryStaleUpkeepReport) + if err := _AutomationRegistry.contract.UnpackLog(event, "StaleUpkeepReport", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryTransmittedIterator struct { + Event *AutomationRegistryTransmitted + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryTransmittedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryTransmitted) + 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(AutomationRegistryTransmitted) + 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 *AutomationRegistryTransmittedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryTransmittedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryTransmitted struct { + ConfigDigest [32]byte + Epoch uint32 + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterTransmitted(opts *bind.FilterOpts) (*AutomationRegistryTransmittedIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "Transmitted") + if err != nil { + return nil, err + } + return &AutomationRegistryTransmittedIterator{contract: _AutomationRegistry.contract, event: "Transmitted", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *AutomationRegistryTransmitted) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "Transmitted") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryTransmitted) + if err := _AutomationRegistry.contract.UnpackLog(event, "Transmitted", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseTransmitted(log types.Log) (*AutomationRegistryTransmitted, error) { + event := new(AutomationRegistryTransmitted) + if err := _AutomationRegistry.contract.UnpackLog(event, "Transmitted", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUnpausedIterator struct { + Event *AutomationRegistryUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUnpaused) + 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(AutomationRegistryUnpaused) + 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 *AutomationRegistryUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUnpaused struct { + Account common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryUnpausedIterator, error) { + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return &AutomationRegistryUnpausedIterator{contract: _AutomationRegistry.contract, event: "Unpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUnpaused) (event.Subscription, error) { + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "Unpaused") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUnpaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "Unpaused", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUnpaused(log types.Log) (*AutomationRegistryUnpaused, error) { + event := new(AutomationRegistryUnpaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "Unpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepAdminTransferRequestedIterator struct { + Event *AutomationRegistryUpkeepAdminTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepAdminTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepAdminTransferRequested) + 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(AutomationRegistryUpkeepAdminTransferRequested) + 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 *AutomationRegistryUpkeepAdminTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepAdminTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepAdminTransferRequested struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryUpkeepAdminTransferRequestedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepAdminTransferRequested", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepAdminTransferRequestedIterator{contract: _AutomationRegistry.contract, event: "UpkeepAdminTransferRequested", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepAdminTransferRequested", idRule, 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(AutomationRegistryUpkeepAdminTransferRequested) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepAdminTransferRequested", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryUpkeepAdminTransferRequested, error) { + event := new(AutomationRegistryUpkeepAdminTransferRequested) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepAdminTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepAdminTransferredIterator struct { + Event *AutomationRegistryUpkeepAdminTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepAdminTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepAdminTransferred) + 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(AutomationRegistryUpkeepAdminTransferred) + 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 *AutomationRegistryUpkeepAdminTransferredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepAdminTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepAdminTransferred struct { + Id *big.Int + From common.Address + To common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryUpkeepAdminTransferredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepAdminTransferred", idRule, fromRule, toRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepAdminTransferredIterator{contract: _AutomationRegistry.contract, event: "UpkeepAdminTransferred", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + 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 := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepAdminTransferred", idRule, 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(AutomationRegistryUpkeepAdminTransferred) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepAdminTransferred", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryUpkeepAdminTransferred, error) { + event := new(AutomationRegistryUpkeepAdminTransferred) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepAdminTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepCanceledIterator struct { + Event *AutomationRegistryUpkeepCanceled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepCanceledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepCanceled) + 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(AutomationRegistryUpkeepCanceled) + 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 *AutomationRegistryUpkeepCanceledIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepCanceledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepCanceled struct { + Id *big.Int + AtBlockHeight uint64 + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryUpkeepCanceledIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepCanceledIterator{contract: _AutomationRegistry.contract, event: "UpkeepCanceled", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var atBlockHeightRule []interface{} + for _, atBlockHeightItem := range atBlockHeight { + atBlockHeightRule = append(atBlockHeightRule, atBlockHeightItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepCanceled", idRule, atBlockHeightRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepCanceled) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepCanceled", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepCanceled(log types.Log) (*AutomationRegistryUpkeepCanceled, error) { + event := new(AutomationRegistryUpkeepCanceled) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepCanceled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepCheckDataSetIterator struct { + Event *AutomationRegistryUpkeepCheckDataSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepCheckDataSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepCheckDataSet) + 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(AutomationRegistryUpkeepCheckDataSet) + 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 *AutomationRegistryUpkeepCheckDataSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepCheckDataSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepCheckDataSet struct { + Id *big.Int + NewCheckData []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepCheckDataSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepCheckDataSetIterator{contract: _AutomationRegistry.contract, event: "UpkeepCheckDataSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepCheckDataSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepCheckDataSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepCheckDataSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryUpkeepCheckDataSet, error) { + event := new(AutomationRegistryUpkeepCheckDataSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepCheckDataSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepGasLimitSetIterator struct { + Event *AutomationRegistryUpkeepGasLimitSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepGasLimitSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepGasLimitSet) + 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(AutomationRegistryUpkeepGasLimitSet) + 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 *AutomationRegistryUpkeepGasLimitSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepGasLimitSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepGasLimitSet struct { + Id *big.Int + GasLimit *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepGasLimitSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepGasLimitSetIterator{contract: _AutomationRegistry.contract, event: "UpkeepGasLimitSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepGasLimitSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepGasLimitSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepGasLimitSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryUpkeepGasLimitSet, error) { + event := new(AutomationRegistryUpkeepGasLimitSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepGasLimitSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepMigratedIterator struct { + Event *AutomationRegistryUpkeepMigrated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepMigratedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepMigrated) + 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(AutomationRegistryUpkeepMigrated) + 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 *AutomationRegistryUpkeepMigratedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepMigratedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepMigrated struct { + Id *big.Int + RemainingBalance *big.Int + Destination common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepMigratedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepMigratedIterator{contract: _AutomationRegistry.contract, event: "UpkeepMigrated", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepMigrated, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepMigrated", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepMigrated) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepMigrated", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepMigrated(log types.Log) (*AutomationRegistryUpkeepMigrated, error) { + event := new(AutomationRegistryUpkeepMigrated) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepMigrated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepOffchainConfigSetIterator struct { + Event *AutomationRegistryUpkeepOffchainConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepOffchainConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepOffchainConfigSet) + 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(AutomationRegistryUpkeepOffchainConfigSet) + 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 *AutomationRegistryUpkeepOffchainConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepOffchainConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepOffchainConfigSet struct { + Id *big.Int + OffchainConfig []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepOffchainConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepOffchainConfigSetIterator{contract: _AutomationRegistry.contract, event: "UpkeepOffchainConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepOffchainConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepOffchainConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepOffchainConfigSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryUpkeepOffchainConfigSet, error) { + event := new(AutomationRegistryUpkeepOffchainConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepOffchainConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepPausedIterator struct { + Event *AutomationRegistryUpkeepPaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepPausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepPaused) + 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(AutomationRegistryUpkeepPaused) + 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 *AutomationRegistryUpkeepPausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepPausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepPaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepPausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepPausedIterator{contract: _AutomationRegistry.contract, event: "UpkeepPaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepPaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepPaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPaused", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepPaused(log types.Log) (*AutomationRegistryUpkeepPaused, error) { + event := new(AutomationRegistryUpkeepPaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepPerformedIterator struct { + Event *AutomationRegistryUpkeepPerformed + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepPerformedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepPerformed) + 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(AutomationRegistryUpkeepPerformed) + 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 *AutomationRegistryUpkeepPerformedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepPerformedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepPerformed struct { + Id *big.Int + Success bool + TotalPayment *big.Int + GasUsed *big.Int + GasOverhead *big.Int + Trigger []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryUpkeepPerformedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepPerformedIterator{contract: _AutomationRegistry.contract, event: "UpkeepPerformed", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + var successRule []interface{} + for _, successItem := range success { + successRule = append(successRule, successItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepPerformed", idRule, successRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepPerformed) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPerformed", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepPerformed(log types.Log) (*AutomationRegistryUpkeepPerformed, error) { + event := new(AutomationRegistryUpkeepPerformed) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPerformed", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepPrivilegeConfigSetIterator struct { + Event *AutomationRegistryUpkeepPrivilegeConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepPrivilegeConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepPrivilegeConfigSet) + 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(AutomationRegistryUpkeepPrivilegeConfigSet) + 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 *AutomationRegistryUpkeepPrivilegeConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepPrivilegeConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepPrivilegeConfigSet struct { + Id *big.Int + PrivilegeConfig []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepPrivilegeConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepPrivilegeConfigSetIterator{contract: _AutomationRegistry.contract, event: "UpkeepPrivilegeConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepPrivilegeConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepPrivilegeConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryUpkeepPrivilegeConfigSet, error) { + event := new(AutomationRegistryUpkeepPrivilegeConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepPrivilegeConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepReceivedIterator struct { + Event *AutomationRegistryUpkeepReceived + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepReceivedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepReceived) + 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(AutomationRegistryUpkeepReceived) + 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 *AutomationRegistryUpkeepReceivedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepReceivedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepReceived struct { + Id *big.Int + StartingBalance *big.Int + ImportedFrom common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepReceivedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepReceivedIterator{contract: _AutomationRegistry.contract, event: "UpkeepReceived", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepReceived, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepReceived", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepReceived) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepReceived", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepReceived(log types.Log) (*AutomationRegistryUpkeepReceived, error) { + event := new(AutomationRegistryUpkeepReceived) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepReceived", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepRegisteredIterator struct { + Event *AutomationRegistryUpkeepRegistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepRegisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepRegistered) + 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(AutomationRegistryUpkeepRegistered) + 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 *AutomationRegistryUpkeepRegisteredIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepRegistered struct { + Id *big.Int + PerformGas uint32 + Admin common.Address + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepRegisteredIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepRegisteredIterator{contract: _AutomationRegistry.contract, event: "UpkeepRegistered", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepRegistered, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepRegistered", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepRegistered) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepRegistered", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepRegistered(log types.Log) (*AutomationRegistryUpkeepRegistered, error) { + event := new(AutomationRegistryUpkeepRegistered) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepTriggerConfigSetIterator struct { + Event *AutomationRegistryUpkeepTriggerConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepTriggerConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepTriggerConfigSet) + 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(AutomationRegistryUpkeepTriggerConfigSet) + 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 *AutomationRegistryUpkeepTriggerConfigSetIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepTriggerConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepTriggerConfigSet struct { + Id *big.Int + TriggerConfig []byte + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepTriggerConfigSetIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepTriggerConfigSetIterator{contract: _AutomationRegistry.contract, event: "UpkeepTriggerConfigSet", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepTriggerConfigSet", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepTriggerConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepTriggerConfigSet", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryUpkeepTriggerConfigSet, error) { + event := new(AutomationRegistryUpkeepTriggerConfigSet) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepTriggerConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type AutomationRegistryUpkeepUnpausedIterator struct { + Event *AutomationRegistryUpkeepUnpaused + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *AutomationRegistryUpkeepUnpausedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(AutomationRegistryUpkeepUnpaused) + 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(AutomationRegistryUpkeepUnpaused) + 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 *AutomationRegistryUpkeepUnpausedIterator) Error() error { + return it.fail +} + +func (it *AutomationRegistryUpkeepUnpausedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type AutomationRegistryUpkeepUnpaused struct { + Id *big.Int + Raw types.Log +} + +func (_AutomationRegistry *AutomationRegistryFilterer) FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepUnpausedIterator, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.FilterLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return &AutomationRegistryUpkeepUnpausedIterator{contract: _AutomationRegistry.contract, event: "UpkeepUnpaused", logs: logs, sub: sub}, nil +} + +func (_AutomationRegistry *AutomationRegistryFilterer) WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepUnpaused, id []*big.Int) (event.Subscription, error) { + + var idRule []interface{} + for _, idItem := range id { + idRule = append(idRule, idItem) + } + + logs, sub, err := _AutomationRegistry.contract.WatchLogs(opts, "UpkeepUnpaused", idRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(AutomationRegistryUpkeepUnpaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepUnpaused", 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 (_AutomationRegistry *AutomationRegistryFilterer) ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryUpkeepUnpaused, error) { + event := new(AutomationRegistryUpkeepUnpaused) + if err := _AutomationRegistry.contract.UnpackLog(event, "UpkeepUnpaused", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type LatestConfigDetails struct { + ConfigCount uint32 + BlockNumber uint32 + ConfigDigest [32]byte +} +type LatestConfigDigestAndEpoch struct { + ScanLogs bool + ConfigDigest [32]byte + Epoch uint32 +} + +func (_AutomationRegistry *AutomationRegistry) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _AutomationRegistry.abi.Events["AdminPrivilegeConfigSet"].ID: + return _AutomationRegistry.ParseAdminPrivilegeConfigSet(log) + case _AutomationRegistry.abi.Events["CancelledUpkeepReport"].ID: + return _AutomationRegistry.ParseCancelledUpkeepReport(log) + case _AutomationRegistry.abi.Events["ConfigSet"].ID: + return _AutomationRegistry.ParseConfigSet(log) + case _AutomationRegistry.abi.Events["DedupKeyAdded"].ID: + return _AutomationRegistry.ParseDedupKeyAdded(log) + case _AutomationRegistry.abi.Events["FundsAdded"].ID: + return _AutomationRegistry.ParseFundsAdded(log) + case _AutomationRegistry.abi.Events["FundsWithdrawn"].ID: + return _AutomationRegistry.ParseFundsWithdrawn(log) + case _AutomationRegistry.abi.Events["InsufficientFundsUpkeepReport"].ID: + return _AutomationRegistry.ParseInsufficientFundsUpkeepReport(log) + case _AutomationRegistry.abi.Events["OwnerFundsWithdrawn"].ID: + return _AutomationRegistry.ParseOwnerFundsWithdrawn(log) + case _AutomationRegistry.abi.Events["OwnershipTransferRequested"].ID: + return _AutomationRegistry.ParseOwnershipTransferRequested(log) + case _AutomationRegistry.abi.Events["OwnershipTransferred"].ID: + return _AutomationRegistry.ParseOwnershipTransferred(log) + case _AutomationRegistry.abi.Events["Paused"].ID: + return _AutomationRegistry.ParsePaused(log) + case _AutomationRegistry.abi.Events["PayeesUpdated"].ID: + return _AutomationRegistry.ParsePayeesUpdated(log) + case _AutomationRegistry.abi.Events["PayeeshipTransferRequested"].ID: + return _AutomationRegistry.ParsePayeeshipTransferRequested(log) + case _AutomationRegistry.abi.Events["PayeeshipTransferred"].ID: + return _AutomationRegistry.ParsePayeeshipTransferred(log) + case _AutomationRegistry.abi.Events["PaymentWithdrawn"].ID: + return _AutomationRegistry.ParsePaymentWithdrawn(log) + case _AutomationRegistry.abi.Events["ReorgedUpkeepReport"].ID: + return _AutomationRegistry.ParseReorgedUpkeepReport(log) + case _AutomationRegistry.abi.Events["StaleUpkeepReport"].ID: + return _AutomationRegistry.ParseStaleUpkeepReport(log) + case _AutomationRegistry.abi.Events["Transmitted"].ID: + return _AutomationRegistry.ParseTransmitted(log) + case _AutomationRegistry.abi.Events["Unpaused"].ID: + return _AutomationRegistry.ParseUnpaused(log) + case _AutomationRegistry.abi.Events["UpkeepAdminTransferRequested"].ID: + return _AutomationRegistry.ParseUpkeepAdminTransferRequested(log) + case _AutomationRegistry.abi.Events["UpkeepAdminTransferred"].ID: + return _AutomationRegistry.ParseUpkeepAdminTransferred(log) + case _AutomationRegistry.abi.Events["UpkeepCanceled"].ID: + return _AutomationRegistry.ParseUpkeepCanceled(log) + case _AutomationRegistry.abi.Events["UpkeepCheckDataSet"].ID: + return _AutomationRegistry.ParseUpkeepCheckDataSet(log) + case _AutomationRegistry.abi.Events["UpkeepGasLimitSet"].ID: + return _AutomationRegistry.ParseUpkeepGasLimitSet(log) + case _AutomationRegistry.abi.Events["UpkeepMigrated"].ID: + return _AutomationRegistry.ParseUpkeepMigrated(log) + case _AutomationRegistry.abi.Events["UpkeepOffchainConfigSet"].ID: + return _AutomationRegistry.ParseUpkeepOffchainConfigSet(log) + case _AutomationRegistry.abi.Events["UpkeepPaused"].ID: + return _AutomationRegistry.ParseUpkeepPaused(log) + case _AutomationRegistry.abi.Events["UpkeepPerformed"].ID: + return _AutomationRegistry.ParseUpkeepPerformed(log) + case _AutomationRegistry.abi.Events["UpkeepPrivilegeConfigSet"].ID: + return _AutomationRegistry.ParseUpkeepPrivilegeConfigSet(log) + case _AutomationRegistry.abi.Events["UpkeepReceived"].ID: + return _AutomationRegistry.ParseUpkeepReceived(log) + case _AutomationRegistry.abi.Events["UpkeepRegistered"].ID: + return _AutomationRegistry.ParseUpkeepRegistered(log) + case _AutomationRegistry.abi.Events["UpkeepTriggerConfigSet"].ID: + return _AutomationRegistry.ParseUpkeepTriggerConfigSet(log) + case _AutomationRegistry.abi.Events["UpkeepUnpaused"].ID: + return _AutomationRegistry.ParseUpkeepUnpaused(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (AutomationRegistryAdminPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x7c44b4eb59ee7873514e7e43e7718c269d872965938b288aa143befca62f99d2") +} + +func (AutomationRegistryCancelledUpkeepReport) Topic() common.Hash { + return common.HexToHash("0xc3237c8807c467c1b39b8d0395eff077313e691bf0a7388106792564ebfd5636") +} + +func (AutomationRegistryConfigSet) Topic() common.Hash { + return common.HexToHash("0x1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05") +} + +func (AutomationRegistryDedupKeyAdded) Topic() common.Hash { + return common.HexToHash("0xa4a4e334c0e330143f9437484fe516c13bc560b86b5b0daf58e7084aaac228f2") +} + +func (AutomationRegistryFundsAdded) Topic() common.Hash { + return common.HexToHash("0xafd24114486da8ebfc32f3626dada8863652e187461aa74d4bfa734891506203") +} + +func (AutomationRegistryFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0xf3b5906e5672f3e524854103bcafbbdba80dbdfeca2c35e116127b1060a68318") +} + +func (AutomationRegistryInsufficientFundsUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x377c8b0c126ae5248d27aca1c76fac4608aff85673ee3caf09747e1044549e02") +} + +func (AutomationRegistryOwnerFundsWithdrawn) Topic() common.Hash { + return common.HexToHash("0x1d07d0b0be43d3e5fee41a80b579af370affee03fa595bf56d5d4c19328162f1") +} + +func (AutomationRegistryOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (AutomationRegistryOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (AutomationRegistryPaused) Topic() common.Hash { + return common.HexToHash("0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258") +} + +func (AutomationRegistryPayeesUpdated) Topic() common.Hash { + return common.HexToHash("0xa46de38886467c59be07a0675f14781206a5477d871628af46c2443822fcb725") +} + +func (AutomationRegistryPayeeshipTransferRequested) Topic() common.Hash { + return common.HexToHash("0x84f7c7c80bb8ed2279b4aab5f61cd05e6374073d38f46d7f32de8c30e9e38367") +} + +func (AutomationRegistryPayeeshipTransferred) Topic() common.Hash { + return common.HexToHash("0x78af32efdcad432315431e9b03d27e6cd98fb79c405fdc5af7c1714d9c0f75b3") +} + +func (AutomationRegistryPaymentWithdrawn) Topic() common.Hash { + return common.HexToHash("0x9819093176a1851202c7bcfa46845809b4e47c261866550e94ed3775d2f40698") +} + +func (AutomationRegistryReorgedUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x6aa7f60c176da7af894b384daea2249497448137f5943c1237ada8bc92bdc301") +} + +func (AutomationRegistryStaleUpkeepReport) Topic() common.Hash { + return common.HexToHash("0x405288ea7be309e16cfdf481367f90a413e1d4634fcdaf8966546db9b93012e8") +} + +func (AutomationRegistryTransmitted) Topic() common.Hash { + return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62") +} + +func (AutomationRegistryUnpaused) Topic() common.Hash { + return common.HexToHash("0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa") +} + +func (AutomationRegistryUpkeepAdminTransferRequested) Topic() common.Hash { + return common.HexToHash("0xb1cbb2c4b8480034c27e06da5f096b8233a8fd4497028593a41ff6df79726b35") +} + +func (AutomationRegistryUpkeepAdminTransferred) Topic() common.Hash { + return common.HexToHash("0x5cff4db96bef051785e999f44bfcd21c18823e034fb92dd376e3db4ce0feeb2c") +} + +func (AutomationRegistryUpkeepCanceled) Topic() common.Hash { + return common.HexToHash("0x91cb3bb75cfbd718bbfccc56b7f53d92d7048ef4ca39a3b7b7c6d4af1f791181") +} + +func (AutomationRegistryUpkeepCheckDataSet) Topic() common.Hash { + return common.HexToHash("0xcba2d5723b2ee59e53a8e8a82a4a7caf4fdfe70e9f7c582950bf7e7a5c24e83d") +} + +func (AutomationRegistryUpkeepGasLimitSet) Topic() common.Hash { + return common.HexToHash("0xc24c07e655ce79fba8a589778987d3c015bc6af1632bb20cf9182e02a65d972c") +} + +func (AutomationRegistryUpkeepMigrated) Topic() common.Hash { + return common.HexToHash("0xb38647142fbb1ea4c000fc4569b37a4e9a9f6313317b84ee3e5326c1a6cd06ff") +} + +func (AutomationRegistryUpkeepOffchainConfigSet) Topic() common.Hash { + return common.HexToHash("0x3e8740446213c8a77d40e08f79136ce3f347d13ed270a6ebdf57159e0faf4850") +} + +func (AutomationRegistryUpkeepPaused) Topic() common.Hash { + return common.HexToHash("0x8ab10247ce168c27748e656ecf852b951fcaac790c18106b19aa0ae57a8b741f") +} + +func (AutomationRegistryUpkeepPerformed) Topic() common.Hash { + return common.HexToHash("0xad8cc9579b21dfe2c2f6ea35ba15b656e46b4f5b0cb424f52739b8ce5cac9c5b") +} + +func (AutomationRegistryUpkeepPrivilegeConfigSet) Topic() common.Hash { + return common.HexToHash("0x2fd8d70753a007014349d4591843cc031c2dd7a260d7dd82eca8253686ae7769") +} + +func (AutomationRegistryUpkeepReceived) Topic() common.Hash { + return common.HexToHash("0x74931a144e43a50694897f241d973aecb5024c0e910f9bb80a163ea3c1cf5a71") +} + +func (AutomationRegistryUpkeepRegistered) Topic() common.Hash { + return common.HexToHash("0xbae366358c023f887e791d7a62f2e4316f1026bd77f6fb49501a917b3bc5d012") +} + +func (AutomationRegistryUpkeepTriggerConfigSet) Topic() common.Hash { + return common.HexToHash("0x2b72ac786c97e68dbab71023ed6f2bdbfc80ad9bb7808941929229d71b7d5664") +} + +func (AutomationRegistryUpkeepUnpaused) Topic() common.Hash { + return common.HexToHash("0x7bada562044eb163f6b4003c4553e4e62825344c0418eea087bed5ee05a47456") +} + +func (_AutomationRegistry *AutomationRegistry) Address() common.Address { + return _AutomationRegistry.address +} + +type AutomationRegistryInterface interface { + FallbackTo(opts *bind.CallOpts) (common.Address, error) + + LatestConfigDetails(opts *bind.CallOpts) (LatestConfigDetails, + + error) + + LatestConfigDigestAndEpoch(opts *bind.CallOpts) (LatestConfigDigestAndEpoch, + + error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + TypeAndVersion(opts *bind.CallOpts) (string, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + OnTokenTransfer(opts *bind.TransactOpts, sender common.Address, amount *big.Int, data []byte) (*types.Transaction, error) + + SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfigBytes []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) + + SetConfigTypeSafe(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig AutomationRegistryBase22OnchainConfig, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) + + SimulatePerformUpkeep(opts *bind.TransactOpts, id *big.Int, performData []byte) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, rawReport []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) + + Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) + + FilterAdminPrivilegeConfigSet(opts *bind.FilterOpts, admin []common.Address) (*AutomationRegistryAdminPrivilegeConfigSetIterator, error) + + WatchAdminPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryAdminPrivilegeConfigSet, admin []common.Address) (event.Subscription, error) + + ParseAdminPrivilegeConfigSet(log types.Log) (*AutomationRegistryAdminPrivilegeConfigSet, error) + + FilterCancelledUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryCancelledUpkeepReportIterator, error) + + WatchCancelledUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryCancelledUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseCancelledUpkeepReport(log types.Log) (*AutomationRegistryCancelledUpkeepReport, error) + + FilterConfigSet(opts *bind.FilterOpts) (*AutomationRegistryConfigSetIterator, error) + + WatchConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryConfigSet) (event.Subscription, error) + + ParseConfigSet(log types.Log) (*AutomationRegistryConfigSet, error) + + FilterDedupKeyAdded(opts *bind.FilterOpts, dedupKey [][32]byte) (*AutomationRegistryDedupKeyAddedIterator, error) + + WatchDedupKeyAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryDedupKeyAdded, dedupKey [][32]byte) (event.Subscription, error) + + ParseDedupKeyAdded(log types.Log) (*AutomationRegistryDedupKeyAdded, error) + + FilterFundsAdded(opts *bind.FilterOpts, id []*big.Int, from []common.Address) (*AutomationRegistryFundsAddedIterator, error) + + WatchFundsAdded(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFundsAdded, id []*big.Int, from []common.Address) (event.Subscription, error) + + ParseFundsAdded(log types.Log) (*AutomationRegistryFundsAdded, error) + + FilterFundsWithdrawn(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryFundsWithdrawnIterator, error) + + WatchFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryFundsWithdrawn, id []*big.Int) (event.Subscription, error) + + ParseFundsWithdrawn(log types.Log) (*AutomationRegistryFundsWithdrawn, error) + + FilterInsufficientFundsUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryInsufficientFundsUpkeepReportIterator, error) + + WatchInsufficientFundsUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryInsufficientFundsUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseInsufficientFundsUpkeepReport(log types.Log) (*AutomationRegistryInsufficientFundsUpkeepReport, error) + + FilterOwnerFundsWithdrawn(opts *bind.FilterOpts) (*AutomationRegistryOwnerFundsWithdrawnIterator, error) + + WatchOwnerFundsWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnerFundsWithdrawn) (event.Subscription, error) + + ParseOwnerFundsWithdrawn(log types.Log) (*AutomationRegistryOwnerFundsWithdrawn, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*AutomationRegistryOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*AutomationRegistryOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*AutomationRegistryOwnershipTransferred, error) + + FilterPaused(opts *bind.FilterOpts) (*AutomationRegistryPausedIterator, error) + + WatchPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPaused) (event.Subscription, error) + + ParsePaused(log types.Log) (*AutomationRegistryPaused, error) + + FilterPayeesUpdated(opts *bind.FilterOpts) (*AutomationRegistryPayeesUpdatedIterator, error) + + WatchPayeesUpdated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeesUpdated) (event.Subscription, error) + + ParsePayeesUpdated(log types.Log) (*AutomationRegistryPayeesUpdated, error) + + FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryPayeeshipTransferRequestedIterator, error) + + WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeeshipTransferRequested, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferRequested(log types.Log) (*AutomationRegistryPayeeshipTransferRequested, error) + + FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, from []common.Address, to []common.Address) (*AutomationRegistryPayeeshipTransferredIterator, error) + + WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPayeeshipTransferred, transmitter []common.Address, from []common.Address, to []common.Address) (event.Subscription, error) + + ParsePayeeshipTransferred(log types.Log) (*AutomationRegistryPayeeshipTransferred, error) + + FilterPaymentWithdrawn(opts *bind.FilterOpts, transmitter []common.Address, amount []*big.Int, to []common.Address) (*AutomationRegistryPaymentWithdrawnIterator, error) + + WatchPaymentWithdrawn(opts *bind.WatchOpts, sink chan<- *AutomationRegistryPaymentWithdrawn, transmitter []common.Address, amount []*big.Int, to []common.Address) (event.Subscription, error) + + ParsePaymentWithdrawn(log types.Log) (*AutomationRegistryPaymentWithdrawn, error) + + FilterReorgedUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryReorgedUpkeepReportIterator, error) + + WatchReorgedUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryReorgedUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseReorgedUpkeepReport(log types.Log) (*AutomationRegistryReorgedUpkeepReport, error) + + FilterStaleUpkeepReport(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryStaleUpkeepReportIterator, error) + + WatchStaleUpkeepReport(opts *bind.WatchOpts, sink chan<- *AutomationRegistryStaleUpkeepReport, id []*big.Int) (event.Subscription, error) + + ParseStaleUpkeepReport(log types.Log) (*AutomationRegistryStaleUpkeepReport, error) + + FilterTransmitted(opts *bind.FilterOpts) (*AutomationRegistryTransmittedIterator, error) + + WatchTransmitted(opts *bind.WatchOpts, sink chan<- *AutomationRegistryTransmitted) (event.Subscription, error) + + ParseTransmitted(log types.Log) (*AutomationRegistryTransmitted, error) + + FilterUnpaused(opts *bind.FilterOpts) (*AutomationRegistryUnpausedIterator, error) + + WatchUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUnpaused) (event.Subscription, error) + + ParseUnpaused(log types.Log) (*AutomationRegistryUnpaused, error) + + FilterUpkeepAdminTransferRequested(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryUpkeepAdminTransferRequestedIterator, error) + + WatchUpkeepAdminTransferRequested(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepAdminTransferRequested, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferRequested(log types.Log) (*AutomationRegistryUpkeepAdminTransferRequested, error) + + FilterUpkeepAdminTransferred(opts *bind.FilterOpts, id []*big.Int, from []common.Address, to []common.Address) (*AutomationRegistryUpkeepAdminTransferredIterator, error) + + WatchUpkeepAdminTransferred(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepAdminTransferred, id []*big.Int, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseUpkeepAdminTransferred(log types.Log) (*AutomationRegistryUpkeepAdminTransferred, error) + + FilterUpkeepCanceled(opts *bind.FilterOpts, id []*big.Int, atBlockHeight []uint64) (*AutomationRegistryUpkeepCanceledIterator, error) + + WatchUpkeepCanceled(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepCanceled, id []*big.Int, atBlockHeight []uint64) (event.Subscription, error) + + ParseUpkeepCanceled(log types.Log) (*AutomationRegistryUpkeepCanceled, error) + + FilterUpkeepCheckDataSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepCheckDataSetIterator, error) + + WatchUpkeepCheckDataSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepCheckDataSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepCheckDataSet(log types.Log) (*AutomationRegistryUpkeepCheckDataSet, error) + + FilterUpkeepGasLimitSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepGasLimitSetIterator, error) + + WatchUpkeepGasLimitSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepGasLimitSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepGasLimitSet(log types.Log) (*AutomationRegistryUpkeepGasLimitSet, error) + + FilterUpkeepMigrated(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepMigratedIterator, error) + + WatchUpkeepMigrated(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepMigrated, id []*big.Int) (event.Subscription, error) + + ParseUpkeepMigrated(log types.Log) (*AutomationRegistryUpkeepMigrated, error) + + FilterUpkeepOffchainConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepOffchainConfigSetIterator, error) + + WatchUpkeepOffchainConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepOffchainConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepOffchainConfigSet(log types.Log) (*AutomationRegistryUpkeepOffchainConfigSet, error) + + FilterUpkeepPaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepPausedIterator, error) + + WatchUpkeepPaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPaused(log types.Log) (*AutomationRegistryUpkeepPaused, error) + + FilterUpkeepPerformed(opts *bind.FilterOpts, id []*big.Int, success []bool) (*AutomationRegistryUpkeepPerformedIterator, error) + + WatchUpkeepPerformed(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPerformed, id []*big.Int, success []bool) (event.Subscription, error) + + ParseUpkeepPerformed(log types.Log) (*AutomationRegistryUpkeepPerformed, error) + + FilterUpkeepPrivilegeConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepPrivilegeConfigSetIterator, error) + + WatchUpkeepPrivilegeConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepPrivilegeConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepPrivilegeConfigSet(log types.Log) (*AutomationRegistryUpkeepPrivilegeConfigSet, error) + + FilterUpkeepReceived(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepReceivedIterator, error) + + WatchUpkeepReceived(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepReceived, id []*big.Int) (event.Subscription, error) + + ParseUpkeepReceived(log types.Log) (*AutomationRegistryUpkeepReceived, error) + + FilterUpkeepRegistered(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepRegisteredIterator, error) + + WatchUpkeepRegistered(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepRegistered, id []*big.Int) (event.Subscription, error) + + ParseUpkeepRegistered(log types.Log) (*AutomationRegistryUpkeepRegistered, error) + + FilterUpkeepTriggerConfigSet(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepTriggerConfigSetIterator, error) + + WatchUpkeepTriggerConfigSet(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepTriggerConfigSet, id []*big.Int) (event.Subscription, error) + + ParseUpkeepTriggerConfigSet(log types.Log) (*AutomationRegistryUpkeepTriggerConfigSet, error) + + FilterUpkeepUnpaused(opts *bind.FilterOpts, id []*big.Int) (*AutomationRegistryUpkeepUnpausedIterator, error) + + WatchUpkeepUnpaused(opts *bind.WatchOpts, sink chan<- *AutomationRegistryUpkeepUnpaused, id []*big.Int) (event.Subscription, error) + + ParseUpkeepUnpaused(log types.Log) (*AutomationRegistryUpkeepUnpaused, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/log_emitter/log_emitter.go b/core/gethwrappers/generated/log_emitter/log_emitter.go index 3cb11da5125..24fef257af3 100644 --- a/core/gethwrappers/generated/log_emitter/log_emitter.go +++ b/core/gethwrappers/generated/log_emitter/log_emitter.go @@ -31,8 +31,8 @@ var ( ) var LogEmitterMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"Log1\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"Log2\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"Log3\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"v\",\"type\":\"uint256[]\"}],\"name\":\"EmitLog1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"v\",\"type\":\"uint256[]\"}],\"name\":\"EmitLog2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"v\",\"type\":\"string[]\"}],\"name\":\"EmitLog3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b5061052b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063696933c914610046578063bc253bc01461005b578063d9c21f461461006e575b600080fd5b610059610054366004610269565b610081565b005b610059610069366004610269565b6100f5565b61005961007c3660046102ff565b610159565b60005b81518110156100f1577f46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a88282815181106100c0576100c0610424565b60200260200101516040516100d791815260200190565b60405180910390a1806100e981610453565b915050610084565b5050565b60005b81518110156100f15781818151811061011357610113610424565b60200260200101517f624fb00c2ce79f34cb543884c3af64816dce0f4cec3d32661959e49d488a7a9360405160405180910390a28061015181610453565b9150506100f8565b60005b81518110156100f1577fb94ec34dfe32a8a7170992a093976368d1e63decf8f0bc0b38a8eb89cc9f95cf82828151811061019857610198610424565b60200260200101516040516101ad91906104b2565b60405180910390a1806101bf81610453565b91505061015c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561023d5761023d6101c7565b604052919050565b600067ffffffffffffffff82111561025f5761025f6101c7565b5060051b60200190565b6000602080838503121561027c57600080fd5b823567ffffffffffffffff81111561029357600080fd5b8301601f810185136102a457600080fd5b80356102b76102b282610245565b6101f6565b81815260059190911b820183019083810190878311156102d657600080fd5b928401925b828410156102f4578335825292840192908401906102db565b979650505050505050565b6000602080838503121561031257600080fd5b823567ffffffffffffffff8082111561032a57600080fd5b8185019150601f868184011261033f57600080fd5b823561034d6102b282610245565b81815260059190911b8401850190858101908983111561036c57600080fd5b8686015b83811015610416578035868111156103885760008081fd5b8701603f81018c1361039a5760008081fd5b888101356040888211156103b0576103b06101c7565b6103df8b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08a850116016101f6565b8281528e828486010111156103f45760008081fd5b828285018d83013760009281018c019290925250845250918701918701610370565b509998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036104ab577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b600060208083528351808285015260005b818110156104df578581018301518582016040015282016104c3565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509291505056fea164736f6c6343000813000a", + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"Log1\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"Log2\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"name\":\"Log3\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"Log4\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"v\",\"type\":\"uint256[]\"}],\"name\":\"EmitLog1\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"v\",\"type\":\"uint256[]\"}],\"name\":\"EmitLog2\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string[]\",\"name\":\"v\",\"type\":\"string[]\"}],\"name\":\"EmitLog3\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"v\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"w\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"c\",\"type\":\"uint256\"}],\"name\":\"EmitLog4\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b506105c5806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063696933c914610051578063b4b12d9814610066578063bc253bc014610079578063d9c21f461461008c575b600080fd5b61006461005f3660046102d7565b61009f565b005b61006461007436600461036d565b610113565b6100646100873660046102d7565b610163565b61006461009a366004610399565b6101c7565b60005b815181101561010f577f46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a88282815181106100de576100de6104be565b60200260200101516040516100f591815260200190565b60405180910390a180610107816104ed565b9150506100a2565b5050565b60005b8181101561015d57604051839085907fba21d5b63d64546cb4ab29e370a8972bf26f78cb0c395391b4f451699fdfdc5d90600090a380610155816104ed565b915050610116565b50505050565b60005b815181101561010f57818181518110610181576101816104be565b60200260200101517f624fb00c2ce79f34cb543884c3af64816dce0f4cec3d32661959e49d488a7a9360405160405180910390a2806101bf816104ed565b915050610166565b60005b815181101561010f577fb94ec34dfe32a8a7170992a093976368d1e63decf8f0bc0b38a8eb89cc9f95cf828281518110610206576102066104be565b602002602001015160405161021b919061054c565b60405180910390a18061022d816104ed565b9150506101ca565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156102ab576102ab610235565b604052919050565b600067ffffffffffffffff8211156102cd576102cd610235565b5060051b60200190565b600060208083850312156102ea57600080fd5b823567ffffffffffffffff81111561030157600080fd5b8301601f8101851361031257600080fd5b8035610325610320826102b3565b610264565b81815260059190911b8201830190838101908783111561034457600080fd5b928401925b8284101561036257833582529284019290840190610349565b979650505050505050565b60008060006060848603121561038257600080fd5b505081359360208301359350604090920135919050565b600060208083850312156103ac57600080fd5b823567ffffffffffffffff808211156103c457600080fd5b8185019150601f86818401126103d957600080fd5b82356103e7610320826102b3565b81815260059190911b8401850190858101908983111561040657600080fd5b8686015b838110156104b0578035868111156104225760008081fd5b8701603f81018c136104345760008081fd5b8881013560408882111561044a5761044a610235565b6104798b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08a85011601610264565b8281528e8284860101111561048e5760008081fd5b828285018d83013760009281018c01929092525084525091870191870161040a565b509998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610545577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b600060208083528351808285015260005b818110156105795785810183015185820160400152820161055d565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f830116850101925050509291505056fea164736f6c6343000813000a", } var LogEmitterABI = LogEmitterMetaData.ABI @@ -207,6 +207,18 @@ func (_LogEmitter *LogEmitterTransactorSession) EmitLog3(v []string) (*types.Tra return _LogEmitter.Contract.EmitLog3(&_LogEmitter.TransactOpts, v) } +func (_LogEmitter *LogEmitterTransactor) EmitLog4(opts *bind.TransactOpts, v *big.Int, w *big.Int, c *big.Int) (*types.Transaction, error) { + return _LogEmitter.contract.Transact(opts, "EmitLog4", v, w, c) +} + +func (_LogEmitter *LogEmitterSession) EmitLog4(v *big.Int, w *big.Int, c *big.Int) (*types.Transaction, error) { + return _LogEmitter.Contract.EmitLog4(&_LogEmitter.TransactOpts, v, w, c) +} + +func (_LogEmitter *LogEmitterTransactorSession) EmitLog4(v *big.Int, w *big.Int, c *big.Int) (*types.Transaction, error) { + return _LogEmitter.Contract.EmitLog4(&_LogEmitter.TransactOpts, v, w, c) +} + type LogEmitterLog1Iterator struct { Event *LogEmitterLog1 @@ -568,6 +580,142 @@ func (_LogEmitter *LogEmitterFilterer) ParseLog3(log types.Log) (*LogEmitterLog3 return event, nil } +type LogEmitterLog4Iterator struct { + Event *LogEmitterLog4 + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *LogEmitterLog4Iterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(LogEmitterLog4) + 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(LogEmitterLog4) + 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 *LogEmitterLog4Iterator) Error() error { + return it.fail +} + +func (it *LogEmitterLog4Iterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type LogEmitterLog4 struct { + Arg0 *big.Int + Arg1 *big.Int + Raw types.Log +} + +func (_LogEmitter *LogEmitterFilterer) FilterLog4(opts *bind.FilterOpts, arg0 []*big.Int, arg1 []*big.Int) (*LogEmitterLog4Iterator, error) { + + var arg0Rule []interface{} + for _, arg0Item := range arg0 { + arg0Rule = append(arg0Rule, arg0Item) + } + var arg1Rule []interface{} + for _, arg1Item := range arg1 { + arg1Rule = append(arg1Rule, arg1Item) + } + + logs, sub, err := _LogEmitter.contract.FilterLogs(opts, "Log4", arg0Rule, arg1Rule) + if err != nil { + return nil, err + } + return &LogEmitterLog4Iterator{contract: _LogEmitter.contract, event: "Log4", logs: logs, sub: sub}, nil +} + +func (_LogEmitter *LogEmitterFilterer) WatchLog4(opts *bind.WatchOpts, sink chan<- *LogEmitterLog4, arg0 []*big.Int, arg1 []*big.Int) (event.Subscription, error) { + + var arg0Rule []interface{} + for _, arg0Item := range arg0 { + arg0Rule = append(arg0Rule, arg0Item) + } + var arg1Rule []interface{} + for _, arg1Item := range arg1 { + arg1Rule = append(arg1Rule, arg1Item) + } + + logs, sub, err := _LogEmitter.contract.WatchLogs(opts, "Log4", arg0Rule, arg1Rule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(LogEmitterLog4) + if err := _LogEmitter.contract.UnpackLog(event, "Log4", 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 (_LogEmitter *LogEmitterFilterer) ParseLog4(log types.Log) (*LogEmitterLog4, error) { + event := new(LogEmitterLog4) + if err := _LogEmitter.contract.UnpackLog(event, "Log4", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + func (_LogEmitter *LogEmitter) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { case _LogEmitter.abi.Events["Log1"].ID: @@ -576,6 +724,8 @@ func (_LogEmitter *LogEmitter) ParseLog(log types.Log) (generated.AbigenLog, err return _LogEmitter.ParseLog2(log) case _LogEmitter.abi.Events["Log3"].ID: return _LogEmitter.ParseLog3(log) + case _LogEmitter.abi.Events["Log4"].ID: + return _LogEmitter.ParseLog4(log) default: return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) @@ -594,6 +744,10 @@ func (LogEmitterLog3) Topic() common.Hash { return common.HexToHash("0xb94ec34dfe32a8a7170992a093976368d1e63decf8f0bc0b38a8eb89cc9f95cf") } +func (LogEmitterLog4) Topic() common.Hash { + return common.HexToHash("0xba21d5b63d64546cb4ab29e370a8972bf26f78cb0c395391b4f451699fdfdc5d") +} + func (_LogEmitter *LogEmitter) Address() common.Address { return _LogEmitter.address } @@ -605,6 +759,8 @@ type LogEmitterInterface interface { EmitLog3(opts *bind.TransactOpts, v []string) (*types.Transaction, error) + EmitLog4(opts *bind.TransactOpts, v *big.Int, w *big.Int, c *big.Int) (*types.Transaction, error) + FilterLog1(opts *bind.FilterOpts) (*LogEmitterLog1Iterator, error) WatchLog1(opts *bind.WatchOpts, sink chan<- *LogEmitterLog1) (event.Subscription, error) @@ -623,6 +779,12 @@ type LogEmitterInterface interface { ParseLog3(log types.Log) (*LogEmitterLog3, error) + FilterLog4(opts *bind.FilterOpts, arg0 []*big.Int, arg1 []*big.Int) (*LogEmitterLog4Iterator, error) + + WatchLog4(opts *bind.WatchOpts, sink chan<- *LogEmitterLog4, arg0 []*big.Int, arg1 []*big.Int) (event.Subscription, error) + + ParseLog4(log types.Log) (*LogEmitterLog4, error) + ParseLog(log types.Log) (generated.AbigenLog, error) Address() common.Address diff --git a/core/gethwrappers/generated/operator_factory/operator_factory.go b/core/gethwrappers/generated/operator_factory/operator_factory.go index c9a6c57ce21..c14ef439368 100644 --- a/core/gethwrappers/generated/operator_factory/operator_factory.go +++ b/core/gethwrappers/generated/operator_factory/operator_factory.go @@ -32,7 +32,7 @@ var ( var OperatorFactoryMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"linkAddress\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"AuthorizedForwarderCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"operator\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"OperatorCreated\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"query\",\"type\":\"address\"}],\"name\":\"created\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"deployNewForwarderAndTransferOwnership\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewOperator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"deployNewOperatorAndForwarder\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"linkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a060405234801561001057600080fd5b50604051615caf380380615caf83398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051615c016100ae6000396000818161014f015281816101e6015281816102e3015281816103da015281816104be01526105a50152615c016000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c806357970e93116200006257806357970e931462000149578063d42efd831462000171578063d689d09514620001be578063f4adb6e114620001d557600080fd5b8063181f5a77146200008c57806332f01eae14620000e15780633babafdb1462000119575b600080fd5b620000c96040518060400160405280601581526020017f4f70657261746f72466163746f727920312e302e30000000000000000000000081525081565b604051620000d8919062000717565b60405180910390f35b620000eb620001df565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201620000d8565b62000123620003c6565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001620000d8565b620001237f000000000000000000000000000000000000000000000000000000000000000081565b620001ad620001823660046200075d565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b6040519015158152602001620000d8565b62000123620001cf3660046200077b565b620004b9565b62000123620005a0565b60008060007f000000000000000000000000000000000000000000000000000000000000000033604051620002149062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000255573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4604080516000808252602082019092527f000000000000000000000000000000000000000000000000000000000000000090309084906040516200031590620006a3565b62000324949392919062000805565b604051809103906000f08015801562000341573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033923092917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a490939092509050565b6040805160008082526020820190925281907f000000000000000000000000000000000000000000000000000000000000000090339083906040516200040c90620006a3565b6200041b949392919062000805565b604051809103906000f08015801562000438573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4919050565b6000807f000000000000000000000000000000000000000000000000000000000000000033868686604051620004ef90620006a3565b620004ff95949392919062000852565b604051809103906000f0801580156200051c573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4949350505050565b6000807f000000000000000000000000000000000000000000000000000000000000000033604051620005d39062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000614573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4919050565b613c8880620008d483390190565b611699806200455c83390190565b6000815180845260005b81811015620006d957602081850181015186830182015201620006bb565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006200072c6020830184620006b1565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146200075857600080fd5b919050565b6000602082840312156200077057600080fd5b6200072c8262000733565b6000806000604084860312156200079157600080fd5b6200079c8462000733565b9250602084013567ffffffffffffffff80821115620007ba57600080fd5b818601915086601f830112620007cf57600080fd5b813581811115620007df57600080fd5b876020828501011115620007f257600080fd5b6020830194508093505050509250925092565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015280851660408401525060806060830152620008486080830184620006b1565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501168301019050969550505050505056fe60a060405260016006553480156200001657600080fd5b5060405162003c8838038062003c888339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613a4362000245600039600081816101ec0152818161075e015281816109f301528181610c4f015281816117d201528181611a3c01528181611adc01528181611e7701528181612310015281816125c30152612b4b0152613a436000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004612fbe565b610550565b005b3480156101c957600080fd5b506101bb6101d8366004613064565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d91906130dd565b34801561029857600080fd5b506102a161096c565b60405161022d919061312e565b3480156102ba57600080fd5b506101bb6102c93660046131bd565b6109db565b3480156102da57600080fd5b506101bb6102e936600461324a565b610ae3565b3480156102fa57600080fd5b506101bb6103093660046132a1565b610c37565b34801561031a57600080fd5b5061032e610329366004613344565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb61039236600461339e565b611045565b3480156103a357600080fd5b5061032e6103b236600461340a565b6110c9565b6101bb6103c536600461339e565b611445565b3480156103d657600080fd5b506101bb6103e536600461348e565b6115d8565b3480156103f657600080fd5b506101bb61185c565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e6104453660046134cb565b61195d565b34801561045657600080fd5b506101bb61046536600461354a565b611ac4565b34801561047657600080fd5b506101bb61048536600461348e565b611c52565b34801561049657600080fd5b506101bb6104a5366004612fbe565b611f02565b3480156104b657600080fd5b506101bb6104c5366004613635565b612210565b3480156104d657600080fd5b506101bb6104e5366004613659565b612224565b3480156104f657600080fd5b5061032e610505366004613635565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b36600461339e565b612389565b6105586124e5565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e6613685565b90506020020160208101906105fb9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905582828281811061066057610660613685565b90506020020160208101906106759190613635565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c9613685565b90506020020160208101906106de9190613635565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b5050505080610747906136e3565b90506105c6565b505050565b61075b61253a565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b892919061371b565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a6125bd565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf99989796959493929190613774565b60405180910390a250505050505050505050565b610aeb61253a565b60005b82811015610c3157600060056000868685818110610b0e57610b0e613685565b9050602002016020810190610b239190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b88613685565b9050602002016020810190610b9d9190613635565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a906136e3565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a6125bd565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b99989796959493929190613774565b60405180910390a25050505050505050505050565b6000610d4a61289b565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c89898989896001612914565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906137ff565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612b0c565b905090565b61104d6124e5565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612389565b60006110d361289b565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e6002612914565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b49392919061381b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916137ff565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b8481101561156f5760008484838181106114d9576114d9613685565b90506020020135905080836114ee9190613857565b925086868381811061150257611502613685565b90506020020160208101906115179190613635565b73ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f1935050505015801561155c573d6000803e3d6000fd5b505080611568906136e3565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146116fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42821115611765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118549190613870565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146118dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b600061196761253a565b8380611971612b0c565b10156119ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611a77908990899089908990600401613892565b6020604051808303816000875af1158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba9190613870565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611b63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611b748183612bd5565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611ba791906137ff565b600060405180830381855af49150503d8060008114611be2576040519150601f19603f3d011682016040523d82523d6000602084013e611be7565b606091505b5050905080611854576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611da0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611ed5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef99190613870565b50505050505050565b611f0a6124e5565b611f70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80611fd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b8181101561206c57600080600060018481548110611ffd57611ffd613685565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055612065816136e3565b9050611fdd565b5060005b828110156121c25760008085858481811061208d5761208d613685565b90506020020160208101906120a29190613635565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff1615612133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b600160008086868581811061214a5761214a613685565b905060200201602081019061215f9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556121bb816136e3565b9050612070565b506121cf60018484612ede565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122039392919061391e565b60405180910390a1505050565b61221861253a565b61222181612d51565b50565b61222c61253a565b8080612236612b0c565b10156122c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237d9190613870565b61074e5761074e613958565b6123916124e5565b6123f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e7727848484843360405161242e959493929190613987565b60405180910390a160005b838110156109655784848281811061245357612453613685565b90506020020160208101906124689190613635565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b81526004016124a29291906139d7565b600060405180830381600087803b1580156124bc57600080fd5b505af11580156124d0573d6000803e3d6000fd5b50505050806124de906136e3565b9050612439565b3360009081526020819052604081205460ff168061104057503361251e60025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff1633146125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612676576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001615612781576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61278d61012c426139f3565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff1916815260200161282c87612e47565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c91909117905560065461288b908a906139f3565b6006555050965096945050505050565b3360009081526020819052604090205460ff166125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612a38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612a4182612e47565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612ae4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612af29190613857565b600655505050600093845250506004602052506040812055565b60006001600654612b1d9190613857565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612ba7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bcb9190613a06565b6110409190613857565b612be160026020613a1f565b612bec9060046139f3565b81511015612c56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612ce757507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612dd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612eda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215612f56579160200282015b82811115612f565781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612efe565b50612eda9291505b80821115612eda5760008155600101612f5e565b60008083601f840112612f8457600080fd5b50813567ffffffffffffffff811115612f9c57600080fd5b6020830191508360208260051b8501011115612fb757600080fd5b9250929050565b60008060208385031215612fd157600080fd5b823567ffffffffffffffff811115612fe857600080fd5b612ff485828601612f72565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461222157600080fd5b60008083601f84011261303457600080fd5b50813567ffffffffffffffff81111561304c57600080fd5b602083019150836020828501011115612fb757600080fd5b60008060006040848603121561307957600080fd5b833561308481613000565b9250602084013567ffffffffffffffff8111156130a057600080fd5b6130ac86828701613022565b9497909650939450505050565b60005b838110156130d45781810151838201526020016130bc565b50506000910152565b60208152600082518060208401526130fc8160408501602087016130b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561317c57835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161314a565b50909695505050505050565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146131b857600080fd5b919050565b60008060008060008060008060e0898b0312156131d957600080fd5b88356131e481613000565b9750602089013596506040890135955061320060608a01613188565b94506080890135935060a0890135925060c089013567ffffffffffffffff81111561322a57600080fd5b6132368b828c01613022565b999c989b5096995094979396929594505050565b60008060006040848603121561325f57600080fd5b833567ffffffffffffffff81111561327657600080fd5b61328286828701612f72565b909450925050602084013561329681613000565b809150509250925092565b60008060008060008060008060006101008a8c0312156132c057600080fd5b89356132cb81613000565b985060208a0135975060408a0135965060608a01356132e981613000565b95506132f760808b01613188565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff81111561332157600080fd5b61332d8c828d01613022565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561335d57600080fd5b8635955060208701359450604087013561337681613000565b935061338460608801613188565b92506080870135915060a087013590509295509295509295565b600080600080604085870312156133b457600080fd5b843567ffffffffffffffff808211156133cc57600080fd5b6133d888838901612f72565b909650945060208701359150808211156133f157600080fd5b506133fe87828801612f72565b95989497509550505050565b600080600080600080600060c0888a03121561342557600080fd5b8735965060208801359550604088013561343e81613000565b945061344c60608901613188565b93506080880135925060a088013567ffffffffffffffff81111561346f57600080fd5b61347b8a828b01613022565b989b979a50959850939692959293505050565b600080600080608085870312156134a457600080fd5b84359350602085013592506134bb60408601613188565b9396929550929360600135925050565b600080600080606085870312156134e157600080fd5b84356134ec81613000565b935060208501359250604085013567ffffffffffffffff81111561350f57600080fd5b6133fe87828801613022565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561355f57600080fd5b833561356a81613000565b925060208401359150604084013567ffffffffffffffff8082111561358e57600080fd5b818601915086601f8301126135a257600080fd5b8135818111156135b4576135b461351b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156135fa576135fa61351b565b8160405282815289602084870101111561361357600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561364757600080fd5b813561365281613000565b9392505050565b6000806040838503121561366c57600080fd5b823561367781613000565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613714576137146136b4565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e08401526137ef818401858761372b565b9c9b505050505050505050505050565b600082516138118184602087016130b9565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b8181038181111561386a5761386a6136b4565b92915050565b60006020828403121561388257600080fd5b8151801515811461365257600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611aba60608301848661372b565b8183526000602080850194508260005b858110156139135781356138eb81613000565b73ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016138d8565b509495945050505050565b6040815260006139326040830185876138c8565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60608152600061399b6060830187896138c8565b82810360208401526139ae8186886138c8565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b6020815260006139eb6020830184866138c8565b949350505050565b8082018082111561386a5761386a6136b4565b600060208284031215613a1857600080fd5b5051919050565b808202811582820484141761386a5761386a6136b456fea164736f6c6343000813000a60a06040523480156200001157600080fd5b50604051620016993803806200169983398101604081905262000034916200029d565b82826001600160a01b038216620000925760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c557620000c58162000199565b50506001600160a01b0384166200012b5760405162461bcd60e51b815260206004820152602360248201527f4c696e6b20746f6b656e2063616e6e6f742062652061207a65726f206164647260448201526265737360e81b606482015260840162000089565b6001600160a01b038085166080528216156200018f57816001600160a01b0316836001600160a01b03167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e836040516200018691906200038e565b60405180910390a35b50505050620003c3565b336001600160a01b03821603620001f35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000089565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200025c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002945781810151838201526020016200027a565b50506000910152565b60008060008060808587031215620002b457600080fd5b620002bf8562000244565b9350620002cf6020860162000244565b9250620002df6040860162000244565b60608601519092506001600160401b0380821115620002fd57600080fd5b818701915087601f8301126200031257600080fd5b81518181111562000327576200032762000261565b604051601f8201601f19908116603f0116810190838211818310171562000352576200035262000261565b816040528281528a60208487010111156200036c57600080fd5b6200037f83602083016020880162000277565b979a9699509497505050505050565b6020815260008251806020840152620003af81604085016020870162000277565b601f01601f19169190910160400192915050565b6080516112ac620003ed6000396000818161016d0152818161037501526105d301526112ac6000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806379ba509711610081578063ee56997b1161005b578063ee56997b14610200578063f2fde38b14610213578063fa00763a1461022657600080fd5b806379ba5097146101c75780638da5cb5b146101cf578063b64fa9e6146101ed57600080fd5b80634d3e2323116100b25780634d3e23231461015557806357970e93146101685780636fadcf72146101b457600080fd5b8063033f49f7146100d9578063181f5a77146100ee5780632408afaa14610140575b600080fd5b6100ec6100e7366004610e72565b61026f565b005b61012a6040518060400160405280601981526020017f417574686f72697a6564466f7277617264657220312e312e300000000000000081525081565b6040516101379190610ef5565b60405180910390f35b610148610287565b6040516101379190610f61565b6100ec610163366004610e72565b6102f6565b61018f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610137565b6100ec6101c2366004610e72565b61036b565b6100ec61042d565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b6100ec6101fb366004611007565b61052a565b6100ec61020e366004611073565b6106cb565b6100ec6102213660046110b5565b6109dc565b61025f6102343660046110b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205460ff1690565b6040519015158152602001610137565b6102776109f0565b610282838383610a73565b505050565b606060038054806020026020016040519081016040528092919081815260200182805480156102ec57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116102c1575b5050505050905090565b6102ff836109dc565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e848460405161035e9291906110d7565b60405180910390a3505050565b610373610c00565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e0000000060448201526064015b60405180910390fd5b60015473ffffffffffffffffffffffffffffffffffffffff1633146104ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610424565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610532610c00565b82811461059b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f417272617973206d7573742068617665207468652073616d65206c656e6774686044820152606401610424565b60005b838110156106c45760008585838181106105ba576105ba611124565b90506020020160208101906105cf91906110b5565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610686576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e000000006044820152606401610424565b6106b38185858581811061069c5761069c611124565b90506020028101906106ae9190611153565b610a73565b506106bd816111b8565b905061059e565b5050505050565b6106d3610c79565b610739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e646572730000006044820152606401610424565b806107a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e64657200000000006044820152606401610424565b60035460005b8181101561083657600060026000600384815481106107c7576107c7611124565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561082f816111b8565b90506107a6565b5060005b8281101561098e576002600085858481811061085857610858611124565b905060200201602081019061086d91906110b5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156108fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e64657273006044820152606401610424565b60016002600086868581811061091657610916611124565b905060200201602081019061092b91906110b5565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610987816111b8565b905061083a565b5061099b60038484610dac565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516109cf93929190611217565b60405180910390a1505050565b6109e46109f0565b6109ed81610cb7565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610424565b565b73ffffffffffffffffffffffffffffffffffffffff83163b610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e74726163740000000000006044820152606401610424565b6000808473ffffffffffffffffffffffffffffffffffffffff168484604051610b1b92919061128f565b6000604051808303816000865af19150503d8060008114610b58576040519150601f19603f3d011682016040523d82523d6000602084013e610b5d565b606091505b5091509150816106c4578051600003610bf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f466f727761726465642063616c6c20726576657274656420776974686f75742060448201527f726561736f6e00000000000000000000000000000000000000000000000000006064820152608401610424565b805181602001fd5b3360009081526002602052604090205460ff16610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e64657200000000000000000000006044820152606401610424565b600033610c9b60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b3373ffffffffffffffffffffffffffffffffffffffff821603610d36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610424565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610e24579160200282015b82811115610e245781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610dcc565b50610e30929150610e34565b5090565b5b80821115610e305760008155600101610e35565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e6d57600080fd5b919050565b600080600060408486031215610e8757600080fd5b610e9084610e49565b9250602084013567ffffffffffffffff80821115610ead57600080fd5b818601915086601f830112610ec157600080fd5b813581811115610ed057600080fd5b876020828501011115610ee257600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b81811015610f2257858101830151858201604001528201610f06565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6020808252825182820181905260009190848201906040850190845b81811015610faf57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610f7d565b50909695505050505050565b60008083601f840112610fcd57600080fd5b50813567ffffffffffffffff811115610fe557600080fd5b6020830191508360208260051b850101111561100057600080fd5b9250929050565b6000806000806040858703121561101d57600080fd5b843567ffffffffffffffff8082111561103557600080fd5b61104188838901610fbb565b9096509450602087013591508082111561105a57600080fd5b5061106787828801610fbb565b95989497509550505050565b6000806020838503121561108657600080fd5b823567ffffffffffffffff81111561109d57600080fd5b6110a985828601610fbb565b90969095509350505050565b6000602082840312156110c757600080fd5b6110d082610e49565b9392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261118857600080fd5b83018035915067ffffffffffffffff8211156111a357600080fd5b60200191503681900382131561100057600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611210577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6040808252810183905260008460608301825b868110156112655773ffffffffffffffffffffffffffffffffffffffff61125084610e49565b1682526020928301929091019060010161122a565b50809250505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b818382376000910190815291905056fea164736f6c6343000813000aa164736f6c6343000813000a", + Bin: "0x60a060405234801561001057600080fd5b50604051615d59380380615d5983398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b608051615cab6100ae6000396000818161014f015281816101e6015281816102e3015281816103da015281816104be01526105a50152615cab6000f3fe60806040523480156200001157600080fd5b5060043610620000875760003560e01c806357970e93116200006257806357970e931462000149578063d42efd831462000171578063d689d09514620001be578063f4adb6e114620001d557600080fd5b8063181f5a77146200008c57806332f01eae14620000e15780633babafdb1462000119575b600080fd5b620000c96040518060400160405280601581526020017f4f70657261746f72466163746f727920312e302e30000000000000000000000081525081565b604051620000d8919062000717565b60405180910390f35b620000eb620001df565b6040805173ffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201620000d8565b62000123620003c6565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001620000d8565b620001237f000000000000000000000000000000000000000000000000000000000000000081565b620001ad620001823660046200075d565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b6040519015158152602001620000d8565b62000123620001cf3660046200077b565b620004b9565b62000123620005a0565b60008060007f000000000000000000000000000000000000000000000000000000000000000033604051620002149062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000255573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4604080516000808252602082019092527f000000000000000000000000000000000000000000000000000000000000000090309084906040516200031590620006a3565b62000324949392919062000805565b604051809103906000f08015801562000341573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033923092917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a490939092509050565b6040805160008082526020820190925281907f000000000000000000000000000000000000000000000000000000000000000090339083906040516200040c90620006a3565b6200041b949392919062000805565b604051809103906000f08015801562000438573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4919050565b6000807f000000000000000000000000000000000000000000000000000000000000000033868686604051620004ef90620006a3565b620004ff95949392919062000852565b604051809103906000f0801580156200051c573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917f1c9576ab03e40fdf23673f82d904a0f029c8a6629272a4edad4be877e83af64b91a4949350505050565b6000807f000000000000000000000000000000000000000000000000000000000000000033604051620005d39062000695565b73ffffffffffffffffffffffffffffffffffffffff928316815291166020820152604001604051809103906000f08015801562000614573d6000803e3d6000fd5b5073ffffffffffffffffffffffffffffffffffffffff811660008181526020819052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555192935033928392917fd3bb727b2e716a1f142bc9c63c66fe0ae4c5fbc89234f8aa77d0c864a7b63bab91a4919050565b613d3280620008d483390190565b611699806200460683390190565b6000815180845260005b81811015620006d957602081850181015186830182015201620006bb565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006200072c6020830184620006b1565b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146200075857600080fd5b919050565b6000602082840312156200077057600080fd5b6200072c8262000733565b6000806000604084860312156200079157600080fd5b6200079c8462000733565b9250602084013567ffffffffffffffff80821115620007ba57600080fd5b818601915086601f830112620007cf57600080fd5b813581811115620007df57600080fd5b876020828501011115620007f257600080fd5b6020830194508093505050509250925092565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015280851660408401525060806060830152620008486080830184620006b1565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff8088168352808716602084015280861660408401525060806060830152826080830152828460a0840137600060a0848401015260a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501168301019050969550505050505056fe60a060405260016006553480156200001657600080fd5b5060405162003d3238038062003d328339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613aed62000245600039600081816101ec0152818161075e015281816109f301528181610c4f0152818161187c01528181611ae601528181611b8601528181611f21015281816123ba0152818161266d0152612bf50152613aed6000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004613068565b610550565b005b3480156101c957600080fd5b506101bb6101d836600461310e565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d9190613187565b34801561029857600080fd5b506102a161096c565b60405161022d91906131d8565b3480156102ba57600080fd5b506101bb6102c9366004613267565b6109db565b3480156102da57600080fd5b506101bb6102e93660046132f4565b610ae3565b3480156102fa57600080fd5b506101bb61030936600461334b565b610c37565b34801561031a57600080fd5b5061032e6103293660046133ee565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb610392366004613448565b611045565b3480156103a357600080fd5b5061032e6103b23660046134b4565b6110c9565b6101bb6103c5366004613448565b611445565b3480156103d657600080fd5b506101bb6103e5366004613538565b611682565b3480156103f657600080fd5b506101bb611906565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e610445366004613575565b611a07565b34801561045657600080fd5b506101bb6104653660046135f4565b611b6e565b34801561047657600080fd5b506101bb610485366004613538565b611cfc565b34801561049657600080fd5b506101bb6104a5366004613068565b611fac565b3480156104b657600080fd5b506101bb6104c53660046136df565b6122ba565b3480156104d657600080fd5b506101bb6104e5366004613703565b6122ce565b3480156104f657600080fd5b5061032e6105053660046136df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b366004613448565b612433565b61055861258f565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e661372f565b90506020020160208101906105fb91906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558282828181106106605761066061372f565b905060200201602081019061067591906136df565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c961372f565b90506020020160208101906106de91906136df565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b50505050806107479061378d565b90506105c6565b505050565b61075b6125e4565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b89291906137c5565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a612667565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf9998979695949392919061381e565b60405180910390a250505050505050505050565b610aeb6125e4565b60005b82811015610c3157600060056000868685818110610b0e57610b0e61372f565b9050602002016020810190610b2391906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b8861372f565b9050602002016020810190610b9d91906136df565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a9061378d565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a612667565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b9998979695949392919061381e565b60405180910390a25050505050505050505050565b6000610d4a612945565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c898989898960016129be565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906138a9565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612bb6565b905090565b61104d61258f565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612433565b60006110d3612945565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e60026129be565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b4939291906138c5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916138a9565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b848110156116195760008484838181106114d9576114d961372f565b90506020020135905080836114ee9190613901565b925060008787848181106115045761150461372f565b905060200201602081019061151991906136df565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611570576040519150601f19603f3d011682016040523d82523d6000602084013e611575565b606091505b5050905080611606576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105ba565b5050806116129061378d565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146117a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b4282111561180f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156118da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fe919061391a565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6000611a116125e4565b8380611a1b612bb6565b1015611aa9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611b2190899089908990899060040161393c565b6020604051808303816000875af1158015611b40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b64919061391a565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611c1e8183612c7f565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611c5191906138a9565b600060405180830381855af49150503d8060008114611c8c576040519150601f19603f3d011682016040523d82523d6000602084013e611c91565b606091505b50509050806118fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611e4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611eb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa3919061391a565b50505050505050565b611fb461258f565b61201a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80612081576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b81811015612116576000806000600184815481106120a7576120a761372f565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561210f8161378d565b9050612087565b5060005b8281101561226c576000808585848181106121375761213761372f565b905060200201602081019061214c91906136df565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156121dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b60016000808686858181106121f4576121f461372f565b905060200201602081019061220991906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556122658161378d565b905061211a565b5061227960018484612f88565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122ad939291906139c8565b60405180910390a1505050565b6122c26125e4565b6122cb81612dfb565b50565b6122d66125e4565b80806122e0612bb6565b101561236e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612403573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612427919061391a565b61074e5761074e613a02565b61243b61258f565b6124a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e772784848484336040516124d8959493929190613a31565b60405180910390a160005b83811015610965578484828181106124fd576124fd61372f565b905060200201602081019061251291906136df565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b815260040161254c929190613a81565b600060405180830381600087803b15801561256657600080fd5b505af115801561257a573d6000803e3d6000fd5b50505050806125889061378d565b90506124e3565b3360009081526020819052604081205460ff16806110405750336125c860025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff163314612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612720576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00161561282b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61283761012c42613a9d565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff191681526020016128d687612ef1565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c919091179055600654612935908a90613a9d565b6006555050965096945050505050565b3360009081526020819052604090205460ff16612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612aeb82612ef1565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612b8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612b9c9190613901565b600655505050600093845250506004602052506040812055565b60006001600654612bc79190613901565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c759190613ab0565b6110409190613901565b612c8b60026020613ac9565b612c96906004613a9d565b81511015612d00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612d9157507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612df7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612e7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612f84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215613000579160200282015b828111156130005781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612fa8565b50612f849291505b80821115612f845760008155600101613008565b60008083601f84011261302e57600080fd5b50813567ffffffffffffffff81111561304657600080fd5b6020830191508360208260051b850101111561306157600080fd5b9250929050565b6000806020838503121561307b57600080fd5b823567ffffffffffffffff81111561309257600080fd5b61309e8582860161301c565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146122cb57600080fd5b60008083601f8401126130de57600080fd5b50813567ffffffffffffffff8111156130f657600080fd5b60208301915083602082850101111561306157600080fd5b60008060006040848603121561312357600080fd5b833561312e816130aa565b9250602084013567ffffffffffffffff81111561314a57600080fd5b613156868287016130cc565b9497909650939450505050565b60005b8381101561317e578181015183820152602001613166565b50506000910152565b60208152600082518060208401526131a6816040850160208701613163565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561322657835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016131f4565b50909695505050505050565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461326257600080fd5b919050565b60008060008060008060008060e0898b03121561328357600080fd5b883561328e816130aa565b975060208901359650604089013595506132aa60608a01613232565b94506080890135935060a0890135925060c089013567ffffffffffffffff8111156132d457600080fd5b6132e08b828c016130cc565b999c989b5096995094979396929594505050565b60008060006040848603121561330957600080fd5b833567ffffffffffffffff81111561332057600080fd5b61332c8682870161301c565b9094509250506020840135613340816130aa565b809150509250925092565b60008060008060008060008060006101008a8c03121561336a57600080fd5b8935613375816130aa565b985060208a0135975060408a0135965060608a0135613393816130aa565b95506133a160808b01613232565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff8111156133cb57600080fd5b6133d78c828d016130cc565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561340757600080fd5b86359550602087013594506040870135613420816130aa565b935061342e60608801613232565b92506080870135915060a087013590509295509295509295565b6000806000806040858703121561345e57600080fd5b843567ffffffffffffffff8082111561347657600080fd5b6134828883890161301c565b9096509450602087013591508082111561349b57600080fd5b506134a88782880161301c565b95989497509550505050565b600080600080600080600060c0888a0312156134cf57600080fd5b873596506020880135955060408801356134e8816130aa565b94506134f660608901613232565b93506080880135925060a088013567ffffffffffffffff81111561351957600080fd5b6135258a828b016130cc565b989b979a50959850939692959293505050565b6000806000806080858703121561354e57600080fd5b843593506020850135925061356560408601613232565b9396929550929360600135925050565b6000806000806060858703121561358b57600080fd5b8435613596816130aa565b935060208501359250604085013567ffffffffffffffff8111156135b957600080fd5b6134a8878288016130cc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561360957600080fd5b8335613614816130aa565b925060208401359150604084013567ffffffffffffffff8082111561363857600080fd5b818601915086601f83011261364c57600080fd5b81358181111561365e5761365e6135c5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156136a4576136a46135c5565b816040528281528960208487010111156136bd57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156136f157600080fd5b81356136fc816130aa565b9392505050565b6000806040838503121561371657600080fd5b8235613721816130aa565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036137be576137be61375e565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e084015261389981840185876137d5565b9c9b505050505050505050505050565b600082516138bb818460208701613163565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b818103818111156139145761391461375e565b92915050565b60006020828403121561392c57600080fd5b815180151581146136fc57600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611b646060830184866137d5565b8183526000602080850194508260005b858110156139bd578135613995816130aa565b73ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613982565b509495945050505050565b6040815260006139dc604083018587613972565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b606081526000613a45606083018789613972565b8281036020840152613a58818688613972565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b602081526000613a95602083018486613972565b949350505050565b808201808211156139145761391461375e565b600060208284031215613ac257600080fd5b5051919050565b80820281158282048414176139145761391461375e56fea164736f6c6343000813000a60a06040523480156200001157600080fd5b50604051620016993803806200169983398101604081905262000034916200029d565b82826001600160a01b038216620000925760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c557620000c58162000199565b50506001600160a01b0384166200012b5760405162461bcd60e51b815260206004820152602360248201527f4c696e6b20746f6b656e2063616e6e6f742062652061207a65726f206164647260448201526265737360e81b606482015260840162000089565b6001600160a01b038085166080528216156200018f57816001600160a01b0316836001600160a01b03167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e836040516200018691906200038e565b60405180910390a35b50505050620003c3565b336001600160a01b03821603620001f35760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000089565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b03811681146200025c57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620002945781810151838201526020016200027a565b50506000910152565b60008060008060808587031215620002b457600080fd5b620002bf8562000244565b9350620002cf6020860162000244565b9250620002df6040860162000244565b60608601519092506001600160401b0380821115620002fd57600080fd5b818701915087601f8301126200031257600080fd5b81518181111562000327576200032762000261565b604051601f8201601f19908116603f0116810190838211818310171562000352576200035262000261565b816040528281528a60208487010111156200036c57600080fd5b6200037f83602083016020880162000277565b979a9699509497505050505050565b6020815260008251806020840152620003af81604085016020870162000277565b601f01601f19169190910160400192915050565b6080516112ac620003ed6000396000818161016d0152818161037501526105d301526112ac6000f3fe608060405234801561001057600080fd5b50600436106100d45760003560e01c806379ba509711610081578063ee56997b1161005b578063ee56997b14610200578063f2fde38b14610213578063fa00763a1461022657600080fd5b806379ba5097146101c75780638da5cb5b146101cf578063b64fa9e6146101ed57600080fd5b80634d3e2323116100b25780634d3e23231461015557806357970e93146101685780636fadcf72146101b457600080fd5b8063033f49f7146100d9578063181f5a77146100ee5780632408afaa14610140575b600080fd5b6100ec6100e7366004610e72565b61026f565b005b61012a6040518060400160405280601981526020017f417574686f72697a6564466f7277617264657220312e312e300000000000000081525081565b6040516101379190610ef5565b60405180910390f35b610148610287565b6040516101379190610f61565b6100ec610163366004610e72565b6102f6565b61018f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610137565b6100ec6101c2366004610e72565b61036b565b6100ec61042d565b60005473ffffffffffffffffffffffffffffffffffffffff1661018f565b6100ec6101fb366004611007565b61052a565b6100ec61020e366004611073565b6106cb565b6100ec6102213660046110b5565b6109dc565b61025f6102343660046110b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205460ff1690565b6040519015158152602001610137565b6102776109f0565b610282838383610a73565b505050565b606060038054806020026020016040519081016040528092919081815260200182805480156102ec57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116102c1575b5050505050905090565b6102ff836109dc565b8273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f4e1e878dc28d5f040db5969163ff1acd75c44c3f655da2dde9c70bbd8e56dc7e848460405161035e9291906110d7565b60405180910390a3505050565b610373610c00565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610277576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e0000000060448201526064015b60405180910390fd5b60015473ffffffffffffffffffffffffffffffffffffffff1633146104ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610424565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610532610c00565b82811461059b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f417272617973206d7573742068617665207468652073616d65206c656e6774686044820152606401610424565b60005b838110156106c45760008585838181106105ba576105ba611124565b90506020020160208101906105cf91906110b5565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610686576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f43616e6e6f7420666f727761726420746f204c696e6b20746f6b656e000000006044820152606401610424565b6106b38185858581811061069c5761069c611124565b90506020028101906106ae9190611153565b610a73565b506106bd816111b8565b905061059e565b5050505050565b6106d3610c79565b610739576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e646572730000006044820152606401610424565b806107a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e64657200000000006044820152606401610424565b60035460005b8181101561083657600060026000600384815481106107c7576107c7611124565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561082f816111b8565b90506107a6565b5060005b8281101561098e576002600085858481811061085857610858611124565b905060200201602081019061086d91906110b5565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156108fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e64657273006044820152606401610424565b60016002600086868581811061091657610916611124565b905060200201602081019061092b91906110b5565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055610987816111b8565b905061083a565b5061099b60038484610dac565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516109cf93929190611217565b60405180910390a1505050565b6109e46109f0565b6109ed81610cb7565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610424565b565b73ffffffffffffffffffffffffffffffffffffffff83163b610af1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e74726163740000000000006044820152606401610424565b6000808473ffffffffffffffffffffffffffffffffffffffff168484604051610b1b92919061128f565b6000604051808303816000865af19150503d8060008114610b58576040519150601f19603f3d011682016040523d82523d6000602084013e610b5d565b606091505b5091509150816106c4578051600003610bf8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f466f727761726465642063616c6c20726576657274656420776974686f75742060448201527f726561736f6e00000000000000000000000000000000000000000000000000006064820152608401610424565b805181602001fd5b3360009081526002602052604090205460ff16610a71576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e64657200000000000000000000006044820152606401610424565b600033610c9b60005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b3373ffffffffffffffffffffffffffffffffffffffff821603610d36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610424565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b828054828255906000526020600020908101928215610e24579160200282015b82811115610e245781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190610dcc565b50610e30929150610e34565b5090565b5b80821115610e305760008155600101610e35565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e6d57600080fd5b919050565b600080600060408486031215610e8757600080fd5b610e9084610e49565b9250602084013567ffffffffffffffff80821115610ead57600080fd5b818601915086601f830112610ec157600080fd5b813581811115610ed057600080fd5b876020828501011115610ee257600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b81811015610f2257858101830151858201604001528201610f06565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b6020808252825182820181905260009190848201906040850190845b81811015610faf57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101610f7d565b50909695505050505050565b60008083601f840112610fcd57600080fd5b50813567ffffffffffffffff811115610fe557600080fd5b6020830191508360208260051b850101111561100057600080fd5b9250929050565b6000806000806040858703121561101d57600080fd5b843567ffffffffffffffff8082111561103557600080fd5b61104188838901610fbb565b9096509450602087013591508082111561105a57600080fd5b5061106787828801610fbb565b95989497509550505050565b6000806020838503121561108657600080fd5b823567ffffffffffffffff81111561109d57600080fd5b6110a985828601610fbb565b90969095509350505050565b6000602082840312156110c757600080fd5b6110d082610e49565b9392505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261118857600080fd5b83018035915067ffffffffffffffff8211156111a357600080fd5b60200191503681900382131561100057600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611210577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5060010190565b6040808252810183905260008460608301825b868110156112655773ffffffffffffffffffffffffffffffffffffffff61125084610e49565b1682526020928301929091019060010161122a565b50809250505073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b818382376000910190815291905056fea164736f6c6343000813000aa164736f6c6343000813000a", } var OperatorFactoryABI = OperatorFactoryMetaData.ABI diff --git a/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go b/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go index 4b7f6347639..db0ca418b2c 100644 --- a/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go +++ b/core/gethwrappers/generated/operator_wrapper/operator_wrapper.go @@ -32,7 +32,7 @@ var ( var OperatorMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"AuthorizedSendersChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CancelOracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"callbackAddr\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"cancelExpiration\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"OracleResponse\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"acceptedContract\",\"type\":\"address\"}],\"name\":\"OwnableContractAccepted\",\"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\":\"targets\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"changedBy\",\"type\":\"address\"}],\"name\":\"TargetsUpdatedAuthorizedSenders\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"EXPIRYTIME\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"acceptAuthorizedReceivers\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"ownable\",\"type\":\"address[]\"}],\"name\":\"acceptOwnableContracts\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunc\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"cancelOracleRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunc\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"}],\"name\":\"cancelOracleRequestByRequester\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable[]\",\"name\":\"receivers\",\"type\":\"address[]\"},{\"internalType\":\"uint256[]\",\"name\":\"amounts\",\"type\":\"uint256[]\"}],\"name\":\"distributeFunds\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"data\",\"type\":\"bytes32\"}],\"name\":\"fulfillOracleRequest\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"expiration\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"fulfillOracleRequest2\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAuthorizedSenders\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainlinkToken\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"isAuthorizedSender\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"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\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"operatorRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"specId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callbackAddress\",\"type\":\"address\"},{\"internalType\":\"bytes4\",\"name\":\"callbackFunctionId\",\"type\":\"bytes4\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"dataVersion\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"oracleRequest\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerForward\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"ownerTransferAndCall\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSenders\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"targets\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"senders\",\"type\":\"address[]\"}],\"name\":\"setAuthorizedSendersOn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"ownable\",\"type\":\"address[]\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnableContracts\",\"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\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawable\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60a060405260016006553480156200001657600080fd5b5060405162003c8838038062003c888339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613a4362000245600039600081816101ec0152818161075e015281816109f301528181610c4f015281816117d201528181611a3c01528181611adc01528181611e7701528181612310015281816125c30152612b4b0152613a436000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004612fbe565b610550565b005b3480156101c957600080fd5b506101bb6101d8366004613064565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d91906130dd565b34801561029857600080fd5b506102a161096c565b60405161022d919061312e565b3480156102ba57600080fd5b506101bb6102c93660046131bd565b6109db565b3480156102da57600080fd5b506101bb6102e936600461324a565b610ae3565b3480156102fa57600080fd5b506101bb6103093660046132a1565b610c37565b34801561031a57600080fd5b5061032e610329366004613344565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb61039236600461339e565b611045565b3480156103a357600080fd5b5061032e6103b236600461340a565b6110c9565b6101bb6103c536600461339e565b611445565b3480156103d657600080fd5b506101bb6103e536600461348e565b6115d8565b3480156103f657600080fd5b506101bb61185c565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e6104453660046134cb565b61195d565b34801561045657600080fd5b506101bb61046536600461354a565b611ac4565b34801561047657600080fd5b506101bb61048536600461348e565b611c52565b34801561049657600080fd5b506101bb6104a5366004612fbe565b611f02565b3480156104b657600080fd5b506101bb6104c5366004613635565b612210565b3480156104d657600080fd5b506101bb6104e5366004613659565b612224565b3480156104f657600080fd5b5061032e610505366004613635565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b36600461339e565b612389565b6105586124e5565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e6613685565b90506020020160208101906105fb9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905582828281811061066057610660613685565b90506020020160208101906106759190613635565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c9613685565b90506020020160208101906106de9190613635565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b5050505080610747906136e3565b90506105c6565b505050565b61075b61253a565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b892919061371b565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a6125bd565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf99989796959493929190613774565b60405180910390a250505050505050505050565b610aeb61253a565b60005b82811015610c3157600060056000868685818110610b0e57610b0e613685565b9050602002016020810190610b239190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b88613685565b9050602002016020810190610b9d9190613635565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a906136e3565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a6125bd565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b99989796959493929190613774565b60405180910390a25050505050505050505050565b6000610d4a61289b565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c89898989896001612914565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906137ff565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612b0c565b905090565b61104d6124e5565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612389565b60006110d361289b565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e6002612914565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b49392919061381b565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916137ff565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b8481101561156f5760008484838181106114d9576114d9613685565b90506020020135905080836114ee9190613857565b925086868381811061150257611502613685565b90506020020160208101906115179190613635565b73ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f1935050505015801561155c573d6000803e3d6000fd5b505080611568906136e3565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146116fb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42821115611765576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611830573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118549190613870565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff1633146118dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b600061196761253a565b8380611971612b0c565b10156119ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611a77908990899089908990600401613892565b6020604051808303816000875af1158015611a96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aba9190613870565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611b63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611b748183612bd5565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611ba791906137ff565b600060405180830381855af49150503d8060008114611be2576040519150601f19603f3d011682016040523d82523d6000602084013e611be7565b606091505b5050905080611854576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611da0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611ed5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef99190613870565b50505050505050565b611f0a6124e5565b611f70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80611fd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b8181101561206c57600080600060018481548110611ffd57611ffd613685565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055612065816136e3565b9050611fdd565b5060005b828110156121c25760008085858481811061208d5761208d613685565b90506020020160208101906120a29190613635565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff1615612133576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b600160008086868581811061214a5761214a613685565b905060200201602081019061215f9190613635565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556121bb816136e3565b9050612070565b506121cf60018484612ede565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122039392919061391e565b60405180910390a1505050565b61221861253a565b61222181612d51565b50565b61222c61253a565b8080612236612b0c565b10156122c4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237d9190613870565b61074e5761074e613958565b6123916124e5565b6123f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e7727848484843360405161242e959493929190613987565b60405180910390a160005b838110156109655784848281811061245357612453613685565b90506020020160208101906124689190613635565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b81526004016124a29291906139d7565b600060405180830381600087803b1580156124bc57600080fd5b505af11580156124d0573d6000803e3d6000fd5b50505050806124de906136e3565b9050612439565b3360009081526020819052604081205460ff168061104057503361251e60025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff1633146125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612676576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001615612781576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61278d61012c426139f3565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff1916815260200161282c87612e47565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c91909117905560065461288b908a906139f3565b6006555050965096945050505050565b3360009081526020819052604090205460ff166125bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612a38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612a4182612e47565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612ae4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612af29190613857565b600655505050600093845250506004602052506040812055565b60006001600654612b1d9190613857565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612ba7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bcb9190613a06565b6110409190613857565b612be160026020613a1f565b612bec9060046139f3565b81511015612c56576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612ce757507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612dd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612eda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215612f56579160200282015b82811115612f565781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612efe565b50612eda9291505b80821115612eda5760008155600101612f5e565b60008083601f840112612f8457600080fd5b50813567ffffffffffffffff811115612f9c57600080fd5b6020830191508360208260051b8501011115612fb757600080fd5b9250929050565b60008060208385031215612fd157600080fd5b823567ffffffffffffffff811115612fe857600080fd5b612ff485828601612f72565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461222157600080fd5b60008083601f84011261303457600080fd5b50813567ffffffffffffffff81111561304c57600080fd5b602083019150836020828501011115612fb757600080fd5b60008060006040848603121561307957600080fd5b833561308481613000565b9250602084013567ffffffffffffffff8111156130a057600080fd5b6130ac86828701613022565b9497909650939450505050565b60005b838110156130d45781810151838201526020016130bc565b50506000910152565b60208152600082518060208401526130fc8160408501602087016130b9565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561317c57835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161314a565b50909695505050505050565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146131b857600080fd5b919050565b60008060008060008060008060e0898b0312156131d957600080fd5b88356131e481613000565b9750602089013596506040890135955061320060608a01613188565b94506080890135935060a0890135925060c089013567ffffffffffffffff81111561322a57600080fd5b6132368b828c01613022565b999c989b5096995094979396929594505050565b60008060006040848603121561325f57600080fd5b833567ffffffffffffffff81111561327657600080fd5b61328286828701612f72565b909450925050602084013561329681613000565b809150509250925092565b60008060008060008060008060006101008a8c0312156132c057600080fd5b89356132cb81613000565b985060208a0135975060408a0135965060608a01356132e981613000565b95506132f760808b01613188565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff81111561332157600080fd5b61332d8c828d01613022565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561335d57600080fd5b8635955060208701359450604087013561337681613000565b935061338460608801613188565b92506080870135915060a087013590509295509295509295565b600080600080604085870312156133b457600080fd5b843567ffffffffffffffff808211156133cc57600080fd5b6133d888838901612f72565b909650945060208701359150808211156133f157600080fd5b506133fe87828801612f72565b95989497509550505050565b600080600080600080600060c0888a03121561342557600080fd5b8735965060208801359550604088013561343e81613000565b945061344c60608901613188565b93506080880135925060a088013567ffffffffffffffff81111561346f57600080fd5b61347b8a828b01613022565b989b979a50959850939692959293505050565b600080600080608085870312156134a457600080fd5b84359350602085013592506134bb60408601613188565b9396929550929360600135925050565b600080600080606085870312156134e157600080fd5b84356134ec81613000565b935060208501359250604085013567ffffffffffffffff81111561350f57600080fd5b6133fe87828801613022565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561355f57600080fd5b833561356a81613000565b925060208401359150604084013567ffffffffffffffff8082111561358e57600080fd5b818601915086601f8301126135a257600080fd5b8135818111156135b4576135b461351b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156135fa576135fa61351b565b8160405282815289602084870101111561361357600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60006020828403121561364757600080fd5b813561365281613000565b9392505050565b6000806040838503121561366c57600080fd5b823561367781613000565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203613714576137146136b4565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e08401526137ef818401858761372b565b9c9b505050505050505050505050565b600082516138118184602087016130b9565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b8181038181111561386a5761386a6136b4565b92915050565b60006020828403121561388257600080fd5b8151801515811461365257600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611aba60608301848661372b565b8183526000602080850194508260005b858110156139135781356138eb81613000565b73ffffffffffffffffffffffffffffffffffffffff16875295820195908201906001016138d8565b509495945050505050565b6040815260006139326040830185876138c8565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b60608152600061399b6060830187896138c8565b82810360208401526139ae8186886138c8565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b6020815260006139eb6020830184866138c8565b949350505050565b8082018082111561386a5761386a6136b4565b600060208284031215613a1857600080fd5b5051919050565b808202811582820484141761386a5761386a6136b456fea164736f6c6343000813000a", + Bin: "0x60a060405260016006553480156200001657600080fd5b5060405162003d3238038062003d328339810160408190526200003991620001ab565b808060006001600160a01b038216620000995760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b0384811691909117909155811615620000cc57620000cc81620000e2565b505050506001600160a01b0316608052620001e3565b336001600160a01b038216036200013c5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000090565b600380546001600160a01b0319166001600160a01b03838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b80516001600160a01b0381168114620001a657600080fd5b919050565b60008060408385031215620001bf57600080fd5b620001ca836200018e565b9150620001da602084016200018e565b90509250929050565b608051613aed62000245600039600081816101ec0152818161075e015281816109f301528181610c4f0152818161187c01528181611ae601528181611b8601528181611f21015281816123ba0152818161266d0152612bf50152613aed6000f3fe6080604052600436106101965760003560e01c80636ae0bc76116100e1578063a4c0ed361161008a578063f2fde38b11610064578063f2fde38b146104aa578063f3fef3a3146104ca578063fa00763a146104ea578063fc4a03ed1461053057600080fd5b8063a4c0ed361461044a578063eb007d991461046a578063ee56997b1461048a57600080fd5b806379ba5097116100bb57806379ba5097146103ea5780638da5cb5b146103ff578063902fc3701461042a57600080fd5b80636ae0bc76146103975780636bd59ec0146103b75780636ee4d553146103ca57600080fd5b80633ec5bc1411610143578063501883011161011d578063501883011461033e57806352043783146103615780635ffa62881461037757600080fd5b80633ec5bc14146102ce57806340429946146102ee5780634ab0d1901461030e57600080fd5b8063181f5a7711610174578063181f5a77146102365780632408afaa1461028c5780633c6d41b9146102ae57600080fd5b806301994b991461019b578063033f49f7146101bd578063165d35e1146101dd575b600080fd5b3480156101a757600080fd5b506101bb6101b6366004613068565b610550565b005b3480156101c957600080fd5b506101bb6101d836600461310e565b610753565b3480156101e957600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561024257600080fd5b5061027f6040518060400160405280600e81526020017f4f70657261746f7220312e302e3000000000000000000000000000000000000081525081565b60405161022d9190613187565b34801561029857600080fd5b506102a161096c565b60405161022d91906131d8565b3480156102ba57600080fd5b506101bb6102c9366004613267565b6109db565b3480156102da57600080fd5b506101bb6102e93660046132f4565b610ae3565b3480156102fa57600080fd5b506101bb61030936600461334b565b610c37565b34801561031a57600080fd5b5061032e6103293660046133ee565b610d40565b604051901515815260200161022d565b34801561034a57600080fd5b50610353611036565b60405190815260200161022d565b34801561036d57600080fd5b5061035361012c81565b34801561038357600080fd5b506101bb610392366004613448565b611045565b3480156103a357600080fd5b5061032e6103b23660046134b4565b6110c9565b6101bb6103c5366004613448565b611445565b3480156103d657600080fd5b506101bb6103e5366004613538565b611682565b3480156103f657600080fd5b506101bb611906565b34801561040b57600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff1661020c565b34801561043657600080fd5b5061032e610445366004613575565b611a07565b34801561045657600080fd5b506101bb6104653660046135f4565b611b6e565b34801561047657600080fd5b506101bb610485366004613538565b611cfc565b34801561049657600080fd5b506101bb6104a5366004613068565b611fac565b3480156104b657600080fd5b506101bb6104c53660046136df565b6122ba565b3480156104d657600080fd5b506101bb6104e5366004613703565b6122ce565b3480156104f657600080fd5b5061032e6105053660046136df565b73ffffffffffffffffffffffffffffffffffffffff1660009081526020819052604090205460ff1690565b34801561053c57600080fd5b506101bb61054b366004613448565b612433565b61055861258f565b6105c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064015b60405180910390fd5b60005b8181101561074e576001600560008585858181106105e6576105e661372f565b90506020020160208101906105fb91906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790558282828181106106605761066061372f565b905060200201602081019061067591906136df565b73ffffffffffffffffffffffffffffffffffffffff167f615a0c1cb00a60d4acd77ec67acf2f17f223ef0932d591052fabc33643fe7e8260405160405180910390a28282828181106106c9576106c961372f565b90506020020160208101906106de91906136df565b73ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b50505050806107479061378d565b90506105c6565b505050565b61075b6125e4565b827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610811576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff84163b61088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d75737420666f727761726420746f206120636f6e747261637400000000000060448201526064016105ba565b60008473ffffffffffffffffffffffffffffffffffffffff1684846040516108b89291906137c5565b6000604051808303816000865af19150503d80600081146108f5576040519150601f19603f3d011682016040523d82523d6000602084013e6108fa565b606091505b5050905080610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f466f727761726465642063616c6c206661696c6564000000000000000000000060448201526064016105ba565b5050505050565b606060018054806020026020016040519081016040528092919081815260200182805480156109d157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a6575b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610a7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610a8b8a8a8c8a8a8a612667565b91509150877fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658b848c8e8c878c8c8c604051610acf9998979695949392919061381e565b60405180910390a250505050505050505050565b610aeb6125e4565b60005b82811015610c3157600060056000868685818110610b0e57610b0e61372f565b9050602002016020810190610b2391906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055838382818110610b8857610b8861372f565b9050602002016020810190610b9d91906136df565b6040517ff2fde38b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152919091169063f2fde38b90602401600060405180830381600087803b158015610c0857600080fd5b505af1158015610c1c573d6000803e3d6000fd5b5050505080610c2a9061378d565b9050610aee565b50505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610cd6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b600080610ce78b8b8a8a8a8a612667565b91509150887fd8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c658c848d8f8c878c8c8c604051610d2b9998979695949392919061381e565b60405180910390a25050505050505050505050565b6000610d4a612945565b600087815260046020526040812054889160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003610deb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8616600090815260056020526040902054869060ff1615610e7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b610e8c898989898960016129be565b60405189907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015610f24576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008773ffffffffffffffffffffffffffffffffffffffff16878b87604051602401610f5a929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051610fe391906138a9565b6000604051808303816000865af19150503d8060008114611020576040519150601f19603f3d011682016040523d82523d6000602084013e611025565b606091505b50909b9a5050505050505050505050565b6000611040612bb6565b905090565b61104d61258f565b6110b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b6110bd8484610550565b610c3184848484612433565b60006110d3612945565b600088815260046020526040812054899160089190911b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169003611174576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d757374206861766520612076616c696420726571756573744964000000000060448201526064016105ba565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020526040902054879060ff1615611206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616e6e6f742063616c6c206f776e656420636f6e747261637400000000000060448201526064016105ba565b8985856020811015611274576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f526573706f6e7365206d757374206265203e203332206279746573000000000060448201526064016105ba565b81358381146112df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f466972737420776f7264206d757374206265207265717565737449640000000060448201526064016105ba565b6112ee8e8e8e8e8e60026129be565b6040518e907f9e9bc7616d42c2835d05ae617e508454e63b30b934be8aa932ebc125e0e58a6490600090a262061a805a1015611386576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4d7573742070726f7669646520636f6e73756d657220656e6f7567682067617360448201526064016105ba565b60008c73ffffffffffffffffffffffffffffffffffffffff168c8b8b6040516020016113b4939291906138c5565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526113ec916138a9565b6000604051808303816000865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b509098505050505050505050979650505050505050565b821580159061145357508281145b6114b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c6964206172726179206c656e67746828732900000000000000000060448201526064016105ba565b3460005b848110156116195760008484838181106114d9576114d961372f565b90506020020135905080836114ee9190613901565b925060008787848181106115045761150461372f565b905060200201602081019061151991906136df565b73ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114611570576040519150601f19603f3d011682016040523d82523d6000602084013e611575565b606091505b5050905080611606576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016105ba565b5050806116129061378d565b90506114bd565b508015610965576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d756368204554482073656e7400000000000000000000000000000060448201526064016105ba565b6040805160208082018690527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b16828401527fffffffff00000000000000000000000000000000000000000000000000000000851660548301526058808301859052835180840390910181526078909201909252805191012060009060008681526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00908116908216146117a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b4282111561180f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000858152600460205260408082208290555186917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af11580156118da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118fe919061391a565b505050505050565b60035473ffffffffffffffffffffffffffffffffffffffff163314611987576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016105ba565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560038054909116905560405173ffffffffffffffffffffffffffffffffffffffff909116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6000611a116125e4565b8380611a1b612bb6565b1015611aa9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517f4000aea000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634000aea090611b2190899089908990899060040161393c565b6020604051808303816000875af1158015611b40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b64919061391a565b9695505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614611c0d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4d75737420757365204c494e4b20746f6b656e0000000000000000000000000060448201526064016105ba565b60208101518190611c1e8183612c7f565b84602484015283604484015260003073ffffffffffffffffffffffffffffffffffffffff1684604051611c5191906138a9565b600060405180830381855af49150503d8060008114611c8c576040519150601f19603f3d011682016040523d82523d6000602084013e611c91565b606091505b50509050806118fe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e61626c6520746f206372656174652072657175657374000000000000000060448201526064016105ba565b604080513360601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660208083018290526034808401899052845180850390910181526054840185528051908201206074840188905260948401929092527fffffffff00000000000000000000000000000000000000000000000000000000861660a884015260ac8084018690528451808503909101815260cc9093019093528151919092012060009060008381526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614611e4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b42831115611eb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f52657175657374206973206e6f7420657870697265640000000000000000000060448201526064016105ba565b6000828152600460205260408082208290555183917fa7842b9ec549398102c0d91b1b9919b2f20558aefdadf57528a95c6cd3292e9391a26040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018690527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a9059cbb906044016020604051808303816000875af1158015611f7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa3919061391a565b50505050505050565b611fb461258f565b61201a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b80612081576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f4d7573742068617665206174206c6561737420312073656e646572000000000060448201526064016105ba565b60015460005b81811015612116576000806000600184815481106120a7576120a761372f565b60009182526020808320919091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905561210f8161378d565b9050612087565b5060005b8281101561226c576000808585848181106121375761213761372f565b905060200201602081019061214c91906136df565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156121dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4d757374206e6f742068617665206475706c69636174652073656e646572730060448201526064016105ba565b60016000808686858181106121f4576121f461372f565b905060200201602081019061220991906136df565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169115159190911790556122658161378d565b905061211a565b5061227960018484612f88565b507ff263cfb3e4298332e776194610cf9fdc09ccb3ada8b9aa39764d882e11fbf0a08383336040516122ad939291906139c8565b60405180910390a1505050565b6122c26125e4565b6122cb81612dfb565b50565b6122d66125e4565b80806122e0612bb6565b101561236e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f416d6f756e74207265717565737465642069732067726561746572207468616e60448201527f20776974686472617761626c652062616c616e6365000000000000000000000060648201526084016105ba565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8481166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612403573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612427919061391a565b61074e5761074e613a02565b61243b61258f565b6124a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f43616e6e6f742073657420617574686f72697a65642073656e6465727300000060448201526064016105ba565b7f1bb185903e2cb2f1b303523128b60e314dea81df4f8d9b7351cadd344f6e772784848484336040516124d8959493929190613a31565b60405180910390a160005b83811015610965578484828181106124fd576124fd61372f565b905060200201602081019061251291906136df565b73ffffffffffffffffffffffffffffffffffffffff1663ee56997b84846040518363ffffffff1660e01b815260040161254c929190613a81565b600060405180830381600087803b15801561256657600080fd5b505af115801561257a573d6000803e3d6000fd5b50505050806125889061378d565b90506124e3565b3360009081526020819052604081205460ff16806110405750336125c860025473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614905090565b60025473ffffffffffffffffffffffffffffffffffffffff163314612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016105ba565b565b600080857f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612720576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f43616e6e6f742063616c6c20746f204c494e4b0000000000000000000000000060448201526064016105ba565b6040517fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608b901b16602082015260348101869052605401604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001815291815281516020928301206000818152600490935291205490935060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00161561282b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f4d75737420757365206120756e6971756520494400000000000000000000000060448201526064016105ba565b61283761012c42613a9d565b6040805160208082018c90527fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060608c901b16828401527fffffffff000000000000000000000000000000000000000000000000000000008a1660548301526058808301859052835180840390910181526078909201909252805191012090925060405180604001604052808260ff191681526020016128d687612ef1565b60ff9081169091526000868152600460209081526040909120835193909101519091167f01000000000000000000000000000000000000000000000000000000000000000260089290921c919091179055600654612935908a90613a9d565b6006555050965096945050505050565b3360009081526020819052604090205460ff16612665576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420617574686f72697a65642073656e646572000000000000000000000060448201526064016105ba565b6040805160208082018890527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606088901b16828401527fffffffff00000000000000000000000000000000000000000000000000000000861660548301526058808301869052835180840390910181526078909201909252805191012060009060008881526004602052604090205490915060081b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090811690821614612ae2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f506172616d7320646f206e6f74206d617463682072657175657374204944000060448201526064016105ba565b612aeb82612ef1565b60008881526004602052604090205460ff9182167f01000000000000000000000000000000000000000000000000000000000000009091049091161115612b8e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f446174612076657273696f6e73206d757374206d61746368000000000000000060448201526064016105ba565b85600654612b9c9190613901565b600655505050600093845250506004602052506040812055565b60006001600654612bc79190613901565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c759190613ab0565b6110409190613901565b612c8b60026020613ac9565b612c96906004613a9d565b81511015612d00576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e76616c69642072657175657374206c656e6774680000000000000000000060448201526064016105ba565b7fffffffff0000000000000000000000000000000000000000000000000000000082167f3c6d41b9000000000000000000000000000000000000000000000000000000001480612d9157507fffffffff0000000000000000000000000000000000000000000000000000000082167f4042994600000000000000000000000000000000000000000000000000000000145b612df7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4d757374207573652077686974656c69737465642066756e6374696f6e73000060448201526064016105ba565b5050565b3373ffffffffffffffffffffffffffffffffffffffff821603612e7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016105ba565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae127890600090a350565b600060ff821115612f84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201527f206269747300000000000000000000000000000000000000000000000000000060648201526084016105ba565b5090565b828054828255906000526020600020908101928215613000579160200282015b828111156130005781547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff843516178255602090920191600190910190612fa8565b50612f849291505b80821115612f845760008155600101613008565b60008083601f84011261302e57600080fd5b50813567ffffffffffffffff81111561304657600080fd5b6020830191508360208260051b850101111561306157600080fd5b9250929050565b6000806020838503121561307b57600080fd5b823567ffffffffffffffff81111561309257600080fd5b61309e8582860161301c565b90969095509350505050565b73ffffffffffffffffffffffffffffffffffffffff811681146122cb57600080fd5b60008083601f8401126130de57600080fd5b50813567ffffffffffffffff8111156130f657600080fd5b60208301915083602082850101111561306157600080fd5b60008060006040848603121561312357600080fd5b833561312e816130aa565b9250602084013567ffffffffffffffff81111561314a57600080fd5b613156868287016130cc565b9497909650939450505050565b60005b8381101561317e578181015183820152602001613166565b50506000910152565b60208152600082518060208401526131a6816040850160208701613163565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6020808252825182820181905260009190848201906040850190845b8181101561322657835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016131f4565b50909695505050505050565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461326257600080fd5b919050565b60008060008060008060008060e0898b03121561328357600080fd5b883561328e816130aa565b975060208901359650604089013595506132aa60608a01613232565b94506080890135935060a0890135925060c089013567ffffffffffffffff8111156132d457600080fd5b6132e08b828c016130cc565b999c989b5096995094979396929594505050565b60008060006040848603121561330957600080fd5b833567ffffffffffffffff81111561332057600080fd5b61332c8682870161301c565b9094509250506020840135613340816130aa565b809150509250925092565b60008060008060008060008060006101008a8c03121561336a57600080fd5b8935613375816130aa565b985060208a0135975060408a0135965060608a0135613393816130aa565b95506133a160808b01613232565b945060a08a0135935060c08a0135925060e08a013567ffffffffffffffff8111156133cb57600080fd5b6133d78c828d016130cc565b915080935050809150509295985092959850929598565b60008060008060008060c0878903121561340757600080fd5b86359550602087013594506040870135613420816130aa565b935061342e60608801613232565b92506080870135915060a087013590509295509295509295565b6000806000806040858703121561345e57600080fd5b843567ffffffffffffffff8082111561347657600080fd5b6134828883890161301c565b9096509450602087013591508082111561349b57600080fd5b506134a88782880161301c565b95989497509550505050565b600080600080600080600060c0888a0312156134cf57600080fd5b873596506020880135955060408801356134e8816130aa565b94506134f660608901613232565b93506080880135925060a088013567ffffffffffffffff81111561351957600080fd5b6135258a828b016130cc565b989b979a50959850939692959293505050565b6000806000806080858703121561354e57600080fd5b843593506020850135925061356560408601613232565b9396929550929360600135925050565b6000806000806060858703121561358b57600080fd5b8435613596816130aa565b935060208501359250604085013567ffffffffffffffff8111156135b957600080fd5b6134a8878288016130cc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60008060006060848603121561360957600080fd5b8335613614816130aa565b925060208401359150604084013567ffffffffffffffff8082111561363857600080fd5b818601915086601f83011261364c57600080fd5b81358181111561365e5761365e6135c5565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156136a4576136a46135c5565b816040528281528960208487010111156136bd57600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b6000602082840312156136f157600080fd5b81356136fc816130aa565b9392505050565b6000806040838503121561371657600080fd5b8235613721816130aa565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036137be576137be61375e565b5060010190565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600061010073ffffffffffffffffffffffffffffffffffffffff808d1684528b60208501528a6040850152808a166060850152507fffffffff00000000000000000000000000000000000000000000000000000000881660808401528660a08401528560c08401528060e084015261389981840185876137d5565b9c9b505050505050505050505050565b600082516138bb818460208701613163565b9190910192915050565b7fffffffff0000000000000000000000000000000000000000000000000000000084168152818360048301376000910160040190815292915050565b818103818111156139145761391461375e565b92915050565b60006020828403121561392c57600080fd5b815180151581146136fc57600080fd5b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201526000611b646060830184866137d5565b8183526000602080850194508260005b858110156139bd578135613995816130aa565b73ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613982565b509495945050505050565b6040815260006139dc604083018587613972565b905073ffffffffffffffffffffffffffffffffffffffff83166020830152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b606081526000613a45606083018789613972565b8281036020840152613a58818688613972565b91505073ffffffffffffffffffffffffffffffffffffffff831660408301529695505050505050565b602081526000613a95602083018486613972565b949350505050565b808201808211156139145761391461375e565b600060208284031215613ac257600080fd5b5051919050565b80820281158282048414176139145761391461375e56fea164736f6c6343000813000a", } var OperatorABI = OperatorMetaData.ABI diff --git a/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go b/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go index bb28c8bd6c4..1409bcb1548 100644 --- a/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go +++ b/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper/simple_log_upkeep_counter_wrapper.go @@ -30,6 +30,12 @@ var ( _ = abi.ConvertType ) +type CheckData struct { + CheckBurnAmount *big.Int + PerformBurnAmount *big.Int + EventSig [32]byte +} + type Log struct { Index *big.Int Timestamp *big.Int @@ -42,8 +48,8 @@ type Log struct { } var SimpleLogUpkeepCounterMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lastBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"previousBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"counter\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timeToPerform\",\"type\":\"uint256\"}],\"name\":\"PerformingUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"log\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeToPerform\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b5060006001819055438155600281905560035561088a806100326000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c806361bc221a1161005b57806361bc221a146100d4578063806b984f146100dd578063917d895f146100e6578063c6066f0d146100ef57600080fd5b80632cb158641461008257806340691db41461009e5780634585e33b146100bf575b600080fd5b61008b60025481565b6040519081526020015b60405180910390f35b6100b16100ac366004610384565b6100f8565b60405161009592919061055e565b6100d26100cd366004610312565b61012a565b005b61008b60035481565b61008b60005481565b61008b60015481565b61008b60045481565b6000606060018460405160200161010f91906105db565b604051602081830303815290604052915091505b9250929050565b60025461013657436002555b436000556003546101489060016107f0565b6003556000805460015561015e828401846103f1565b90508060200151426101709190610808565b6004819055600254600054600154600354604080519485526020850193909352918301526060820152608081019190915232907f4874b8dd61a40fe23599b4360a9a824d7081742fca9f555bcee3d389c4f4bd659060a00160405180910390a2505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146101f957600080fd5b919050565b600082601f83011261020f57600080fd5b8135602067ffffffffffffffff82111561022b5761022b61084e565b8160051b61023a8282016106d6565b83815282810190868401838801850189101561025557600080fd5b600093505b8584101561027857803583526001939093019291840191840161025a565b50979650505050505050565b600082601f83011261029557600080fd5b813567ffffffffffffffff8111156102af576102af61084e565b6102e060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016106d6565b8181528460208386010111156102f557600080fd5b816020850160208301376000918101602001919091529392505050565b6000806020838503121561032557600080fd5b823567ffffffffffffffff8082111561033d57600080fd5b818501915085601f83011261035157600080fd5b81358181111561036057600080fd5b86602082850101111561037257600080fd5b60209290920196919550909350505050565b6000806040838503121561039757600080fd5b823567ffffffffffffffff808211156103af57600080fd5b9084019061010082870312156103c457600080fd5b909250602084013590808211156103da57600080fd5b506103e785828601610284565b9150509250929050565b60006020828403121561040357600080fd5b813567ffffffffffffffff8082111561041b57600080fd5b90830190610100828603121561043057600080fd5b6104386106ac565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015261047060a084016101d5565b60a082015260c08301358281111561048757600080fd5b610493878286016101fe565b60c08301525060e0830135828111156104ab57600080fd5b6104b787828601610284565b60e08301525095945050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156104f857600080fd5b8260051b8083602087013760009401602001938452509192915050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b821515815260006020604081840152835180604085015260005b8181101561059457858101830151858201606001528201610578565b818111156105a6576000606083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201606001949350505050565b6020815281356020820152602082013560408201526040820135606082015260608201356080820152608082013560a082015273ffffffffffffffffffffffffffffffffffffffff61062f60a084016101d5565b1660c0820152600061064460c0840184610725565b6101008060e086015261065c610120860183856104c6565b925061066b60e087018761078c565b92507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086850301828701526106a1848483610515565b979650505050505050565b604051610100810167ffffffffffffffff811182821017156106d0576106d061084e565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561071d5761071d61084e565b604052919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261075a57600080fd5b830160208101925035905067ffffffffffffffff81111561077a57600080fd5b8060051b360383131561012357600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126107c157600080fd5b830160208101925035905067ffffffffffffffff8111156107e157600080fd5b80360383131561012357600080fd5b600082198211156108035761080361081f565b500190565b60008282101561081a5761081a61081f565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"initialBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"lastBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"previousBlock\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"counter\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timeToPerform\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isRecovered\",\"type\":\"bool\"}],\"name\":\"PerformingUpkeep\",\"type\":\"event\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"checkBurnAmount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"performBurnAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"eventSig\",\"type\":\"bytes32\"}],\"internalType\":\"structCheckData\",\"name\":\"\",\"type\":\"tuple\"}],\"name\":\"_checkDataConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"txHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"source\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"topics\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"internalType\":\"structLog\",\"name\":\"log\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"checkData\",\"type\":\"bytes\"}],\"name\":\"checkLog\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"counter\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"dummyMap\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isRecovered\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"lastBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"performData\",\"type\":\"bytes\"}],\"name\":\"performUpkeep\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"previousPerformBlock\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"timeToPerform\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b5060006002819055436001556003819055600455610d12806100336000396000f3fe608060405234801561001057600080fd5b50600436106100be5760003560e01c80637145f11b11610076578063917d895f1161005b578063917d895f1461016b578063c6066f0d14610174578063eb950ce71461017d57600080fd5b80637145f11b1461012f578063806b984f1461016257600080fd5b80634585e33b116100a75780634585e33b1461010057806361bc221a14610115578063697794731461011e57600080fd5b80632cb15864146100c357806340691db4146100df575b600080fd5b6100cc60035481565b6040519081526020015b60405180910390f35b6100f26100ed3660046106c6565b61018a565b6040516100d692919061092d565b61011361010e366004610628565b6102c2565b005b6100cc60045481565b61011361012c36600461066a565b50565b61015261013d36600461060f565b60006020819052908152604090205460ff1681565b60405190151581526020016100d6565b6100cc60015481565b6100cc60025481565b6100cc60055481565b6006546101529060ff1681565b6000606081808061019d8688018861083b565b92509250925060005a905060006101b5600143610c61565b40905060008515610224575b855a6101cd9085610c61565b1015610224578080156101ee575060008281526020819052604090205460ff165b604080516020810185905230918101919091529091506060016040516020818303038152906040528051906020012091506101c1565b8361023260c08d018d610a9d565b600281811061024357610243610ca7565b9050602002013514156102875760018b438c8c60405160200161026994939291906109aa565b604051602081830303815290604052975097505050505050506102ba565b60008b438c8c6040516020016102a094939291906109aa565b604051602081830303815290604052975097505050505050505b935093915050565b6003546102ce57436003555b4360019081556004546102e091610c49565b600455600154600255600080806102f984860186610738565b92509250925082602001514261030f9190610c61565b600555600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556060830151821461037157600680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b60008060008380602001905181019061038a9190610867565b92509250925060005a905060006103a2600143610c61565b40905060008415610411575b845a6103ba9085610c61565b1015610411578080156103db575060008281526020819052604090205460ff165b604080516020810185905230918101919091529091506060016040516020818303038152906040528051906020012091506103ae565b600354600154600254600454600554600654604080519687526020870195909552938501929092526060840152608083015260ff16151560a082015232907f29eff4cb37911c3ea85db4630638cc5474fdd0631ec42215aef1d7ec96c8e63d9060c00160405180910390a25050505050505050505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146104ad57600080fd5b919050565b600082601f8301126104c357600080fd5b8135602067ffffffffffffffff8211156104df576104df610cd6565b8160051b6104ee828201610b2f565b83815282810190868401838801850189101561050957600080fd5b600093505b8584101561052c57803583526001939093019291840191840161050e565b50979650505050505050565b60008083601f84011261054a57600080fd5b50813567ffffffffffffffff81111561056257600080fd5b60208301915083602082850101111561057a57600080fd5b9250929050565b600082601f83011261059257600080fd5b813567ffffffffffffffff8111156105ac576105ac610cd6565b6105dd60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601610b2f565b8181528460208386010111156105f257600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561062157600080fd5b5035919050565b6000806020838503121561063b57600080fd5b823567ffffffffffffffff81111561065257600080fd5b61065e85828601610538565b90969095509350505050565b60006060828403121561067c57600080fd5b6040516060810181811067ffffffffffffffff8211171561069f5761069f610cd6565b80604052508235815260208301356020820152604083013560408201528091505092915050565b6000806000604084860312156106db57600080fd5b833567ffffffffffffffff808211156106f357600080fd5b90850190610100828803121561070857600080fd5b9093506020850135908082111561071e57600080fd5b5061072b86828701610538565b9497909650939450505050565b60008060006060848603121561074d57600080fd5b833567ffffffffffffffff8082111561076557600080fd5b90850190610100828803121561077a57600080fd5b610782610b05565b82358152602083013560208201526040830135604082015260608301356060820152608083013560808201526107ba60a08401610489565b60a082015260c0830135828111156107d157600080fd5b6107dd898286016104b2565b60c08301525060e0830135828111156107f557600080fd5b61080189828601610581565b60e083015250945060208601359350604086013591508082111561082457600080fd5b5061083186828701610581565b9150509250925092565b60008060006060848603121561085057600080fd5b505081359360208301359350604090920135919050565b60008060006060848603121561087c57600080fd5b8351925060208401519150604084015190509250925092565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156108c757600080fd5b8260051b8083602087013760009401602001938452509192915050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b821515815260006020604081840152835180604085015260005b8181101561096357858101830151858201606001528201610947565b81811115610975576000606083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201606001949350505050565b606081528435606082015260208501356080820152604085013560a0820152606085013560c0820152608085013560e082015260006109eb60a08701610489565b61010073ffffffffffffffffffffffffffffffffffffffff821681850152610a1660c0890189610b7e565b925081610120860152610a2e61016086018483610895565b92505050610a3f60e0880188610be5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa085840301610140860152610a758382846108e4565b925050508560208401528281036040840152610a928185876108e4565b979650505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610ad257600080fd5b83018035915067ffffffffffffffff821115610aed57600080fd5b6020019150600581901b360382131561057a57600080fd5b604051610100810167ffffffffffffffff81118282101715610b2957610b29610cd6565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610b7657610b76610cd6565b604052919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610bb357600080fd5b830160208101925035905067ffffffffffffffff811115610bd357600080fd5b8060051b360383131561057a57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610c1a57600080fd5b830160208101925035905067ffffffffffffffff811115610c3a57600080fd5b80360383131561057a57600080fd5b60008219821115610c5c57610c5c610c78565b500190565b600082821015610c7357610c73610c78565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var SimpleLogUpkeepCounterABI = SimpleLogUpkeepCounterMetaData.ABI @@ -182,9 +188,9 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactorRaw) Transact(opt return _SimpleLogUpkeepCounter.Contract.contract.Transact(opts, method, params...) } -func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) CheckLog(opts *bind.CallOpts, log Log, arg1 []byte) (bool, []byte, error) { +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) CheckLog(opts *bind.CallOpts, log Log, checkData []byte) (bool, []byte, error) { var out []interface{} - err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "checkLog", log, arg1) + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "checkLog", log, checkData) if err != nil { return *new(bool), *new([]byte), err @@ -197,12 +203,12 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) CheckLog(opts *bind } -func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) CheckLog(log Log, arg1 []byte) (bool, []byte, error) { - return _SimpleLogUpkeepCounter.Contract.CheckLog(&_SimpleLogUpkeepCounter.CallOpts, log, arg1) +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) CheckLog(log Log, checkData []byte) (bool, []byte, error) { + return _SimpleLogUpkeepCounter.Contract.CheckLog(&_SimpleLogUpkeepCounter.CallOpts, log, checkData) } -func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) CheckLog(log Log, arg1 []byte) (bool, []byte, error) { - return _SimpleLogUpkeepCounter.Contract.CheckLog(&_SimpleLogUpkeepCounter.CallOpts, log, arg1) +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) CheckLog(log Log, checkData []byte) (bool, []byte, error) { + return _SimpleLogUpkeepCounter.Contract.CheckLog(&_SimpleLogUpkeepCounter.CallOpts, log, checkData) } func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) Counter(opts *bind.CallOpts) (*big.Int, error) { @@ -227,6 +233,28 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) Counter() (* return _SimpleLogUpkeepCounter.Contract.Counter(&_SimpleLogUpkeepCounter.CallOpts) } +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) DummyMap(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "dummyMap", arg0) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) DummyMap(arg0 [32]byte) (bool, error) { + return _SimpleLogUpkeepCounter.Contract.DummyMap(&_SimpleLogUpkeepCounter.CallOpts, arg0) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) DummyMap(arg0 [32]byte) (bool, error) { + return _SimpleLogUpkeepCounter.Contract.DummyMap(&_SimpleLogUpkeepCounter.CallOpts, arg0) +} + func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) InitialBlock(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "initialBlock") @@ -249,6 +277,28 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) InitialBlock return _SimpleLogUpkeepCounter.Contract.InitialBlock(&_SimpleLogUpkeepCounter.CallOpts) } +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) IsRecovered(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "isRecovered") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) IsRecovered() (bool, error) { + return _SimpleLogUpkeepCounter.Contract.IsRecovered(&_SimpleLogUpkeepCounter.CallOpts) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) IsRecovered() (bool, error) { + return _SimpleLogUpkeepCounter.Contract.IsRecovered(&_SimpleLogUpkeepCounter.CallOpts) +} + func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCaller) LastBlock(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _SimpleLogUpkeepCounter.contract.Call(opts, &out, "lastBlock") @@ -315,6 +365,18 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterCallerSession) TimeToPerfor return _SimpleLogUpkeepCounter.Contract.TimeToPerform(&_SimpleLogUpkeepCounter.CallOpts) } +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactor) CheckDataConfig(opts *bind.TransactOpts, arg0 CheckData) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.contract.Transact(opts, "_checkDataConfig", arg0) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterSession) CheckDataConfig(arg0 CheckData) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.CheckDataConfig(&_SimpleLogUpkeepCounter.TransactOpts, arg0) +} + +func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactorSession) CheckDataConfig(arg0 CheckData) (*types.Transaction, error) { + return _SimpleLogUpkeepCounter.Contract.CheckDataConfig(&_SimpleLogUpkeepCounter.TransactOpts, arg0) +} + func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounterTransactor) PerformUpkeep(opts *bind.TransactOpts, performData []byte) (*types.Transaction, error) { return _SimpleLogUpkeepCounter.contract.Transact(opts, "performUpkeep", performData) } @@ -394,6 +456,7 @@ type SimpleLogUpkeepCounterPerformingUpkeep struct { PreviousBlock *big.Int Counter *big.Int TimeToPerform *big.Int + IsRecovered bool Raw types.Log } @@ -470,7 +533,7 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounter) ParseLog(log types.Log) ( } func (SimpleLogUpkeepCounterPerformingUpkeep) Topic() common.Hash { - return common.HexToHash("0x4874b8dd61a40fe23599b4360a9a824d7081742fca9f555bcee3d389c4f4bd65") + return common.HexToHash("0x29eff4cb37911c3ea85db4630638cc5474fdd0631ec42215aef1d7ec96c8e63d") } func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounter) Address() common.Address { @@ -478,18 +541,24 @@ func (_SimpleLogUpkeepCounter *SimpleLogUpkeepCounter) Address() common.Address } type SimpleLogUpkeepCounterInterface interface { - CheckLog(opts *bind.CallOpts, log Log, arg1 []byte) (bool, []byte, error) + CheckLog(opts *bind.CallOpts, log Log, checkData []byte) (bool, []byte, error) Counter(opts *bind.CallOpts) (*big.Int, error) + DummyMap(opts *bind.CallOpts, arg0 [32]byte) (bool, error) + InitialBlock(opts *bind.CallOpts) (*big.Int, error) + IsRecovered(opts *bind.CallOpts) (bool, error) + LastBlock(opts *bind.CallOpts) (*big.Int, error) PreviousPerformBlock(opts *bind.CallOpts) (*big.Int, error) TimeToPerform(opts *bind.CallOpts) (*big.Int, error) + CheckDataConfig(opts *bind.TransactOpts, arg0 CheckData) (*types.Transaction, error) + PerformUpkeep(opts *bind.TransactOpts, performData []byte) (*types.Transaction, error) FilterPerformingUpkeep(opts *bind.FilterOpts, from []common.Address) (*SimpleLogUpkeepCounterPerformingUpkeepIterator, error) diff --git a/core/gethwrappers/generated/vrf_coordinator_test_v2/vrf_coordinator_test_v2.go b/core/gethwrappers/generated/vrf_coordinator_test_v2/vrf_coordinator_test_v2.go new file mode 100644 index 00000000000..cb4e2cea016 --- /dev/null +++ b/core/gethwrappers/generated/vrf_coordinator_test_v2/vrf_coordinator_test_v2.go @@ -0,0 +1,3115 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package vrf_coordinator_test_v2 + +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 VRFCoordinatorTestV2FeeConfig struct { + FulfillmentFlatFeeLinkPPMTier1 uint32 + FulfillmentFlatFeeLinkPPMTier2 uint32 + FulfillmentFlatFeeLinkPPMTier3 uint32 + FulfillmentFlatFeeLinkPPMTier4 uint32 + FulfillmentFlatFeeLinkPPMTier5 uint32 + ReqsForTier2 *big.Int + ReqsForTier3 *big.Int + ReqsForTier4 *big.Int + ReqsForTier5 *big.Int +} + +type VRFCoordinatorTestV2RequestCommitment struct { + BlockNum uint64 + SubId uint64 + CallbackGasLimit uint32 + NumWords uint32 + Sender common.Address +} + +type VRFProof struct { + Pk [2]*big.Int + Gamma [2]*big.Int + C *big.Int + S *big.Int + Seed *big.Int + UWitness common.Address + CGammaWitness [2]*big.Int + SHashWitness [2]*big.Int + ZInv *big.Int +} + +var VRFCoordinatorTestV2MetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"blockhashStore\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"linkEthFeed\",\"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\":\"uint32\",\"name\":\"have\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"want\",\"type\":\"uint32\"}],\"name\":\"GasLimitTooBig\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IncorrectCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"InvalidConsumer\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"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\":\"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\":\"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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier3\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier4\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier5\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier2\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier3\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier4\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier5\",\"type\":\"uint24\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorTestV2.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"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\":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\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"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\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"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\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCanceled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"SubscriptionConsumerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"SubscriptionCreated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"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\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"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\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"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_ETH_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\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"acceptSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"addConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"cancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createSubscription\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"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\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"internalType\":\"structVRFCoordinatorTestV2.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"name\":\"fulfillRandomWords\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"}],\"name\":\"getCommitment\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"stalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasAfterPaymentCalculation\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentSubId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFallbackWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier3\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier4\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier5\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier2\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier3\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier4\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier5\",\"type\":\"uint24\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"}],\"name\":\"getFeeTier\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"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\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"getSubscription\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"balance\",\"type\":\"uint96\"},{\"internalType\":\"uint64\",\"name\":\"reqCount\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"consumers\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getTotalBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"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\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"name\":\"ownerCancelSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"}],\"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\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"registerProvingKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"}],\"name\":\"removeConsumer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"}],\"name\":\"requestRandomWords\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"requestSubscriptionOwnerTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier3\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier4\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPMTier5\",\"type\":\"uint32\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier2\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier3\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier4\",\"type\":\"uint24\"},{\"internalType\":\"uint24\",\"name\":\"reqsForTier5\",\"type\":\"uint24\"}],\"internalType\":\"structVRFCoordinatorTestV2.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"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\"}]", + Bin: "0x60e06040523480156200001157600080fd5b5060405162005755380380620057558339810160408190526200003491620001b1565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050506001600160601b0319606093841b811660805290831b811660a052911b1660c052620001fb565b6001600160a01b038116331415620001435760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001ac57600080fd5b919050565b600080600060608486031215620001c757600080fd5b620001d28462000194565b9250620001e26020850162000194565b9150620001f26040850162000194565b90509250925092565b60805160601c60a05160601c60c05160601c6154f0620002656000396000818161051901526138180152600081816106030152613c0401526000818161036d015281816114df0152818161233c01528181612d7301528181612eaf01526134d401526154f06000f3fe608060405234801561001057600080fd5b506004361061025b5760003560e01c80636f64f03f11610145578063ad178361116100bd578063d2f9f9a71161008c578063e72f6e3011610071578063e72f6e30146106e0578063e82ad7d4146106f3578063f2fde38b1461071657600080fd5b8063d2f9f9a7146106ba578063d7ae1d30146106cd57600080fd5b8063ad178361146105fe578063af198b9714610625578063c3f909d414610655578063caf70c4a146106a757600080fd5b80638da5cb5b11610114578063a21a23e4116100f9578063a21a23e4146105c0578063a47c7696146105c8578063a4c0ed36146105eb57600080fd5b80638da5cb5b1461059c5780639f87fad7146105ad57600080fd5b80636f64f03f1461055b5780637341c10c1461056e57806379ba509714610581578063823597401461058957600080fd5b8063356dac71116101d85780635fbbc0d2116101a757806366316d8d1161018c57806366316d8d14610501578063689c45171461051457806369bcdb7d1461053b57600080fd5b80635fbbc0d2146103f357806364d51a2a146104f957600080fd5b8063356dac71146103a757806340d6bb82146103af5780634cb48a54146103cd5780635d3b1d30146103e057600080fd5b806308821d581161022f57806315c48b841161021457806315c48b841461030e578063181f5a77146103295780631b6b6d231461036857600080fd5b806308821d58146102cf57806312b58349146102e257600080fd5b80620122911461026057806302bcc5b61461028057806304c357cb1461029557806306bfa637146102a8575b600080fd5b610268610729565b6040516102779392919061503a565b60405180910390f35b61029361028e366004614e86565b6107a5565b005b6102936102a3366004614ea1565b610837565b60055467ffffffffffffffff165b60405167ffffffffffffffff9091168152602001610277565b6102936102dd366004614b97565b6109eb565b6005546801000000000000000090046bffffffffffffffffffffffff165b604051908152602001610277565b61031660c881565b60405161ffff9091168152602001610277565b604080518082018252601681527f565246436f6f7264696e61746f72563220312e302e3000000000000000000000602082015290516102779190614fe5565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610277565b600a54610300565b6103b86101f481565b60405163ffffffff9091168152602001610277565b6102936103db366004614d30565b610bb0565b6103006103ee366004614c0a565b610fa7565b600c546040805163ffffffff80841682526401000000008404811660208301526801000000000000000084048116928201929092526c010000000000000000000000008304821660608201527001000000000000000000000000000000008304909116608082015262ffffff740100000000000000000000000000000000000000008304811660a0830152770100000000000000000000000000000000000000000000008304811660c08301527a0100000000000000000000000000000000000000000000000000008304811660e08301527d01000000000000000000000000000000000000000000000000000000000090920490911661010082015261012001610277565b610316606481565b61029361050f366004614b4f565b61138a565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b610300610549366004614e6d565b60009081526009602052604090205490565b610293610569366004614a94565b6115d9565b61029361057c366004614ea1565b611709565b610293611956565b610293610597366004614e86565b611a1f565b6000546001600160a01b031661038f565b6102936105bb366004614ea1565b611be5565b6102b6611fe4565b6105db6105d6366004614e86565b6121c7565b60405161027794939291906151d8565b6102936105f9366004614ac8565b6122ea565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b610638610633366004614c68565b612541565b6040516bffffffffffffffffffffffff9091168152602001610277565b600b546040805161ffff8316815263ffffffff6201000084048116602083015267010000000000000084048116928201929092526b010000000000000000000000909204166060820152608001610277565b6103006106b5366004614bb3565b6129db565b6103b86106c8366004614e86565b612a0b565b6102936106db366004614ea1565b612c00565b6102936106ee366004614a79565b612d3a565b610706610701366004614e86565b612f77565b6040519015158152602001610277565b610293610724366004614a79565b61319a565b600b546007805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561079357602002820191906000526020600020905b81548152602001906001019080831161077f575b50505050509050925092509250909192565b6107ad6131ab565b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316610806576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546108349082906001600160a01b0316613207565b50565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680610893576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146108e5576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024015b60405180910390fd5b600b546601000000000000900460ff161561092c576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff84166000908152600360205260409020600101546001600160a01b038481169116146109e55767ffffffffffffffff841660008181526003602090815260409182902060010180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be91015b60405180910390a25b50505050565b6109f36131ab565b604080518082018252600091610a229190849060029083908390808284376000920191909152506129db915050565b6000818152600660205260409020549091506001600160a01b031680610a77576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b600082815260066020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600754811015610b67578260078281548110610aca57610aca615485565b90600052602060002001541415610b55576007805460009190610aef9060019061533f565b81548110610aff57610aff615485565b906000526020600020015490508060078381548110610b2057610b20615485565b6000918252602090912001556007805480610b3d57610b3d615456565b60019003818190600052602060002001600090559055505b80610b5f81615383565b915050610aac565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610ba391815260200190565b60405180910390a2505050565b610bb86131ab565b60c861ffff87161115610c0b576040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff871660048201819052602482015260c860448201526064016108dc565b60008213610c48576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018390526024016108dc565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001690971762010000909502949094177fffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff166701000000000000009092027fffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff16919091176b010000000000000000000000909302929092179093558651600c80549489015189890151938a0151978a0151968a015160c08b015160e08c01516101008d01519588167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009099169890981764010000000093881693909302929092177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000958716959095027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16949094176c0100000000000000000000000098861698909802979097177fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000096909416959095027fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff16929092177401000000000000000000000000000000000000000062ffffff92831602177fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff1677010000000000000000000000000000000000000000000000958216959095027fffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffff16949094177a01000000000000000000000000000000000000000000000000000092851692909202919091177cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0100000000000000000000000000000000000000000000000000000000009390911692909202919091178155600a84905590517fc21e3bd2e0b339d2848f0dd956947a88966c242c0c0c582a33137a5c1ceb5cb291610f97918991899189918991899190615099565b60405180910390a1505050505050565b600b546000906601000000000000900460ff1615610ff1576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff85166000908152600360205260409020546001600160a01b031661104a576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260026020908152604080832067ffffffffffffffff808a16855292529091205416806110ba576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff871660048201523360248201526044016108dc565b600b5461ffff90811690861610806110d6575060c861ffff8616115b1561112657600b546040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff8088166004830152909116602482015260c860448201526064016108dc565b600b5463ffffffff620100009091048116908516111561118d57600b546040517ff5d7e01e00000000000000000000000000000000000000000000000000000000815263ffffffff80871660048301526201000090920490911660248201526044016108dc565b6101f463ffffffff841611156111df576040517f47386bec00000000000000000000000000000000000000000000000000000000815263ffffffff841660048201526101f460248201526044016108dc565b60006111ec82600161529b565b6040805160208082018c9052338284015267ffffffffffffffff808c16606084015284166080808401919091528351808403909101815260a08301845280519082012060c083018d905260e080840182905284518085039091018152610100909301909352815191012091925060009182916040805160208101849052439181019190915267ffffffffffffffff8c16606082015263ffffffff808b166080830152891660a08201523360c0820152919350915060e00160408051808303601f19018152828252805160209182012060008681526009835283902055848352820183905261ffff8a169082015263ffffffff808916606083015287166080820152339067ffffffffffffffff8b16908c907f63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a97729060a00160405180910390a45033600090815260026020908152604080832067ffffffffffffffff808d16855292529091208054919093167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161790915591505095945050505050565b600b546601000000000000900460ff16156113d1576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600860205260409020546bffffffffffffffffffffffff8083169116101561142b576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260086020526040812080548392906114589084906bffffffffffffffffffffffff16615356565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080600560088282829054906101000a90046bffffffffffffffffffffffff166114af9190615356565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb83836040518363ffffffff1660e01b815260040161154d9291906001600160a01b039290921682526bffffffffffffffffffffffff16602082015260400190565b602060405180830381600087803b15801561156757600080fd5b505af115801561157b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061159f9190614bcf565b6115d5576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b6115e16131ab565b6040805180820182526000916116109190849060029083908390808284376000920191909152506129db915050565b6000818152600660205260409020549091506001600160a01b031615611665576040517f4a0b8fa7000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b600081815260066020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0388169081179091556007805460018101825594527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610ba3565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611765576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b038216146117b2576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff16156117f9576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff841660009081526003602052604090206002015460641415611850576040517f05a48e0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff8089168552925290912054161561188a576109e5565b6001600160a01b038316600081815260026020818152604080842067ffffffffffffffff8a1680865290835281852080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001908117909155600384528286209094018054948501815585529382902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001685179055905192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e091016109dc565b6001546001600160a01b031633146119b05760405162461bcd60e51b815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016108dc565b60008054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600b546601000000000000900460ff1615611a66576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316611abf576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff81166000908152600360205260409020600101546001600160a01b03163314611b475767ffffffffffffffff8116600090815260036020526040908190206001015490517fd084e9750000000000000000000000000000000000000000000000000000000081526001600160a01b0390911660048201526024016108dc565b67ffffffffffffffff81166000818152600360209081526040918290208054337fffffffffffffffffffffffff0000000000000000000000000000000000000000808316821784556001909301805490931690925583516001600160a01b03909116808252928101919091529092917f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f0910160405180910390a25050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680611c41576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614611c8e576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615611cd5576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038316600090815260026020908152604080832067ffffffffffffffff808916855292529091205416611d56576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526001600160a01b03841660248201526044016108dc565b67ffffffffffffffff8416600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611dc457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611da6575b50505050509050600060018251611ddb919061533f565b905060005b8251811015611f5357856001600160a01b0316838281518110611e0557611e05615485565b60200260200101516001600160a01b03161415611f41576000838381518110611e3057611e30615485565b6020026020010151905080600360008a67ffffffffffffffff1667ffffffffffffffff1681526020019081526020016000206002018381548110611e7657611e76615485565b600091825260208083209190910180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03949094169390931790925567ffffffffffffffff8a168152600390915260409020600201805480611ee357611ee3615456565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611f53565b80611f4b81615383565b915050611de0565b506001600160a01b038516600081815260026020908152604080832067ffffffffffffffff8b168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b91015b60405180910390a2505050505050565b600b546000906601000000000000900460ff161561202e576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805467ffffffffffffffff16906000612048836153bc565b82546101009290920a67ffffffffffffffff81810219909316918316021790915560055416905060008060405190808252806020026020018201604052801561209b578160200160208202803683370190505b506040805180820182526000808252602080830182815267ffffffffffffffff888116808552600484528685209551865493516bffffffffffffffffffffffff9091167fffffffffffffffffffffffff0000000000000000000000000000000000000000948516176c01000000000000000000000000919093160291909117909455845160608101865233815280830184815281870188815295855260038452959093208351815483166001600160a01b039182161782559551600182018054909316961695909517905591518051949550909361217f92600285019201906147d3565b505060405133815267ffffffffffffffff841691507f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a250905090565b67ffffffffffffffff8116600090815260036020526040812054819081906060906001600160a01b0316612227576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff80861660009081526004602090815260408083205460038352928190208054600290910180548351818602810186019094528084526bffffffffffffffffffffffff8616966c01000000000000000000000000909604909516946001600160a01b039092169390929183918301828280156122d457602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116122b6575b5050505050905093509350935093509193509193565b600b546601000000000000900460ff1615612331576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612393576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081146123cd576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006123db82840184614e86565b67ffffffffffffffff81166000908152600360205260409020549091506001600160a01b0316612437576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260046020526040812080546bffffffffffffffffffffffff169186919061246e83856152c7565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555084600560088282829054906101000a90046bffffffffffffffffffffffff166124c591906152c7565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f882878461252c9190615283565b60408051928352602083019190915201611fd4565b600b546000906601000000000000900460ff161561258b576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a9050600080600061259f878761362c565b9250925092506000866060015163ffffffff1667ffffffffffffffff8111156125ca576125ca6154b4565b6040519080825280602002602001820160405280156125f3578160200160208202803683370190505b50905060005b876060015163ffffffff168110156126675760408051602081018590529081018290526060016040516020818303038152906040528051906020012060001c82828151811061264a5761264a615485565b60209081029190910101528061265f81615383565b9150506125f9565b506000838152600960205260408082208290555181907f1fe543e300000000000000000000000000000000000000000000000000000000906126af908790869060240161518a565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055908a015160808b015191925060009161275f9163ffffffff169084613936565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff1690556020808c01805167ffffffffffffffff9081166000908152600490935260408084205492518216845290922080549394506c01000000000000000000000000918290048316936001939192600c926127e392869290041661529b565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550600061283a8a600b600001600b9054906101000a900463ffffffff1663ffffffff1661283485612a0b565b3a613984565b6020808e015167ffffffffffffffff166000908152600490915260409020549091506bffffffffffffffffffffffff808316911610156128a6576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808d015167ffffffffffffffff16600090815260049091526040812080548392906128e29084906bffffffffffffffffffffffff16615356565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b8152600660209081526040808320546001600160a01b03168352600890915281208054859450909261293e918591166152c7565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550877f7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e48883866040516129c1939291909283526bffffffffffffffffffffffff9190911660208301521515604082015260600190565b60405180910390a299505050505050505050505b92915050565b6000816040516020016129ee9190614fd7565b604051602081830303815290604052805190602001209050919050565b6040805161012081018252600c5463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015262ffffff740100000000000000000000000000000000000000008304811660a08301819052770100000000000000000000000000000000000000000000008404821660c08401527a0100000000000000000000000000000000000000000000000000008404821660e08401527d0100000000000000000000000000000000000000000000000000000000009093041661010082015260009167ffffffffffffffff841611612b29575192915050565b8267ffffffffffffffff168160a0015162ffffff16108015612b5e57508060c0015162ffffff168367ffffffffffffffff1611155b15612b6d576020015192915050565b8267ffffffffffffffff168160c0015162ffffff16108015612ba257508060e0015162ffffff168367ffffffffffffffff1611155b15612bb1576040015192915050565b8267ffffffffffffffff168160e0015162ffffff16108015612be7575080610100015162ffffff168367ffffffffffffffff1611155b15612bf6576060015192915050565b6080015192915050565b67ffffffffffffffff821660009081526003602052604090205482906001600160a01b031680612c5c576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336001600160a01b03821614612ca9576040517fd8a3fb520000000000000000000000000000000000000000000000000000000081526001600160a01b03821660048201526024016108dc565b600b546601000000000000900460ff1615612cf0576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612cf984612f77565b15612d30576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109e58484613207565b612d426131ab565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a082319060240160206040518083038186803b158015612dbd57600080fd5b505afa158015612dd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612df59190614bf1565b6005549091506801000000000000000090046bffffffffffffffffffffffff1681811115612e59576040517fa99da30200000000000000000000000000000000000000000000000000000000815260048101829052602481018390526044016108dc565b81811015612f72576000612e6d828461533f565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b158015612ef557600080fd5b505af1158015612f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f2d9190614bcf565b50604080516001600160a01b0386168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a1505b505050565b67ffffffffffffffff81166000908152600360209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561300c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612fee575b505050505081525050905060005b8160400151518110156131905760005b60075481101561317d5760006131466007838154811061304c5761304c615485565b90600052602060002001548560400151858151811061306d5761306d615485565b602002602001015188600260008960400151898151811061309057613090615485565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff808f16835293522054166040805160208082018790526001600160a01b03959095168183015267ffffffffffffffff9384166060820152919092166080808301919091528251808303909101815260a08201835280519084012060c082019490945260e080820185905282518083039091018152610100909101909152805191012091565b506000818152600960205260409020549091501561316a5750600195945050505050565b508061317581615383565b91505061302a565b508061318881615383565b91505061301a565b5060009392505050565b6131a26131ab565b61083481613a8c565b6000546001600160a01b031633146132055760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016108dc565b565b600b546601000000000000900460ff161561324e576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff82166000908152600360209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152929593948601938301828280156132df57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116132c1575b5050509190925250505067ffffffffffffffff80851660009081526004602090815260408083208151808301909252546bffffffffffffffffffffffff81168083526c01000000000000000000000000909104909416918101919091529293505b8360400151518110156133d957600260008560400151838151811061336757613367615485565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812067ffffffffffffffff8a168252909252902080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000169055806133d181615383565b915050613340565b5067ffffffffffffffff8516600090815260036020526040812080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811682556001820180549091169055906134346002830182614850565b505067ffffffffffffffff8516600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600580548291906008906134a49084906801000000000000000090046bffffffffffffffffffffffff16615356565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb85836bffffffffffffffffffffffff166040518363ffffffff1660e01b81526004016135429291906001600160a01b03929092168252602082015260400190565b602060405180830381600087803b15801561355c57600080fd5b505af1158015613570573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135949190614bcf565b6135ca576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516001600160a01b03861681526bffffffffffffffffffffffff8316602082015267ffffffffffffffff8716917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050565b600080600061363e85600001516129db565b6000818152600660205260409020549093506001600160a01b031680613693576040517f77f5b84c000000000000000000000000000000000000000000000000000000008152600481018590526024016108dc565b60808601516040516136b2918691602001918252602082015260400190565b60408051601f1981840301815291815281516020928301206000818152600990935291205490935080613711576040517f3688124a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85516020808801516040808a015160608b015160808c0151925161377d968b96909594910195865267ffffffffffffffff948516602087015292909316604085015263ffffffff90811660608501529190911660808301526001600160a01b031660a082015260c00190565b6040516020818303038152906040528051906020012081146137cb576040517fd529142c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855167ffffffffffffffff1640806138e25786516040517fe9413d3800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b15801561386257600080fd5b505afa158015613876573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061389a9190614bf1565b9050806138e25786516040517f175dadad00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201526024016108dc565b6000886080015182604051602001613904929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c90506139298982613b4e565b9450505050509250925092565b60005a61138881101561394857600080fd5b61138881039050846040820482031161396057600080fd5b50823b61396c57600080fd5b60008083516020850160008789f190505b9392505050565b60008061398f613bb9565b9050600081136139ce576040517f43d4cf66000000000000000000000000000000000000000000000000000000008152600481018290526024016108dc565b6000815a6139dc8989615283565b6139e6919061533f565b6139f886670de0b6b3a7640000615302565b613a029190615302565b613a0c91906152ee565b90506000613a2563ffffffff871664e8d4a51000615302565b9050613a3d816b033b2e3c9fd0803ce800000061533f565b821115613a76576040517fe80fa38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613a808183615283565b98975050505050505050565b6001600160a01b038116331415613ae55760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016108dc565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000613b828360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151613cc0565b60038360200151604051602001613b9a929190615176565b60408051601f1981840301815291905280516020909101209392505050565b600b54604080517ffeaf968c0000000000000000000000000000000000000000000000000000000081529051600092670100000000000000900463ffffffff169182151591849182917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b158015613c5257600080fd5b505afa158015613c66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c8a9190614ecb565b509450909250849150508015613cae5750613ca5824261533f565b8463ffffffff16105b15613cb85750600a545b949350505050565b613cc989613efb565b613d155760405162461bcd60e51b815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e20637572766500000000000060448201526064016108dc565b613d1e88613efb565b613d6a5760405162461bcd60e51b815260206004820152601560248201527f67616d6d61206973206e6f74206f6e206375727665000000000000000000000060448201526064016108dc565b613d7383613efb565b613dbf5760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e20637572766500000060448201526064016108dc565b613dc882613efb565b613e145760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e2063757276650000000060448201526064016108dc565b613e20878a8887613fd4565b613e6c5760405162461bcd60e51b815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e6573730000000000000060448201526064016108dc565b6000613e788a87614125565b90506000613e8b898b878b868989614189565b90506000613e9c838d8d8a866142a9565b9050808a14613eed5760405162461bcd60e51b815260206004820152600d60248201527f696e76616c69642070726f6f660000000000000000000000000000000000000060448201526064016108dc565b505050505050505050505050565b80516000906401000003d01911613f545760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420782d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d01911613fad5760405162461bcd60e51b815260206004820152601260248201527f696e76616c696420792d6f7264696e617465000000000000000000000000000060448201526064016108dc565b60208201516401000003d019908009613fcd8360005b60200201516142e9565b1492915050565b60006001600160a01b03821661402c5760405162461bcd60e51b815260206004820152600b60248201527f626164207769746e65737300000000000000000000000000000000000000000060448201526064016108dc565b60208401516000906001161561404357601c614046565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418587600060200201510986517ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa1580156140fd573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b61412d61486e565b61415a6001848460405160200161414693929190614fb6565b60405160208183030381529060405261430d565b90505b61416681613efb565b6129d55780516040805160208101929092526141829101614146565b905061415d565b61419161486e565b825186516401000003d01990819006910614156141f05760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e6374000060448201526064016108dc565b6141fb87898861435c565b6142475760405162461bcd60e51b815260206004820152601660248201527f4669727374206d756c20636865636b206661696c65640000000000000000000060448201526064016108dc565b61425284868561435c565b61429e5760405162461bcd60e51b815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c656400000000000000000060448201526064016108dc565b613a808684846144a4565b6000600286868685876040516020016142c796959493929190614f44565b60408051601f1981840301815291905280516020909101209695505050505050565b6000806401000003d01980848509840990506401000003d019600782089392505050565b61431561486e565b61431e8261456b565b815261433361432e826000613fc3565b6145a6565b602082018190526002900660011415614357576020810180516401000003d0190390525b919050565b6000826143ab5760405162461bcd60e51b815260206004820152600b60248201527f7a65726f207363616c617200000000000000000000000000000000000000000060448201526064016108dc565b835160208501516000906143c1906002906153e4565b156143cd57601c6143d0565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614450573d6000803e3d6000fd5b50505060206040510351905060008660405160200161446f9190614f32565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b6144ac61486e565b8351602080860151855191860151600093849384936144cd939091906145c6565b919450925090506401000003d01985820960011461452d5760405162461bcd60e51b815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a0000000000000060448201526064016108dc565b60405180604001604052806401000003d0198061454c5761454c615427565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d019811061435757604080516020808201939093528151808203840181529082019091528051910120614573565b60006129d58260026145bf6401000003d0196001615283565b901c6146a6565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a089050600061460683838585614766565b909850905061461788828e8861478a565b909850905061462888828c8761478a565b9098509050600061463b8d878b8561478a565b909850905061464c88828686614766565b909850905061465d88828e8961478a565b9098509050818114614692576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614696565b8196505b5050505050509450945094915050565b6000806146b161488c565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a08201526146e36148aa565b60208160c08460057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa92508261475c5760405162461bcd60e51b815260206004820152601260248201527f6269674d6f64457870206661696c75726521000000000000000000000000000060448201526064016108dc565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614840579160200282015b8281111561484057825182547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039091161782556020909201916001909101906147f3565b5061484c9291506148c8565b5090565b508054600082559060005260206000209081019061083491906148c8565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b8082111561484c57600081556001016148c9565b80356001600160a01b038116811461435757600080fd5b80604081018310156129d557600080fd5b600082601f83011261491657600080fd5b6040516040810181811067ffffffffffffffff82111715614939576149396154b4565b806040525080838560408601111561495057600080fd5b60005b6002811015614972578135835260209283019290910190600101614953565b509195945050505050565b600060a0828403121561498f57600080fd5b60405160a0810181811067ffffffffffffffff821117156149b2576149b26154b4565b6040529050806149c183614a47565b81526149cf60208401614a47565b60208201526149e060408401614a33565b60408201526149f160608401614a33565b6060820152614a02608084016148dd565b60808201525092915050565b803561ffff8116811461435757600080fd5b803562ffffff8116811461435757600080fd5b803563ffffffff8116811461435757600080fd5b803567ffffffffffffffff8116811461435757600080fd5b805169ffffffffffffffffffff8116811461435757600080fd5b600060208284031215614a8b57600080fd5b61397d826148dd565b60008060608385031215614aa757600080fd5b614ab0836148dd565b9150614abf84602085016148f4565b90509250929050565b60008060008060608587031215614ade57600080fd5b614ae7856148dd565b935060208501359250604085013567ffffffffffffffff80821115614b0b57600080fd5b818701915087601f830112614b1f57600080fd5b813581811115614b2e57600080fd5b886020828501011115614b4057600080fd5b95989497505060200194505050565b60008060408385031215614b6257600080fd5b614b6b836148dd565b915060208301356bffffffffffffffffffffffff81168114614b8c57600080fd5b809150509250929050565b600060408284031215614ba957600080fd5b61397d83836148f4565b600060408284031215614bc557600080fd5b61397d8383614905565b600060208284031215614be157600080fd5b8151801515811461397d57600080fd5b600060208284031215614c0357600080fd5b5051919050565b600080600080600060a08688031215614c2257600080fd5b85359450614c3260208701614a47565b9350614c4060408701614a0e565b9250614c4e60608701614a33565b9150614c5c60808701614a33565b90509295509295909350565b600080828403610240811215614c7d57600080fd5b6101a080821215614c8d57600080fd5b614c95615259565b9150614ca18686614905565b8252614cb08660408701614905565b60208301526080850135604083015260a0850135606083015260c08501356080830152614cdf60e086016148dd565b60a0830152610100614cf387828801614905565b60c0840152614d06876101408801614905565b60e08401526101808601358184015250819350614d258682870161497d565b925050509250929050565b6000806000806000808688036101c0811215614d4b57600080fd5b614d5488614a0e565b9650614d6260208901614a33565b9550614d7060408901614a33565b9450614d7e60608901614a33565b935060808801359250610120807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6083011215614db957600080fd5b614dc1615259565b9150614dcf60a08a01614a33565b8252614ddd60c08a01614a33565b6020830152614dee60e08a01614a33565b6040830152610100614e01818b01614a33565b6060840152614e11828b01614a33565b6080840152614e236101408b01614a20565b60a0840152614e356101608b01614a20565b60c0840152614e476101808b01614a20565b60e0840152614e596101a08b01614a20565b818401525050809150509295509295509295565b600060208284031215614e7f57600080fd5b5035919050565b600060208284031215614e9857600080fd5b61397d82614a47565b60008060408385031215614eb457600080fd5b614ebd83614a47565b9150614abf602084016148dd565b600080600080600060a08688031215614ee357600080fd5b614eec86614a5f565b9450602086015193506040860151925060608601519150614c5c60808701614a5f565b8060005b60028110156109e5578151845260209384019390910190600101614f13565b614f3c8183614f0f565b604001919050565b868152614f546020820187614f0f565b614f616060820186614f0f565b614f6e60a0820185614f0f565b614f7b60e0820184614f0f565b60609190911b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166101208201526101340195945050505050565b838152614fc66020820184614f0f565b606081019190915260800192915050565b604081016129d58284614f0f565b600060208083528351808285015260005b8181101561501257858101830151858201604001528201614ff6565b81811115615024576000604083870101525b50601f01601f1916929092016040019392505050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b8181101561508b5784518352938301939183019160010161506f565b509098975050505050505050565b60006101c08201905061ffff8816825263ffffffff808816602084015280871660408401528086166060840152846080840152835481811660a08501526150ed60c08501838360201c1663ffffffff169052565b61510460e08501838360401c1663ffffffff169052565b61511c6101008501838360601c1663ffffffff169052565b6151346101208501838360801c1663ffffffff169052565b62ffffff60a082901c811661014086015260b882901c811661016086015260d082901c1661018085015260e81c6101a090930192909252979650505050505050565b8281526060810161397d6020830184614f0f565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156151cb578451835293830193918301916001016151af565b5090979650505050505050565b6000608082016bffffffffffffffffffffffff87168352602067ffffffffffffffff8716818501526001600160a01b0380871660408601526080606086015282865180855260a087019150838801945060005b8181101561524957855184168352948401949184019160010161522b565b50909a9950505050505050505050565b604051610120810167ffffffffffffffff8111828210171561527d5761527d6154b4565b60405290565b60008219821115615296576152966153f8565b500190565b600067ffffffffffffffff8083168185168083038211156152be576152be6153f8565b01949350505050565b60006bffffffffffffffffffffffff8083168185168083038211156152be576152be6153f8565b6000826152fd576152fd615427565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561533a5761533a6153f8565b500290565b600082821015615351576153516153f8565b500390565b60006bffffffffffffffffffffffff8381169083168181101561537b5761537b6153f8565b039392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156153b5576153b56153f8565b5060010190565b600067ffffffffffffffff808316818114156153da576153da6153f8565b6001019392505050565b6000826153f3576153f3615427565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", +} + +var VRFCoordinatorTestV2ABI = VRFCoordinatorTestV2MetaData.ABI + +var VRFCoordinatorTestV2Bin = VRFCoordinatorTestV2MetaData.Bin + +func DeployVRFCoordinatorTestV2(auth *bind.TransactOpts, backend bind.ContractBackend, link common.Address, blockhashStore common.Address, linkEthFeed common.Address) (common.Address, *types.Transaction, *VRFCoordinatorTestV2, error) { + parsed, err := VRFCoordinatorTestV2MetaData.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(VRFCoordinatorTestV2Bin), backend, link, blockhashStore, linkEthFeed) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VRFCoordinatorTestV2{address: address, abi: *parsed, VRFCoordinatorTestV2Caller: VRFCoordinatorTestV2Caller{contract: contract}, VRFCoordinatorTestV2Transactor: VRFCoordinatorTestV2Transactor{contract: contract}, VRFCoordinatorTestV2Filterer: VRFCoordinatorTestV2Filterer{contract: contract}}, nil +} + +type VRFCoordinatorTestV2 struct { + address common.Address + abi abi.ABI + VRFCoordinatorTestV2Caller + VRFCoordinatorTestV2Transactor + VRFCoordinatorTestV2Filterer +} + +type VRFCoordinatorTestV2Caller struct { + contract *bind.BoundContract +} + +type VRFCoordinatorTestV2Transactor struct { + contract *bind.BoundContract +} + +type VRFCoordinatorTestV2Filterer struct { + contract *bind.BoundContract +} + +type VRFCoordinatorTestV2Session struct { + Contract *VRFCoordinatorTestV2 + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type VRFCoordinatorTestV2CallerSession struct { + Contract *VRFCoordinatorTestV2Caller + CallOpts bind.CallOpts +} + +type VRFCoordinatorTestV2TransactorSession struct { + Contract *VRFCoordinatorTestV2Transactor + TransactOpts bind.TransactOpts +} + +type VRFCoordinatorTestV2Raw struct { + Contract *VRFCoordinatorTestV2 +} + +type VRFCoordinatorTestV2CallerRaw struct { + Contract *VRFCoordinatorTestV2Caller +} + +type VRFCoordinatorTestV2TransactorRaw struct { + Contract *VRFCoordinatorTestV2Transactor +} + +func NewVRFCoordinatorTestV2(address common.Address, backend bind.ContractBackend) (*VRFCoordinatorTestV2, error) { + abi, err := abi.JSON(strings.NewReader(VRFCoordinatorTestV2ABI)) + if err != nil { + return nil, err + } + contract, err := bindVRFCoordinatorTestV2(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2{address: address, abi: abi, VRFCoordinatorTestV2Caller: VRFCoordinatorTestV2Caller{contract: contract}, VRFCoordinatorTestV2Transactor: VRFCoordinatorTestV2Transactor{contract: contract}, VRFCoordinatorTestV2Filterer: VRFCoordinatorTestV2Filterer{contract: contract}}, nil +} + +func NewVRFCoordinatorTestV2Caller(address common.Address, caller bind.ContractCaller) (*VRFCoordinatorTestV2Caller, error) { + contract, err := bindVRFCoordinatorTestV2(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2Caller{contract: contract}, nil +} + +func NewVRFCoordinatorTestV2Transactor(address common.Address, transactor bind.ContractTransactor) (*VRFCoordinatorTestV2Transactor, error) { + contract, err := bindVRFCoordinatorTestV2(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2Transactor{contract: contract}, nil +} + +func NewVRFCoordinatorTestV2Filterer(address common.Address, filterer bind.ContractFilterer) (*VRFCoordinatorTestV2Filterer, error) { + contract, err := bindVRFCoordinatorTestV2(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2Filterer{contract: contract}, nil +} + +func bindVRFCoordinatorTestV2(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := VRFCoordinatorTestV2MetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFCoordinatorTestV2.Contract.VRFCoordinatorTestV2Caller.contract.Call(opts, result, method, params...) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.VRFCoordinatorTestV2Transactor.contract.Transfer(opts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.VRFCoordinatorTestV2Transactor.contract.Transact(opts, method, params...) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFCoordinatorTestV2.Contract.contract.Call(opts, result, method, params...) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.contract.Transfer(opts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.contract.Transact(opts, method, params...) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) BLOCKHASHSTORE(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "BLOCKHASH_STORE") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) BLOCKHASHSTORE() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.BLOCKHASHSTORE(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) BLOCKHASHSTORE() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.BLOCKHASHSTORE(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) LINK(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "LINK") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) LINK() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.LINK(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) LINK() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.LINK(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) LINKETHFEED(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "LINK_ETH_FEED") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) LINKETHFEED() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.LINKETHFEED(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) LINKETHFEED() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.LINKETHFEED(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "MAX_CONSUMERS") + + if err != nil { + return *new(uint16), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) MAXCONSUMERS() (uint16, error) { + return _VRFCoordinatorTestV2.Contract.MAXCONSUMERS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) MAXCONSUMERS() (uint16, error) { + return _VRFCoordinatorTestV2.Contract.MAXCONSUMERS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) MAXNUMWORDS(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "MAX_NUM_WORDS") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) MAXNUMWORDS() (uint32, error) { + return _VRFCoordinatorTestV2.Contract.MAXNUMWORDS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) MAXNUMWORDS() (uint32, error) { + return _VRFCoordinatorTestV2.Contract.MAXNUMWORDS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) MAXREQUESTCONFIRMATIONS(opts *bind.CallOpts) (uint16, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "MAX_REQUEST_CONFIRMATIONS") + + if err != nil { + return *new(uint16), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) MAXREQUESTCONFIRMATIONS() (uint16, error) { + return _VRFCoordinatorTestV2.Contract.MAXREQUESTCONFIRMATIONS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) MAXREQUESTCONFIRMATIONS() (uint16, error) { + return _VRFCoordinatorTestV2.Contract.MAXREQUESTCONFIRMATIONS(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetCommitment(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getCommitment", requestId) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetCommitment(requestId *big.Int) ([32]byte, error) { + return _VRFCoordinatorTestV2.Contract.GetCommitment(&_VRFCoordinatorTestV2.CallOpts, requestId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetCommitment(requestId *big.Int) ([32]byte, error) { + return _VRFCoordinatorTestV2.Contract.GetCommitment(&_VRFCoordinatorTestV2.CallOpts, requestId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetConfig(opts *bind.CallOpts) (GetConfig, + + error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getConfig") + + outstruct := new(GetConfig) + if err != nil { + return *outstruct, err + } + + outstruct.MinimumRequestConfirmations = *abi.ConvertType(out[0], new(uint16)).(*uint16) + outstruct.MaxGasLimit = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.StalenessSeconds = *abi.ConvertType(out[2], new(uint32)).(*uint32) + outstruct.GasAfterPaymentCalculation = *abi.ConvertType(out[3], new(uint32)).(*uint32) + + return *outstruct, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetConfig() (GetConfig, + + error) { + return _VRFCoordinatorTestV2.Contract.GetConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetConfig() (GetConfig, + + error) { + return _VRFCoordinatorTestV2.Contract.GetConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetCurrentSubId(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getCurrentSubId") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetCurrentSubId() (uint64, error) { + return _VRFCoordinatorTestV2.Contract.GetCurrentSubId(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetCurrentSubId() (uint64, error) { + return _VRFCoordinatorTestV2.Contract.GetCurrentSubId(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetFallbackWeiPerUnitLink(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getFallbackWeiPerUnitLink") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetFallbackWeiPerUnitLink() (*big.Int, error) { + return _VRFCoordinatorTestV2.Contract.GetFallbackWeiPerUnitLink(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetFallbackWeiPerUnitLink() (*big.Int, error) { + return _VRFCoordinatorTestV2.Contract.GetFallbackWeiPerUnitLink(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetFeeConfig(opts *bind.CallOpts) (GetFeeConfig, + + error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getFeeConfig") + + outstruct := new(GetFeeConfig) + if err != nil { + return *outstruct, err + } + + outstruct.FulfillmentFlatFeeLinkPPMTier1 = *abi.ConvertType(out[0], new(uint32)).(*uint32) + outstruct.FulfillmentFlatFeeLinkPPMTier2 = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.FulfillmentFlatFeeLinkPPMTier3 = *abi.ConvertType(out[2], new(uint32)).(*uint32) + outstruct.FulfillmentFlatFeeLinkPPMTier4 = *abi.ConvertType(out[3], new(uint32)).(*uint32) + outstruct.FulfillmentFlatFeeLinkPPMTier5 = *abi.ConvertType(out[4], new(uint32)).(*uint32) + outstruct.ReqsForTier2 = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + outstruct.ReqsForTier3 = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) + outstruct.ReqsForTier4 = *abi.ConvertType(out[7], new(*big.Int)).(**big.Int) + outstruct.ReqsForTier5 = *abi.ConvertType(out[8], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetFeeConfig() (GetFeeConfig, + + error) { + return _VRFCoordinatorTestV2.Contract.GetFeeConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetFeeConfig() (GetFeeConfig, + + error) { + return _VRFCoordinatorTestV2.Contract.GetFeeConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetFeeTier(opts *bind.CallOpts, reqCount uint64) (uint32, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getFeeTier", reqCount) + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetFeeTier(reqCount uint64) (uint32, error) { + return _VRFCoordinatorTestV2.Contract.GetFeeTier(&_VRFCoordinatorTestV2.CallOpts, reqCount) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetFeeTier(reqCount uint64) (uint32, error) { + return _VRFCoordinatorTestV2.Contract.GetFeeTier(&_VRFCoordinatorTestV2.CallOpts, reqCount) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetRequestConfig(opts *bind.CallOpts) (uint16, uint32, [][32]byte, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getRequestConfig") + + if err != nil { + return *new(uint16), *new(uint32), *new([][32]byte), err + } + + out0 := *abi.ConvertType(out[0], new(uint16)).(*uint16) + out1 := *abi.ConvertType(out[1], new(uint32)).(*uint32) + out2 := *abi.ConvertType(out[2], new([][32]byte)).(*[][32]byte) + + return out0, out1, out2, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetRequestConfig() (uint16, uint32, [][32]byte, error) { + return _VRFCoordinatorTestV2.Contract.GetRequestConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetRequestConfig() (uint16, uint32, [][32]byte, error) { + return _VRFCoordinatorTestV2.Contract.GetRequestConfig(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetSubscription(opts *bind.CallOpts, subId uint64) (GetSubscription, + + error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getSubscription", subId) + + outstruct := new(GetSubscription) + if err != nil { + return *outstruct, err + } + + outstruct.Balance = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.ReqCount = *abi.ConvertType(out[1], new(uint64)).(*uint64) + outstruct.Owner = *abi.ConvertType(out[2], new(common.Address)).(*common.Address) + outstruct.Consumers = *abi.ConvertType(out[3], new([]common.Address)).(*[]common.Address) + + return *outstruct, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetSubscription(subId uint64) (GetSubscription, + + error) { + return _VRFCoordinatorTestV2.Contract.GetSubscription(&_VRFCoordinatorTestV2.CallOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetSubscription(subId uint64) (GetSubscription, + + error) { + return _VRFCoordinatorTestV2.Contract.GetSubscription(&_VRFCoordinatorTestV2.CallOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) GetTotalBalance(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "getTotalBalance") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) GetTotalBalance() (*big.Int, error) { + return _VRFCoordinatorTestV2.Contract.GetTotalBalance(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) GetTotalBalance() (*big.Int, error) { + return _VRFCoordinatorTestV2.Contract.GetTotalBalance(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) HashOfKey(opts *bind.CallOpts, publicKey [2]*big.Int) ([32]byte, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "hashOfKey", publicKey) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) HashOfKey(publicKey [2]*big.Int) ([32]byte, error) { + return _VRFCoordinatorTestV2.Contract.HashOfKey(&_VRFCoordinatorTestV2.CallOpts, publicKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) HashOfKey(publicKey [2]*big.Int) ([32]byte, error) { + return _VRFCoordinatorTestV2.Contract.HashOfKey(&_VRFCoordinatorTestV2.CallOpts, publicKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) Owner() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.Owner(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) Owner() (common.Address, error) { + return _VRFCoordinatorTestV2.Contract.Owner(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) PendingRequestExists(opts *bind.CallOpts, subId uint64) (bool, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "pendingRequestExists", subId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) PendingRequestExists(subId uint64) (bool, error) { + return _VRFCoordinatorTestV2.Contract.PendingRequestExists(&_VRFCoordinatorTestV2.CallOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) PendingRequestExists(subId uint64) (bool, error) { + return _VRFCoordinatorTestV2.Contract.PendingRequestExists(&_VRFCoordinatorTestV2.CallOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Caller) TypeAndVersion(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _VRFCoordinatorTestV2.contract.Call(opts, &out, "typeAndVersion") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) TypeAndVersion() (string, error) { + return _VRFCoordinatorTestV2.Contract.TypeAndVersion(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2CallerSession) TypeAndVersion() (string, error) { + return _VRFCoordinatorTestV2.Contract.TypeAndVersion(&_VRFCoordinatorTestV2.CallOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "acceptOwnership") +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) AcceptOwnership() (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AcceptOwnership(&_VRFCoordinatorTestV2.TransactOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AcceptOwnership(&_VRFCoordinatorTestV2.TransactOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "acceptSubscriptionOwnerTransfer", subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) AcceptSubscriptionOwnerTransfer(subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AcceptSubscriptionOwnerTransfer(&_VRFCoordinatorTestV2.TransactOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) AcceptSubscriptionOwnerTransfer(subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AcceptSubscriptionOwnerTransfer(&_VRFCoordinatorTestV2.TransactOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) AddConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "addConsumer", subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) AddConsumer(subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AddConsumer(&_VRFCoordinatorTestV2.TransactOpts, subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) AddConsumer(subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.AddConsumer(&_VRFCoordinatorTestV2.TransactOpts, subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) CancelSubscription(opts *bind.TransactOpts, subId uint64, to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "cancelSubscription", subId, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) CancelSubscription(subId uint64, to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.CancelSubscription(&_VRFCoordinatorTestV2.TransactOpts, subId, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) CancelSubscription(subId uint64, to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.CancelSubscription(&_VRFCoordinatorTestV2.TransactOpts, subId, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "createSubscription") +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) CreateSubscription() (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.CreateSubscription(&_VRFCoordinatorTestV2.TransactOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) CreateSubscription() (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.CreateSubscription(&_VRFCoordinatorTestV2.TransactOpts) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) DeregisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "deregisterProvingKey", publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) DeregisterProvingKey(publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.DeregisterProvingKey(&_VRFCoordinatorTestV2.TransactOpts, publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) DeregisterProvingKey(publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.DeregisterProvingKey(&_VRFCoordinatorTestV2.TransactOpts, publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFCoordinatorTestV2RequestCommitment) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "fulfillRandomWords", proof, rc) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) FulfillRandomWords(proof VRFProof, rc VRFCoordinatorTestV2RequestCommitment) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.FulfillRandomWords(&_VRFCoordinatorTestV2.TransactOpts, proof, rc) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) FulfillRandomWords(proof VRFProof, rc VRFCoordinatorTestV2RequestCommitment) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.FulfillRandomWords(&_VRFCoordinatorTestV2.TransactOpts, proof, rc) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "onTokenTransfer", arg0, amount, data) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) OnTokenTransfer(arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OnTokenTransfer(&_VRFCoordinatorTestV2.TransactOpts, arg0, amount, data) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) OnTokenTransfer(arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OnTokenTransfer(&_VRFCoordinatorTestV2.TransactOpts, arg0, amount, data) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "oracleWithdraw", recipient, amount) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) OracleWithdraw(recipient common.Address, amount *big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OracleWithdraw(&_VRFCoordinatorTestV2.TransactOpts, recipient, amount) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) OracleWithdraw(recipient common.Address, amount *big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OracleWithdraw(&_VRFCoordinatorTestV2.TransactOpts, recipient, amount) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) OwnerCancelSubscription(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "ownerCancelSubscription", subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) OwnerCancelSubscription(subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OwnerCancelSubscription(&_VRFCoordinatorTestV2.TransactOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) OwnerCancelSubscription(subId uint64) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.OwnerCancelSubscription(&_VRFCoordinatorTestV2.TransactOpts, subId) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) RecoverFunds(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "recoverFunds", to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) RecoverFunds(to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RecoverFunds(&_VRFCoordinatorTestV2.TransactOpts, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) RecoverFunds(to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RecoverFunds(&_VRFCoordinatorTestV2.TransactOpts, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "registerProvingKey", oracle, publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) RegisterProvingKey(oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RegisterProvingKey(&_VRFCoordinatorTestV2.TransactOpts, oracle, publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) RegisterProvingKey(oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RegisterProvingKey(&_VRFCoordinatorTestV2.TransactOpts, oracle, publicProvingKey) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) RemoveConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "removeConsumer", subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) RemoveConsumer(subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RemoveConsumer(&_VRFCoordinatorTestV2.TransactOpts, subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) RemoveConsumer(subId uint64, consumer common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RemoveConsumer(&_VRFCoordinatorTestV2.TransactOpts, subId, consumer) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) RequestRandomWords(opts *bind.TransactOpts, keyHash [32]byte, subId uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "requestRandomWords", keyHash, subId, requestConfirmations, callbackGasLimit, numWords) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) RequestRandomWords(keyHash [32]byte, subId uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RequestRandomWords(&_VRFCoordinatorTestV2.TransactOpts, keyHash, subId, requestConfirmations, callbackGasLimit, numWords) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) RequestRandomWords(keyHash [32]byte, subId uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RequestRandomWords(&_VRFCoordinatorTestV2.TransactOpts, keyHash, subId, requestConfirmations, callbackGasLimit, numWords) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64, newOwner common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "requestSubscriptionOwnerTransfer", subId, newOwner) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) RequestSubscriptionOwnerTransfer(subId uint64, newOwner common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RequestSubscriptionOwnerTransfer(&_VRFCoordinatorTestV2.TransactOpts, subId, newOwner) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) RequestSubscriptionOwnerTransfer(subId uint64, newOwner common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.RequestSubscriptionOwnerTransfer(&_VRFCoordinatorTestV2.TransactOpts, subId, newOwner) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) SetConfig(opts *bind.TransactOpts, minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig VRFCoordinatorTestV2FeeConfig) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "setConfig", minimumRequestConfirmations, maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, feeConfig) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) SetConfig(minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig VRFCoordinatorTestV2FeeConfig) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.SetConfig(&_VRFCoordinatorTestV2.TransactOpts, minimumRequestConfirmations, maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, feeConfig) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) SetConfig(minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig VRFCoordinatorTestV2FeeConfig) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.SetConfig(&_VRFCoordinatorTestV2.TransactOpts, minimumRequestConfirmations, maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, feeConfig) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Transactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.contract.Transact(opts, "transferOwnership", to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Session) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.TransferOwnership(&_VRFCoordinatorTestV2.TransactOpts, to) +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2TransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _VRFCoordinatorTestV2.Contract.TransferOwnership(&_VRFCoordinatorTestV2.TransactOpts, to) +} + +type VRFCoordinatorTestV2ConfigSetIterator struct { + Event *VRFCoordinatorTestV2ConfigSet + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2ConfigSetIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2ConfigSet) + 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(VRFCoordinatorTestV2ConfigSet) + 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 *VRFCoordinatorTestV2ConfigSetIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2ConfigSetIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2ConfigSet struct { + MinimumRequestConfirmations uint16 + MaxGasLimit uint32 + StalenessSeconds uint32 + GasAfterPaymentCalculation uint32 + FallbackWeiPerUnitLink *big.Int + FeeConfig VRFCoordinatorTestV2FeeConfig + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorTestV2ConfigSetIterator, error) { + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2ConfigSetIterator{contract: _VRFCoordinatorTestV2.contract, event: "ConfigSet", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ConfigSet) (event.Subscription, error) { + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "ConfigSet") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2ConfigSet) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ConfigSet", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseConfigSet(log types.Log) (*VRFCoordinatorTestV2ConfigSet, error) { + event := new(VRFCoordinatorTestV2ConfigSet) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ConfigSet", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2FundsRecoveredIterator struct { + Event *VRFCoordinatorTestV2FundsRecovered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2FundsRecoveredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2FundsRecovered) + 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(VRFCoordinatorTestV2FundsRecovered) + 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 *VRFCoordinatorTestV2FundsRecoveredIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2FundsRecoveredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2FundsRecovered struct { + To common.Address + Amount *big.Int + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterFundsRecovered(opts *bind.FilterOpts) (*VRFCoordinatorTestV2FundsRecoveredIterator, error) { + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "FundsRecovered") + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2FundsRecoveredIterator{contract: _VRFCoordinatorTestV2.contract, event: "FundsRecovered", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchFundsRecovered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2FundsRecovered) (event.Subscription, error) { + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "FundsRecovered") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2FundsRecovered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "FundsRecovered", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseFundsRecovered(log types.Log) (*VRFCoordinatorTestV2FundsRecovered, error) { + event := new(VRFCoordinatorTestV2FundsRecovered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "FundsRecovered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2OwnershipTransferRequestedIterator struct { + Event *VRFCoordinatorTestV2OwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2OwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2OwnershipTransferRequested) + 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(VRFCoordinatorTestV2OwnershipTransferRequested) + 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 *VRFCoordinatorTestV2OwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2OwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2OwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorTestV2OwnershipTransferRequestedIterator, 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 := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2OwnershipTransferRequestedIterator{contract: _VRFCoordinatorTestV2.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2OwnershipTransferRequested, 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 := _VRFCoordinatorTestV2.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(VRFCoordinatorTestV2OwnershipTransferRequested) + if err := _VRFCoordinatorTestV2.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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseOwnershipTransferRequested(log types.Log) (*VRFCoordinatorTestV2OwnershipTransferRequested, error) { + event := new(VRFCoordinatorTestV2OwnershipTransferRequested) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2OwnershipTransferredIterator struct { + Event *VRFCoordinatorTestV2OwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2OwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2OwnershipTransferred) + 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(VRFCoordinatorTestV2OwnershipTransferred) + 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 *VRFCoordinatorTestV2OwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2OwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2OwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorTestV2OwnershipTransferredIterator, 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 := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2OwnershipTransferredIterator{contract: _VRFCoordinatorTestV2.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2OwnershipTransferred, 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 := _VRFCoordinatorTestV2.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(VRFCoordinatorTestV2OwnershipTransferred) + if err := _VRFCoordinatorTestV2.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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseOwnershipTransferred(log types.Log) (*VRFCoordinatorTestV2OwnershipTransferred, error) { + event := new(VRFCoordinatorTestV2OwnershipTransferred) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2ProvingKeyDeregisteredIterator struct { + Event *VRFCoordinatorTestV2ProvingKeyDeregistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2ProvingKeyDeregisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2ProvingKeyDeregistered) + 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(VRFCoordinatorTestV2ProvingKeyDeregistered) + 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 *VRFCoordinatorTestV2ProvingKeyDeregisteredIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2ProvingKeyDeregisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2ProvingKeyDeregistered struct { + KeyHash [32]byte + Oracle common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterProvingKeyDeregistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorTestV2ProvingKeyDeregisteredIterator, error) { + + var oracleRule []interface{} + for _, oracleItem := range oracle { + oracleRule = append(oracleRule, oracleItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "ProvingKeyDeregistered", oracleRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2ProvingKeyDeregisteredIterator{contract: _VRFCoordinatorTestV2.contract, event: "ProvingKeyDeregistered", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchProvingKeyDeregistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ProvingKeyDeregistered, oracle []common.Address) (event.Subscription, error) { + + var oracleRule []interface{} + for _, oracleItem := range oracle { + oracleRule = append(oracleRule, oracleItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "ProvingKeyDeregistered", oracleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2ProvingKeyDeregistered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ProvingKeyDeregistered", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseProvingKeyDeregistered(log types.Log) (*VRFCoordinatorTestV2ProvingKeyDeregistered, error) { + event := new(VRFCoordinatorTestV2ProvingKeyDeregistered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ProvingKeyDeregistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2ProvingKeyRegisteredIterator struct { + Event *VRFCoordinatorTestV2ProvingKeyRegistered + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2ProvingKeyRegisteredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2ProvingKeyRegistered) + 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(VRFCoordinatorTestV2ProvingKeyRegistered) + 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 *VRFCoordinatorTestV2ProvingKeyRegisteredIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2ProvingKeyRegisteredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2ProvingKeyRegistered struct { + KeyHash [32]byte + Oracle common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterProvingKeyRegistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorTestV2ProvingKeyRegisteredIterator, error) { + + var oracleRule []interface{} + for _, oracleItem := range oracle { + oracleRule = append(oracleRule, oracleItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "ProvingKeyRegistered", oracleRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2ProvingKeyRegisteredIterator{contract: _VRFCoordinatorTestV2.contract, event: "ProvingKeyRegistered", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ProvingKeyRegistered, oracle []common.Address) (event.Subscription, error) { + + var oracleRule []interface{} + for _, oracleItem := range oracle { + oracleRule = append(oracleRule, oracleItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "ProvingKeyRegistered", oracleRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2ProvingKeyRegistered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ProvingKeyRegistered", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseProvingKeyRegistered(log types.Log) (*VRFCoordinatorTestV2ProvingKeyRegistered, error) { + event := new(VRFCoordinatorTestV2ProvingKeyRegistered) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "ProvingKeyRegistered", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2RandomWordsFulfilledIterator struct { + Event *VRFCoordinatorTestV2RandomWordsFulfilled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2RandomWordsFulfilledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2RandomWordsFulfilled) + 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(VRFCoordinatorTestV2RandomWordsFulfilled) + 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 *VRFCoordinatorTestV2RandomWordsFulfilledIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2RandomWordsFulfilledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2RandomWordsFulfilled struct { + RequestId *big.Int + OutputSeed *big.Int + Payment *big.Int + Success bool + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int) (*VRFCoordinatorTestV2RandomWordsFulfilledIterator, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "RandomWordsFulfilled", requestIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2RandomWordsFulfilledIterator{contract: _VRFCoordinatorTestV2.contract, event: "RandomWordsFulfilled", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2RandomWordsFulfilled, requestId []*big.Int) (event.Subscription, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "RandomWordsFulfilled", requestIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2RandomWordsFulfilled) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "RandomWordsFulfilled", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseRandomWordsFulfilled(log types.Log) (*VRFCoordinatorTestV2RandomWordsFulfilled, error) { + event := new(VRFCoordinatorTestV2RandomWordsFulfilled) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "RandomWordsFulfilled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2RandomWordsRequestedIterator struct { + Event *VRFCoordinatorTestV2RandomWordsRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2RandomWordsRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2RandomWordsRequested) + 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(VRFCoordinatorTestV2RandomWordsRequested) + 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 *VRFCoordinatorTestV2RandomWordsRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2RandomWordsRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2RandomWordsRequested struct { + KeyHash [32]byte + RequestId *big.Int + PreSeed *big.Int + SubId uint64 + MinimumRequestConfirmations uint16 + CallbackGasLimit uint32 + NumWords uint32 + Sender common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subId []uint64, sender []common.Address) (*VRFCoordinatorTestV2RandomWordsRequestedIterator, error) { + + var keyHashRule []interface{} + for _, keyHashItem := range keyHash { + keyHashRule = append(keyHashRule, keyHashItem) + } + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "RandomWordsRequested", keyHashRule, subIdRule, senderRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2RandomWordsRequestedIterator{contract: _VRFCoordinatorTestV2.contract, event: "RandomWordsRequested", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchRandomWordsRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2RandomWordsRequested, keyHash [][32]byte, subId []uint64, sender []common.Address) (event.Subscription, error) { + + var keyHashRule []interface{} + for _, keyHashItem := range keyHash { + keyHashRule = append(keyHashRule, keyHashItem) + } + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "RandomWordsRequested", keyHashRule, subIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2RandomWordsRequested) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "RandomWordsRequested", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseRandomWordsRequested(log types.Log) (*VRFCoordinatorTestV2RandomWordsRequested, error) { + event := new(VRFCoordinatorTestV2RandomWordsRequested) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "RandomWordsRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionCanceledIterator struct { + Event *VRFCoordinatorTestV2SubscriptionCanceled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionCanceledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionCanceled) + 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(VRFCoordinatorTestV2SubscriptionCanceled) + 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 *VRFCoordinatorTestV2SubscriptionCanceledIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionCanceledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionCanceled struct { + SubId uint64 + To common.Address + Amount *big.Int + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionCanceledIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionCanceled", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionCanceledIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionCanceled", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionCanceled, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionCanceled", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionCanceled) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionCanceled", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionCanceled(log types.Log) (*VRFCoordinatorTestV2SubscriptionCanceled, error) { + event := new(VRFCoordinatorTestV2SubscriptionCanceled) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionCanceled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionConsumerAddedIterator struct { + Event *VRFCoordinatorTestV2SubscriptionConsumerAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionConsumerAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionConsumerAdded) + 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(VRFCoordinatorTestV2SubscriptionConsumerAdded) + 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 *VRFCoordinatorTestV2SubscriptionConsumerAddedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionConsumerAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionConsumerAdded struct { + SubId uint64 + Consumer common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionConsumerAddedIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionConsumerAdded", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionConsumerAddedIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionConsumerAdded", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionConsumerAdded, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionConsumerAdded", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionConsumerAdded) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionConsumerAdded", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionConsumerAdded(log types.Log) (*VRFCoordinatorTestV2SubscriptionConsumerAdded, error) { + event := new(VRFCoordinatorTestV2SubscriptionConsumerAdded) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionConsumerAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator struct { + Event *VRFCoordinatorTestV2SubscriptionConsumerRemoved + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionConsumerRemoved) + 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(VRFCoordinatorTestV2SubscriptionConsumerRemoved) + 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 *VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionConsumerRemoved struct { + SubId uint64 + Consumer common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionConsumerRemoved", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionConsumerRemoved", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionConsumerRemoved, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionConsumerRemoved", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionConsumerRemoved) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionConsumerRemoved", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionConsumerRemoved(log types.Log) (*VRFCoordinatorTestV2SubscriptionConsumerRemoved, error) { + event := new(VRFCoordinatorTestV2SubscriptionConsumerRemoved) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionConsumerRemoved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionCreatedIterator struct { + Event *VRFCoordinatorTestV2SubscriptionCreated + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionCreatedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionCreated) + 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(VRFCoordinatorTestV2SubscriptionCreated) + 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 *VRFCoordinatorTestV2SubscriptionCreatedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionCreatedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionCreated struct { + SubId uint64 + Owner common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionCreated(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionCreatedIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionCreated", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionCreatedIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionCreated", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionCreated, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionCreated", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionCreated) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionCreated", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionCreated(log types.Log) (*VRFCoordinatorTestV2SubscriptionCreated, error) { + event := new(VRFCoordinatorTestV2SubscriptionCreated) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionCreated", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionFundedIterator struct { + Event *VRFCoordinatorTestV2SubscriptionFunded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionFundedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionFunded) + 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(VRFCoordinatorTestV2SubscriptionFunded) + 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 *VRFCoordinatorTestV2SubscriptionFundedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionFundedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionFunded struct { + SubId uint64 + OldBalance *big.Int + NewBalance *big.Int + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionFunded(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionFundedIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionFunded", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionFundedIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionFunded", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionFunded, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionFunded", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionFunded) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionFunded", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionFunded(log types.Log) (*VRFCoordinatorTestV2SubscriptionFunded, error) { + event := new(VRFCoordinatorTestV2SubscriptionFunded) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionFunded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator struct { + Event *VRFCoordinatorTestV2SubscriptionOwnerTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionOwnerTransferRequested) + 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(VRFCoordinatorTestV2SubscriptionOwnerTransferRequested) + 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 *VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionOwnerTransferRequested struct { + SubId uint64 + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionOwnerTransferRequested", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionOwnerTransferRequested", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionOwnerTransferRequested, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionOwnerTransferRequested", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionOwnerTransferRequested) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionOwnerTransferRequested", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionOwnerTransferRequested(log types.Log) (*VRFCoordinatorTestV2SubscriptionOwnerTransferRequested, error) { + event := new(VRFCoordinatorTestV2SubscriptionOwnerTransferRequested) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionOwnerTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator struct { + Event *VRFCoordinatorTestV2SubscriptionOwnerTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFCoordinatorTestV2SubscriptionOwnerTransferred) + 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(VRFCoordinatorTestV2SubscriptionOwnerTransferred) + 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 *VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator) Error() error { + return it.fail +} + +func (it *VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFCoordinatorTestV2SubscriptionOwnerTransferred struct { + SubId uint64 + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.FilterLogs(opts, "SubscriptionOwnerTransferred", subIdRule) + if err != nil { + return nil, err + } + return &VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator{contract: _VRFCoordinatorTestV2.contract, event: "SubscriptionOwnerTransferred", logs: logs, sub: sub}, nil +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionOwnerTransferred, subId []uint64) (event.Subscription, error) { + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + logs, sub, err := _VRFCoordinatorTestV2.contract.WatchLogs(opts, "SubscriptionOwnerTransferred", subIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFCoordinatorTestV2SubscriptionOwnerTransferred) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionOwnerTransferred", 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 (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2Filterer) ParseSubscriptionOwnerTransferred(log types.Log) (*VRFCoordinatorTestV2SubscriptionOwnerTransferred, error) { + event := new(VRFCoordinatorTestV2SubscriptionOwnerTransferred) + if err := _VRFCoordinatorTestV2.contract.UnpackLog(event, "SubscriptionOwnerTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type GetConfig struct { + MinimumRequestConfirmations uint16 + MaxGasLimit uint32 + StalenessSeconds uint32 + GasAfterPaymentCalculation uint32 +} +type GetFeeConfig struct { + FulfillmentFlatFeeLinkPPMTier1 uint32 + FulfillmentFlatFeeLinkPPMTier2 uint32 + FulfillmentFlatFeeLinkPPMTier3 uint32 + FulfillmentFlatFeeLinkPPMTier4 uint32 + FulfillmentFlatFeeLinkPPMTier5 uint32 + ReqsForTier2 *big.Int + ReqsForTier3 *big.Int + ReqsForTier4 *big.Int + ReqsForTier5 *big.Int +} +type GetSubscription struct { + Balance *big.Int + ReqCount uint64 + Owner common.Address + Consumers []common.Address +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _VRFCoordinatorTestV2.abi.Events["ConfigSet"].ID: + return _VRFCoordinatorTestV2.ParseConfigSet(log) + case _VRFCoordinatorTestV2.abi.Events["FundsRecovered"].ID: + return _VRFCoordinatorTestV2.ParseFundsRecovered(log) + case _VRFCoordinatorTestV2.abi.Events["OwnershipTransferRequested"].ID: + return _VRFCoordinatorTestV2.ParseOwnershipTransferRequested(log) + case _VRFCoordinatorTestV2.abi.Events["OwnershipTransferred"].ID: + return _VRFCoordinatorTestV2.ParseOwnershipTransferred(log) + case _VRFCoordinatorTestV2.abi.Events["ProvingKeyDeregistered"].ID: + return _VRFCoordinatorTestV2.ParseProvingKeyDeregistered(log) + case _VRFCoordinatorTestV2.abi.Events["ProvingKeyRegistered"].ID: + return _VRFCoordinatorTestV2.ParseProvingKeyRegistered(log) + case _VRFCoordinatorTestV2.abi.Events["RandomWordsFulfilled"].ID: + return _VRFCoordinatorTestV2.ParseRandomWordsFulfilled(log) + case _VRFCoordinatorTestV2.abi.Events["RandomWordsRequested"].ID: + return _VRFCoordinatorTestV2.ParseRandomWordsRequested(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionCanceled"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionCanceled(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionConsumerAdded"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionConsumerAdded(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionConsumerRemoved"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionConsumerRemoved(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionCreated"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionCreated(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionFunded"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionFunded(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionOwnerTransferRequested"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionOwnerTransferRequested(log) + case _VRFCoordinatorTestV2.abi.Events["SubscriptionOwnerTransferred"].ID: + return _VRFCoordinatorTestV2.ParseSubscriptionOwnerTransferred(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (VRFCoordinatorTestV2ConfigSet) Topic() common.Hash { + return common.HexToHash("0xc21e3bd2e0b339d2848f0dd956947a88966c242c0c0c582a33137a5c1ceb5cb2") +} + +func (VRFCoordinatorTestV2FundsRecovered) Topic() common.Hash { + return common.HexToHash("0x59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600") +} + +func (VRFCoordinatorTestV2OwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (VRFCoordinatorTestV2OwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (VRFCoordinatorTestV2ProvingKeyDeregistered) Topic() common.Hash { + return common.HexToHash("0x72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d") +} + +func (VRFCoordinatorTestV2ProvingKeyRegistered) Topic() common.Hash { + return common.HexToHash("0xe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b8") +} + +func (VRFCoordinatorTestV2RandomWordsFulfilled) Topic() common.Hash { + return common.HexToHash("0x7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4") +} + +func (VRFCoordinatorTestV2RandomWordsRequested) Topic() common.Hash { + return common.HexToHash("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772") +} + +func (VRFCoordinatorTestV2SubscriptionCanceled) Topic() common.Hash { + return common.HexToHash("0xe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815") +} + +func (VRFCoordinatorTestV2SubscriptionConsumerAdded) Topic() common.Hash { + return common.HexToHash("0x43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e0") +} + +func (VRFCoordinatorTestV2SubscriptionConsumerRemoved) Topic() common.Hash { + return common.HexToHash("0x182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b") +} + +func (VRFCoordinatorTestV2SubscriptionCreated) Topic() common.Hash { + return common.HexToHash("0x464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf") +} + +func (VRFCoordinatorTestV2SubscriptionFunded) Topic() common.Hash { + return common.HexToHash("0xd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f8") +} + +func (VRFCoordinatorTestV2SubscriptionOwnerTransferRequested) Topic() common.Hash { + return common.HexToHash("0x69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be") +} + +func (VRFCoordinatorTestV2SubscriptionOwnerTransferred) Topic() common.Hash { + return common.HexToHash("0x6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f0") +} + +func (_VRFCoordinatorTestV2 *VRFCoordinatorTestV2) Address() common.Address { + return _VRFCoordinatorTestV2.address +} + +type VRFCoordinatorTestV2Interface interface { + BLOCKHASHSTORE(opts *bind.CallOpts) (common.Address, error) + + LINK(opts *bind.CallOpts) (common.Address, error) + + LINKETHFEED(opts *bind.CallOpts) (common.Address, error) + + MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) + + MAXNUMWORDS(opts *bind.CallOpts) (uint32, error) + + MAXREQUESTCONFIRMATIONS(opts *bind.CallOpts) (uint16, error) + + GetCommitment(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) + + GetConfig(opts *bind.CallOpts) (GetConfig, + + error) + + GetCurrentSubId(opts *bind.CallOpts) (uint64, error) + + GetFallbackWeiPerUnitLink(opts *bind.CallOpts) (*big.Int, error) + + GetFeeConfig(opts *bind.CallOpts) (GetFeeConfig, + + error) + + GetFeeTier(opts *bind.CallOpts, reqCount uint64) (uint32, error) + + GetRequestConfig(opts *bind.CallOpts) (uint16, uint32, [][32]byte, error) + + GetSubscription(opts *bind.CallOpts, subId uint64) (GetSubscription, + + error) + + GetTotalBalance(opts *bind.CallOpts) (*big.Int, error) + + HashOfKey(opts *bind.CallOpts, publicKey [2]*big.Int) ([32]byte, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + PendingRequestExists(opts *bind.CallOpts, subId uint64) (bool, error) + + TypeAndVersion(opts *bind.CallOpts) (string, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) + + AddConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) + + CancelSubscription(opts *bind.TransactOpts, subId uint64, to common.Address) (*types.Transaction, error) + + CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) + + DeregisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) + + FulfillRandomWords(opts *bind.TransactOpts, proof VRFProof, rc VRFCoordinatorTestV2RequestCommitment) (*types.Transaction, error) + + OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) + + OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) + + OwnerCancelSubscription(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) + + RecoverFunds(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) + + RemoveConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) + + RequestRandomWords(opts *bind.TransactOpts, keyHash [32]byte, subId uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32) (*types.Transaction, error) + + RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64, newOwner common.Address) (*types.Transaction, error) + + SetConfig(opts *bind.TransactOpts, minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig VRFCoordinatorTestV2FeeConfig) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + FilterConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorTestV2ConfigSetIterator, error) + + WatchConfigSet(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ConfigSet) (event.Subscription, error) + + ParseConfigSet(log types.Log) (*VRFCoordinatorTestV2ConfigSet, error) + + FilterFundsRecovered(opts *bind.FilterOpts) (*VRFCoordinatorTestV2FundsRecoveredIterator, error) + + WatchFundsRecovered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2FundsRecovered) (event.Subscription, error) + + ParseFundsRecovered(log types.Log) (*VRFCoordinatorTestV2FundsRecovered, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorTestV2OwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2OwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*VRFCoordinatorTestV2OwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFCoordinatorTestV2OwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2OwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*VRFCoordinatorTestV2OwnershipTransferred, error) + + FilterProvingKeyDeregistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorTestV2ProvingKeyDeregisteredIterator, error) + + WatchProvingKeyDeregistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ProvingKeyDeregistered, oracle []common.Address) (event.Subscription, error) + + ParseProvingKeyDeregistered(log types.Log) (*VRFCoordinatorTestV2ProvingKeyDeregistered, error) + + FilterProvingKeyRegistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorTestV2ProvingKeyRegisteredIterator, error) + + WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2ProvingKeyRegistered, oracle []common.Address) (event.Subscription, error) + + ParseProvingKeyRegistered(log types.Log) (*VRFCoordinatorTestV2ProvingKeyRegistered, error) + + FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int) (*VRFCoordinatorTestV2RandomWordsFulfilledIterator, error) + + WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2RandomWordsFulfilled, requestId []*big.Int) (event.Subscription, error) + + ParseRandomWordsFulfilled(log types.Log) (*VRFCoordinatorTestV2RandomWordsFulfilled, error) + + FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subId []uint64, sender []common.Address) (*VRFCoordinatorTestV2RandomWordsRequestedIterator, error) + + WatchRandomWordsRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2RandomWordsRequested, keyHash [][32]byte, subId []uint64, sender []common.Address) (event.Subscription, error) + + ParseRandomWordsRequested(log types.Log) (*VRFCoordinatorTestV2RandomWordsRequested, error) + + FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionCanceledIterator, error) + + WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionCanceled, subId []uint64) (event.Subscription, error) + + ParseSubscriptionCanceled(log types.Log) (*VRFCoordinatorTestV2SubscriptionCanceled, error) + + FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionConsumerAddedIterator, error) + + WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionConsumerAdded, subId []uint64) (event.Subscription, error) + + ParseSubscriptionConsumerAdded(log types.Log) (*VRFCoordinatorTestV2SubscriptionConsumerAdded, error) + + FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionConsumerRemovedIterator, error) + + WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionConsumerRemoved, subId []uint64) (event.Subscription, error) + + ParseSubscriptionConsumerRemoved(log types.Log) (*VRFCoordinatorTestV2SubscriptionConsumerRemoved, error) + + FilterSubscriptionCreated(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionCreatedIterator, error) + + WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionCreated, subId []uint64) (event.Subscription, error) + + ParseSubscriptionCreated(log types.Log) (*VRFCoordinatorTestV2SubscriptionCreated, error) + + FilterSubscriptionFunded(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionFundedIterator, error) + + WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionFunded, subId []uint64) (event.Subscription, error) + + ParseSubscriptionFunded(log types.Log) (*VRFCoordinatorTestV2SubscriptionFunded, error) + + FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionOwnerTransferRequestedIterator, error) + + WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionOwnerTransferRequested, subId []uint64) (event.Subscription, error) + + ParseSubscriptionOwnerTransferRequested(log types.Log) (*VRFCoordinatorTestV2SubscriptionOwnerTransferRequested, error) + + FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []uint64) (*VRFCoordinatorTestV2SubscriptionOwnerTransferredIterator, error) + + WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorTestV2SubscriptionOwnerTransferred, subId []uint64) (event.Subscription, error) + + ParseSubscriptionOwnerTransferred(log types.Log) (*VRFCoordinatorTestV2SubscriptionOwnerTransferred, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go b/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go index 62e8b9f0de3..1475c56499f 100644 --- a/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go +++ b/core/gethwrappers/generated/vrf_coordinator_v2_5/vrf_coordinator_v2_5.go @@ -66,8 +66,8 @@ type VRFV2PlusClientRandomWordsRequest struct { } var VRFCoordinatorV25MetaData = &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\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"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\":\"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\":[],\"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\":\"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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2_5.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorDeregistered\",\"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\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"name\":\"ProvingKeyDeregistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"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\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"deregisterMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"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\":\"structVRFCoordinatorV2_5.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"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\":\"\",\"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\":\"owner\",\"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\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"onTokenTransfer\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdrawNative\",\"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\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"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\"}],\"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\":[],\"name\":\"s_feeConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"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\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinatorV2_5.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"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\"}]", - Bin: "0x60a06040523480156200001157600080fd5b506040516200615d3803806200615d833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615f82620001db60003960008181610566015261384f0152615f826000f3fe60806040526004361061023c5760003560e01c806379ba50971161012f578063b08c8795116100b1578063b08c87951461076d578063b2a7cac51461078d578063bec4c08c146107ad578063caf70c4a146107cd578063cb631797146107ed578063d98e620e1461080d578063da2f26101461082d578063dac83d2914610863578063dc311dd314610883578063e72f6e30146108b4578063ee9d2d38146108d4578063f2fde38b1461090157600080fd5b806379ba50971461060d5780638402595e1461062257806386fe91c7146106425780638da5cb5b1461066257806395b55cfc146106805780639b1c385e146106935780639d40a6fd146106b3578063a21a23e4146106eb578063a4c0ed3614610700578063aa433aff14610720578063aefb212f1461074057600080fd5b8063330987b3116101c3578063330987b314610444578063405b84fa1461046457806340d6bb821461048457806341af6c87146104af5780635d06b4ab146104df57806364d51a2a146104ff578063659827441461051457806366316d8d14610534578063689c4517146105545780636b6feccc146105885780636f64f03f146105cd57806372e9d565146105ed57600080fd5b80620122911461024157806304104edb1461026e578063043bd6ae14610290578063088070f5146102b457806308821d58146103345780630ae095401461035457806315c48b841461037457806318e3dd271461039c5780631b6b6d23146103db5780632949265714610408578063294daa4914610428575b600080fd5b34801561024d57600080fd5b50610256610921565b60405161026593929190615a61565b60405180910390f35b34801561027a57600080fd5b5061028e61028936600461533c565b61099d565b005b34801561029c57600080fd5b506102a660115481565b604051908152602001610265565b3480156102c057600080fd5b50600d546102fc9061ffff81169063ffffffff62010000820481169160ff600160301b82041691600160381b8204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610265565b34801561034057600080fd5b5061028e61034f36600461547c565b610b53565b34801561036057600080fd5b5061028e61036f36600461571e565b610ce7565b34801561038057600080fd5b5061038960c881565b60405161ffff9091168152602001610265565b3480156103a857600080fd5b50600a546103c390600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610265565b3480156103e757600080fd5b506002546103fb906001600160a01b031681565b604051610265919061594f565b34801561041457600080fd5b5061028e610423366004615359565b610dac565b34801561043457600080fd5b5060405160018152602001610265565b34801561045057600080fd5b506103c361045f36600461554e565b610f29565b34801561047057600080fd5b5061028e61047f36600461571e565b61140d565b34801561049057600080fd5b5061049a6101f481565b60405163ffffffff9091168152602001610265565b3480156104bb57600080fd5b506104cf6104ca3660046154d1565b6117f8565b6040519015158152602001610265565b3480156104eb57600080fd5b5061028e6104fa36600461533c565b611999565b34801561050b57600080fd5b50610389606481565b34801561052057600080fd5b5061028e61052f36600461538e565b611a50565b34801561054057600080fd5b5061028e61054f366004615359565b611ab0565b34801561056057600080fd5b506103fb7f000000000000000000000000000000000000000000000000000000000000000081565b34801561059457600080fd5b506012546105b09063ffffffff80821691600160201b90041682565b6040805163ffffffff938416815292909116602083015201610265565b3480156105d957600080fd5b5061028e6105e83660046153c7565b611c78565b3480156105f957600080fd5b506003546103fb906001600160a01b031681565b34801561061957600080fd5b5061028e611d77565b34801561062e57600080fd5b5061028e61063d36600461533c565b611e21565b34801561064e57600080fd5b50600a546103c3906001600160601b031681565b34801561066e57600080fd5b506000546001600160a01b03166103fb565b61028e61068e3660046154d1565b611f33565b34801561069f57600080fd5b506102a66106ae36600461562b565b61207a565b3480156106bf57600080fd5b506007546106d3906001600160401b031681565b6040516001600160401b039091168152602001610265565b3480156106f757600080fd5b506102a661240c565b34801561070c57600080fd5b5061028e61071b3660046153f4565b61265a565b34801561072c57600080fd5b5061028e61073b3660046154d1565b6127fa565b34801561074c57600080fd5b5061076061075b366004615743565b61285a565b60405161026591906159c6565b34801561077957600080fd5b5061028e610788366004615680565b61295b565b34801561079957600080fd5b5061028e6107a83660046154d1565b612ade565b3480156107b957600080fd5b5061028e6107c836600461571e565b612c02565b3480156107d957600080fd5b506102a66107e8366004615498565b612d99565b3480156107f957600080fd5b5061028e61080836600461571e565b612dc9565b34801561081957600080fd5b506102a66108283660046154d1565b6130b6565b34801561083957600080fd5b506103fb6108483660046154d1565b600e602052600090815260409020546001600160a01b031681565b34801561086f57600080fd5b5061028e61087e36600461571e565b6130d7565b34801561088f57600080fd5b506108a361089e3660046154d1565b6131e7565b604051610265959493929190615be3565b3480156108c057600080fd5b5061028e6108cf36600461533c565b6132e2565b3480156108e057600080fd5b506102a66108ef3660046154d1565b60106020526000908152604090205481565b34801561090d57600080fd5b5061028e61091c36600461533c565b6134c3565b600d54600f805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561098b57602002820191906000526020600020905b815481526020019060010190808311610977575b50505050509050925092509250909192565b6109a56134d4565b60135460005b81811015610b2b57826001600160a01b0316601382815481106109d0576109d0615ede565b6000918252602090912001546001600160a01b03161415610b195760136109f8600184615dab565b81548110610a0857610a08615ede565b600091825260209091200154601380546001600160a01b039092169183908110610a3457610a34615ede565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055826013610a6b600185615dab565b81548110610a7b57610a7b615ede565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506013805480610aba57610aba615ec8565b600082815260209020810160001990810180546001600160a01b03191690550190556040517ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af3790610b0c90859061594f565b60405180910390a1505050565b80610b2381615e46565b9150506109ab565b5081604051635428d44960e01b8152600401610b47919061594f565b60405180910390fd5b50565b610b5b6134d4565b604080518082018252600091610b8a919084906002908390839080828437600092019190915250612d99915050565b6000818152600e60205260409020549091506001600160a01b031680610bc657604051631dfd6e1360e21b815260048101839052602401610b47565b6000828152600e6020526040812080546001600160a01b03191690555b600f54811015610c9e5782600f8281548110610c0157610c01615ede565b90600052602060002001541415610c8c57600f805460009190610c2690600190615dab565b81548110610c3657610c36615ede565b9060005260206000200154905080600f8381548110610c5757610c57615ede565b600091825260209091200155600f805480610c7457610c74615ec8565b60019003818190600052602060002001600090559055505b80610c9681615e46565b915050610be3565b50806001600160a01b03167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610cda91815260200190565b60405180910390a2505050565b60008281526005602052604090205482906001600160a01b031680610d1f57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614610d4a5780604051636c51fda960e11b8152600401610b47919061594f565b600d54600160301b900460ff1615610d755760405163769dd35360e11b815260040160405180910390fd5b610d7e846117f8565b15610d9c57604051631685ecdd60e31b815260040160405180910390fd5b610da68484613529565b50505050565b600d54600160301b900460ff1615610dd75760405163769dd35360e11b815260040160405180910390fd5b336000908152600c60205260409020546001600160601b0380831691161015610e1357604051631e9acf1760e31b815260040160405180910390fd5b336000908152600c602052604081208054839290610e3b9084906001600160601b0316615dc2565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610e839190615dc2565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610efd576040519150601f19603f3d011682016040523d82523d6000602084013e610f02565b606091505b5050905080610f245760405163950b247960e01b815260040160405180910390fd5b505050565b600d54600090600160301b900460ff1615610f575760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610f6885856136e4565b90506000846060015163ffffffff166001600160401b03811115610f8e57610f8e615ef4565b604051908082528060200260200182016040528015610fb7578160200160208202803683370190505b50905060005b856060015163ffffffff1681101561103757826040015181604051602001610fef929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c82828151811061101a5761101a615ede565b60209081029190910101528061102f81615e46565b915050610fbd565b5060208083018051600090815260109092526040808320839055905190518291631fe543e360e01b9161106f91908690602401615aeb565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600d805460ff60301b1916600160301b1790559088015160808901519192506000916110d49163ffffffff169084613971565b600d805460ff60301b19169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b0316611114816001615d34565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a0151805161116190600190615dab565b8151811061117157611171615ede565b602091010151600d5460f89190911c60011491506000906111a2908a90600160581b900463ffffffff163a856139bf565b905081156112ab576020808c01516000908152600690915260409020546001600160601b03808316600160601b9092041610156111f257604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c90611229908490600160601b90046001600160601b0316615dc2565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600c90915281208054859450909261128291859116615d56565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550611397565b6020808c01516000908152600690915260409020546001600160601b03808316911610156112ec57604051631e9acf1760e31b815260040160405180910390fd5b6020808c0151600090815260069091526040812080548392906113199084906001600160601b0316615dc2565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600b90915281208054859450909261137291859116615d56565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a6040015184886040516113f4939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600d54600160301b900460ff16156114385760405163769dd35360e11b815260040160405180910390fd5b61144181613a0e565b6114605780604051635428d44960e01b8152600401610b47919061594f565b60008060008061146f866131e7565b945094505093509350336001600160a01b0316826001600160a01b0316146114d25760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b6044820152606401610b47565b6114db866117f8565b156115215760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b6044820152606401610b47565b60006040518060c00160405280611536600190565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b0316815250905060008160405160200161158a91906159ec565b60405160208183030381529060405290506115a488613a78565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b038816906115dd9085906004016159d9565b6000604051808303818588803b1580156115f657600080fd5b505af115801561160a573d6000803e3d6000fd5b50506002546001600160a01b031615801593509150611633905057506001600160601b03861615155b156116fd5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061166a908a908a90600401615996565b602060405180830381600087803b15801561168457600080fd5b505af1158015611698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116bc91906154b4565b6116fd5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610b47565b600d805460ff60301b1916600160301b17905560005b83518110156117a65783818151811061172e5761172e615ede565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b8152600401611761919061594f565b600060405180830381600087803b15801561177b57600080fd5b505af115801561178f573d6000803e3d6000fd5b50505050808061179e90615e46565b915050611713565b50600d805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187906117e69089908b90615963565b60405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561188257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611864575b505050505081525050905060005b81604001515181101561198f5760005b600f5481101561197c576000611945600f83815481106118c2576118c2615ede565b9060005260206000200154856040015185815181106118e3576118e3615ede565b602002602001015188600460008960400151898151811061190657611906615ede565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208d82529092529020546001600160401b0316613cc6565b50600081815260106020526040902054909150156119695750600195945050505050565b508061197481615e46565b9150506118a0565b508061198781615e46565b915050611890565b5060009392505050565b6119a16134d4565b6119aa81613a0e565b156119ca578060405163ac8a27ef60e01b8152600401610b47919061594f565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af0162590611a4590839061594f565b60405180910390a150565b611a586134d4565b6002546001600160a01b031615611a8257604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b600d54600160301b900460ff1615611adb5760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b0316611b045760405163c1f0c0a160e01b815260040160405180910390fd5b336000908152600b60205260409020546001600160601b0380831691161015611b4057604051631e9acf1760e31b815260040160405180910390fd5b336000908152600b602052604081208054839290611b689084906001600160601b0316615dc2565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b0316611bb09190615dc2565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611c059085908590600401615996565b602060405180830381600087803b158015611c1f57600080fd5b505af1158015611c33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5791906154b4565b611c7457604051631e9acf1760e31b815260040160405180910390fd5b5050565b611c806134d4565b604080518082018252600091611caf919084906002908390839080828437600092019190915250612d99915050565b6000818152600e60205260409020549091506001600160a01b031615611ceb57604051634a0b8fa760e01b815260048101829052602401610b47565b6000818152600e6020908152604080832080546001600160a01b0319166001600160a01b038816908117909155600f805460018101825594527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610cda565b6001546001600160a01b03163314611dca5760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610b47565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611e296134d4565b600a544790600160601b90046001600160601b031681811115611e69576040516354ced18160e11b81526004810182905260248101839052604401610b47565b81811015610f24576000611e7d8284615dab565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611ecc576040519150601f19603f3d011682016040523d82523d6000602084013e611ed1565b606091505b5050905080611ef35760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c8583604051611f24929190615963565b60405180910390a15050505050565b600d54600160301b900460ff1615611f5e5760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316611f9357604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611fc28385615d56565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b031661200a9190615d56565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e90282348461205d9190615d1c565b604080519283526020830191909152015b60405180910390a25050565b600d54600090600160301b900460ff16156120a85760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b03166120e357604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b031680612130578260200135336040516379bfd40160e01b8152600401610b47929190615ac0565b600d5461ffff166121476060850160408601615665565b61ffff16108061216a575060c86121646060850160408601615665565b61ffff16115b156121b05761217f6060840160408501615665565b600d5460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610b47565b600d5462010000900463ffffffff166121cf6080850160608601615765565b63ffffffff16111561221f576121eb6080840160608501615765565b600d54604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610b47565b6101f461223260a0850160808601615765565b63ffffffff1611156122785761224e60a0840160808501615765565b6040516311ce1afb60e21b815263ffffffff90911660048201526101f46024820152604401610b47565b6000612285826001615d34565b905060008061229b863533602089013586613cc6565b909250905060006122b76122b260a0890189615c38565b613d3f565b905060006122c482613dbc565b9050836122cf613e2d565b60208a01356122e460808c0160608d01615765565b6122f460a08d0160808e01615765565b338660405160200161230c9796959493929190615b43565b604051602081830303815290604052805190602001206010600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d60400160208101906123839190615665565b8e60600160208101906123969190615765565b8f60800160208101906123a99190615765565b896040516123bc96959493929190615b04565b60405180910390a45050336000908152600460209081526040808320898301358452909152902080546001600160401b0319166001600160401b039490941693909317909255925050505b919050565b600d54600090600160301b900460ff161561243a5760405163769dd35360e11b815260040160405180910390fd5b600033612448600143615dab565b600754604051606093841b6001600160601b03199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b039091169060006124c283615e61565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561250157612501615ef4565b60405190808252806020026020018201604052801561252a578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b03928316178355925160018301805490941691161790915592518051949550909361260b9260028501920190615052565b5061261b91506008905083613ebd565b50817f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d3360405161264c919061594f565b60405180910390a250905090565b600d54600160301b900460ff16156126855760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b031633146126b0576040516344b0e3c360e01b815260040160405180910390fd5b602081146126d157604051638129bbcd60e01b815260040160405180910390fd5b60006126df828401846154d1565b6000818152600560205260409020549091506001600160a01b031661271757604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b03169186919061273e8385615d56565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166127869190615d56565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846127d99190615d1c565b604080519283526020830191909152015b60405180910390a2505050505050565b6128026134d4565b6000818152600560205260409020546001600160a01b031661283757604051630fb532db60e11b815260040160405180910390fd5b600081815260056020526040902054610b509082906001600160a01b0316613529565b606060006128686008613ec9565b905080841061288a57604051631390f2a160e01b815260040160405180910390fd5b60006128968486615d1c565b9050818111806128a4575083155b6128ae57806128b0565b815b905060006128be8683615dab565b6001600160401b038111156128d5576128d5615ef4565b6040519080825280602002602001820160405280156128fe578160200160208202803683370190505b50905060005b81518110156129515761292261291a8883615d1c565b600890613ed3565b82828151811061293457612934615ede565b60209081029190910101528061294981615e46565b915050612904565b5095945050505050565b6129636134d4565b60c861ffff8716111561299d5760405163539c34bb60e11b815261ffff871660048201819052602482015260c86044820152606401610b47565b600082136129c1576040516321ea67b360e11b815260048101839052602401610b47565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600d805465ffffffffffff191688176201000087021768ffffffffffffffffff60301b1916600160381b850263ffffffff60581b191617600160581b83021790558a51601280548d8701519289166001600160401b031990911617600160201b92891692909202919091179081905560118d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600d54600160301b900460ff1615612b095760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316612b3e57604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b03163314612b95576000818152600560205260409081902060010154905163d084e97560e01b8152610b47916001600160a01b03169060040161594f565b6000818152600560205260409081902080546001600160a01b031980821633908117845560019093018054909116905591516001600160a01b039092169183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c93869161206e91859161597c565b60008281526005602052604090205482906001600160a01b031680612c3a57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612c655780604051636c51fda960e11b8152600401610b47919061594f565b600d54600160301b900460ff1615612c905760405163769dd35360e11b815260040160405180910390fd5b60008481526005602052604090206002015460641415612cc3576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b031615612cfa57610da6565b6001600160a01b0383166000818152600460209081526040808320888452825280832080546001600160401b031916600190811790915560058352818420600201805491820181558452919092200180546001600160a01b0319169092179091555184907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e190612d8b90869061594f565b60405180910390a250505050565b600081604051602001612dac91906159b8565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b031680612e0157604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612e2c5780604051636c51fda960e11b8152600401610b47919061594f565b600d54600160301b900460ff1615612e575760405163769dd35360e11b815260040160405180910390fd5b612e60846117f8565b15612e7e57604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316612ecc5783836040516379bfd40160e01b8152600401610b47929190615ac0565b600084815260056020908152604080832060020180548251818502810185019093528083529192909190830182828015612f2f57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612f11575b50505050509050600060018251612f469190615dab565b905060005b825181101561305257856001600160a01b0316838281518110612f7057612f70615ede565b60200260200101516001600160a01b03161415613040576000838381518110612f9b57612f9b615ede565b6020026020010151905080600560008a81526020019081526020016000206002018381548110612fcd57612fcd615ede565b600091825260208083209190910180546001600160a01b0319166001600160a01b03949094169390931790925589815260059091526040902060020180548061301857613018615ec8565b600082815260209020810160001990810180546001600160a01b031916905501905550613052565b8061304a81615e46565b915050612f4b565b506001600160a01b03851660009081526004602090815260408083208984529091529081902080546001600160401b03191690555186907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7906127ea90889061594f565b600f81815481106130c657600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b03168061310f57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461313a5780604051636c51fda960e11b8152600401610b47919061594f565b600d54600160301b900460ff16156131655760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610da6576000848152600560205260409081902060010180546001600160a01b0319166001600160a01b0386161790555184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a190612d8b903390879061597c565b6000818152600560205260408120548190819081906060906001600160a01b031661322557604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b03909416939183918301828280156132c857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116132aa575b505050505090509450945094509450945091939590929450565b6132ea6134d4565b6002546001600160a01b03166133135760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a082319061334490309060040161594f565b60206040518083038186803b15801561335c57600080fd5b505afa158015613370573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061339491906154ea565b600a549091506001600160601b0316818111156133ce576040516354ced18160e11b81526004810182905260248101839052604401610b47565b81811015610f245760006133e28284615dab565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb906134159087908590600401615963565b602060405180830381600087803b15801561342f57600080fd5b505af1158015613443573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061346791906154b4565b61348457604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b43660084826040516134b5929190615963565b60405180910390a150505050565b6134cb6134d4565b610b5081613edf565b6000546001600160a01b031633146135275760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610b47565b565b60008061353584613a78565b60025491935091506001600160a01b03161580159061355c57506001600160601b03821615155b1561360b5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061359c9086906001600160601b03871690600401615963565b602060405180830381600087803b1580156135b657600080fd5b505af11580156135ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ee91906154b4565b61360b57604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613661576040519150601f19603f3d011682016040523d82523d6000602084013e613666565b606091505b50509050806136885760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b604080516060810182526000808252602082018190529181019190915260006137108460000151612d99565b6000818152600e60205260409020549091506001600160a01b03168061374c57604051631dfd6e1360e21b815260048101839052602401610b47565b600082866080015160405160200161376e929190918252602082015260400190565b60408051601f19818403018152918152815160209283012060008181526010909352912054909150806137b457604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d015193516137e3978a979096959101615b8f565b6040516020818303038152906040528051906020012081146138185760405163354a450b60e21b815260040160405180910390fd5b60006138278760000151613f83565b9050806138ff578651604051631d2827a760e31b81526001600160401b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b15801561389957600080fd5b505afa1580156138ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138d191906154ea565b9050806138ff57865160405163175dadad60e01b81526001600160401b039091166004820152602401610b47565b6000886080015182604051602001613921929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006139488a83614065565b604080516060810182529889526020890196909652948701949094525093979650505050505050565b60005a61138881101561398357600080fd5b61138881039050846040820482031161399b57600080fd5b50823b6139a757600080fd5b60008083516020850160008789f190505b9392505050565b600081156139ec576012546139e59086908690600160201b900463ffffffff16866140d0565b9050613a06565b601254613a03908690869063ffffffff1686614172565b90505b949350505050565b6000805b601354811015613a6f57826001600160a01b031660138281548110613a3957613a39615ede565b6000918252602090912001546001600160a01b03161415613a5d5750600192915050565b80613a6781615e46565b915050613a12565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287968796949594860193919290830182828015613b0457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613ae6575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b826040015151811015613be0576004600084604001518381518110613b9057613b90615ede565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120898252909252902080546001600160401b031916905580613bd881615e46565b915050613b69565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613c1860028301826150b7565b5050600085815260066020526040812055613c34600886614298565b50600a8054859190600090613c539084906001600160601b0316615dc2565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613c9b9190615dc2565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b6040805160208082018790526001600160a01b03959095168183015260608101939093526001600160401b03919091166080808401919091528151808403909101815260a08301825280519084012060c083019490945260e0808301859052815180840390910181526101009092019052805191012091565b60408051602081019091526000815281613d685750604080516020810190915260008152611407565b63125fa26760e31b613d7a8385615dea565b6001600160e01b03191614613da257604051632923fee760e11b815260040160405180910390fd5b613daf8260048186615cf2565b8101906139b89190615503565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613df591511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b600046613e39816142a4565b15613eb65760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613e7857600080fd5b505afa158015613e8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613eb091906154ea565b91505090565b4391505090565b60006139b883836142c7565b6000611407825490565b60006139b88383614316565b6001600160a01b038116331415613f325760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b6044820152606401610b47565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613f8f816142a4565b1561405657610100836001600160401b0316613fa9613e2d565b613fb39190615dab565b1180613fcf5750613fc2613e2d565b836001600160401b031610155b15613fdd5750600092915050565b6040516315a03d4160e11b81526001600160401b0384166004820152606490632b407a82906024015b60206040518083038186803b15801561401e57600080fd5b505afa158015614032573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139b891906154ea565b50506001600160401b03164090565b60006140998360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151614340565b600383602001516040516020016140b1929190615ad7565b60408051601f1981840301815291905280516020909101209392505050565b6000806141136000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061455c92505050565b905060005a6141228888615d1c565b61412c9190615dab565b6141369085615d8c565b9050600061414f63ffffffff871664e8d4a51000615d8c565b90508261415c8284615d1c565b6141669190615d1c565b98975050505050505050565b60008061417d614621565b9050600081136141a3576040516321ea67b360e11b815260048101829052602401610b47565b60006141e56000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061455c92505050565b9050600082825a6141f68b8b615d1c565b6142009190615dab565b61420a9088615d8c565b6142149190615d1c565b61422690670de0b6b3a7640000615d8c565b6142309190615d78565b9050600061424963ffffffff881664e8d4a51000615d8c565b9050614261816b033b2e3c9fd0803ce8000000615dab565b8211156142815760405163e80fa38160e01b815260040160405180910390fd5b61428b8183615d1c565b9998505050505050505050565b60006139b883836146ec565b600061a4b18214806142b8575062066eed82145b8061140757505062066eee1490565b600081815260018301602052604081205461430e57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611407565b506000611407565b600082600001828154811061432d5761432d615ede565b9060005260206000200154905092915050565b614349896147df565b6143925760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b6044820152606401610b47565b61439b886147df565b6143df5760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b6044820152606401610b47565b6143e8836147df565b6144345760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610b47565b61443d826147df565b6144895760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610b47565b614495878a88876148a2565b6144dd5760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b6044820152606401610b47565b60006144e98a876149c5565b905060006144fc898b878b868989614a29565b9050600061450d838d8d8a86614b3c565b9050808a1461454e5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610b47565b505050505050505050505050565b600046614568816142a4565b156145a757606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561401e57600080fd5b6145b081614b7c565b15613a6f57600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615f2e604891396040516020016145f69291906158a5565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161400691906159d9565b600d5460035460408051633fabe5a360e21b81529051600093600160381b900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b15801561467f57600080fd5b505afa158015614693573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146b79190615780565b5094509092508491505080156146db57506146d28242615dab565b8463ffffffff16105b15613a065750601154949350505050565b600081815260018301602052604081205480156147d5576000614710600183615dab565b855490915060009061472490600190615dab565b905081811461478957600086600001828154811061474457614744615ede565b906000526020600020015490508087600001848154811061476757614767615ede565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061479a5761479a615ec8565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611407565b6000915050611407565b80516000906401000003d0191161482d5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b6044820152606401610b47565b60208201516401000003d0191161487b5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b6044820152606401610b47565b60208201516401000003d01990800961489b8360005b6020020151614bb6565b1492915050565b60006001600160a01b0382166148e85760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610b47565b6020840151600090600116156148ff57601c614902565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa15801561499d573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b6149cd6150d5565b6149fa600184846040516020016149e69392919061592e565b604051602081830303815290604052614bda565b90505b614a06816147df565b611407578051604080516020810192909252614a2291016149e6565b90506149fd565b614a316150d5565b825186516401000003d0199081900691061415614a905760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610b47565b614a9b878988614c28565b614ae05760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b6044820152606401610b47565b614aeb848685614c28565b614b315760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b6044820152606401610b47565b614166868484614d50565b600060028686868587604051602001614b5a969594939291906158d4565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a821480614b8e57506101a482145b80614b9b575062aa37dc82145b80614ba7575061210582145b8061140757505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614be26150d5565b614beb82614e13565b8152614c00614bfb826000614891565b614e4e565b602082018190526002900660011415612407576020810180516401000003d019039052919050565b600082614c655760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610b47565b83516020850151600090614c7b90600290615e88565b15614c8757601c614c8a565b601b5b9050600070014551231950b75fc4402da1732fc9bebe198387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614cfc573d6000803e3d6000fd5b505050602060405103519050600086604051602001614d1b9190615893565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614d586150d5565b835160208086015185519186015160009384938493614d7993909190614e6e565b919450925090506401000003d019858209600114614dd55760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b6044820152606401610b47565b60405180604001604052806401000003d01980614df457614df4615eb2565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d019811061240757604080516020808201939093528151808203840181529082019091528051910120614e1b565b6000611407826002614e676401000003d0196001615d1c565b901c614f4e565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614eae83838585614fe5565b9098509050614ebf88828e88615009565b9098509050614ed088828c87615009565b90985090506000614ee38d878b85615009565b9098509050614ef488828686614fe5565b9098509050614f0588828e89615009565b9098509050818114614f3a576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614f3e565b8196505b5050505050509450945094915050565b600080614f596150f3565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614f8b615111565b60208160c0846005600019fa925082614fdb5760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b6044820152606401610b47565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b8280548282559060005260206000209081019282156150a7579160200282015b828111156150a757825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190615072565b506150b392915061512f565b5090565b5080546000825590600052602060002090810190610b50919061512f565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b808211156150b35760008155600101615130565b803561240781615f0a565b806040810183101561140757600080fd5b600082601f83011261517157600080fd5b615179615c85565b80838560408601111561518b57600080fd5b60005b60028110156151ad57813584526020938401939091019060010161518e565b509095945050505050565b600082601f8301126151c957600080fd5b81356001600160401b03808211156151e3576151e3615ef4565b604051601f8301601f19908116603f0116810190828211818310171561520b5761520b615ef4565b8160405283815286602085880101111561522457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060c0828403121561525657600080fd5b61525e615cad565b905081356001600160401b03808216821461527857600080fd5b81835260208401356020840152615291604085016152f7565b60408401526152a2606085016152f7565b60608401526152b360808501615144565b608084015260a08401359150808211156152cc57600080fd5b506152d9848285016151b8565b60a08301525092915050565b803561ffff8116811461240757600080fd5b803563ffffffff8116811461240757600080fd5b805169ffffffffffffffffffff8116811461240757600080fd5b80356001600160601b038116811461240757600080fd5b60006020828403121561534e57600080fd5b81356139b881615f0a565b6000806040838503121561536c57600080fd5b823561537781615f0a565b915061538560208401615325565b90509250929050565b600080604083850312156153a157600080fd5b82356153ac81615f0a565b915060208301356153bc81615f0a565b809150509250929050565b600080606083850312156153da57600080fd5b82356153e581615f0a565b9150615385846020850161514f565b6000806000806060858703121561540a57600080fd5b843561541581615f0a565b93506020850135925060408501356001600160401b038082111561543857600080fd5b818701915087601f83011261544c57600080fd5b81358181111561545b57600080fd5b88602082850101111561546d57600080fd5b95989497505060200194505050565b60006040828403121561548e57600080fd5b6139b8838361514f565b6000604082840312156154aa57600080fd5b6139b88383615160565b6000602082840312156154c657600080fd5b81516139b881615f1f565b6000602082840312156154e357600080fd5b5035919050565b6000602082840312156154fc57600080fd5b5051919050565b60006020828403121561551557600080fd5b604051602081018181106001600160401b038211171561553757615537615ef4565b604052823561554581615f1f565b81529392505050565b6000808284036101c081121561556357600080fd5b6101a08082121561557357600080fd5b61557b615ccf565b91506155878686615160565b82526155968660408701615160565b60208301526080850135604083015260a0850135606083015260c085013560808301526155c560e08601615144565b60a08301526101006155d987828801615160565b60c08401526155ec876101408801615160565b60e0840152610180860135908301529092508301356001600160401b0381111561561557600080fd5b61562185828601615244565b9150509250929050565b60006020828403121561563d57600080fd5b81356001600160401b0381111561565357600080fd5b820160c081850312156139b857600080fd5b60006020828403121561567757600080fd5b6139b8826152e5565b60008060008060008086880360e081121561569a57600080fd5b6156a3886152e5565b96506156b1602089016152f7565b95506156bf604089016152f7565b94506156cd606089016152f7565b9350608088013592506040609f19820112156156e857600080fd5b506156f1615c85565b6156fd60a089016152f7565b815261570b60c089016152f7565b6020820152809150509295509295509295565b6000806040838503121561573157600080fd5b8235915060208301356153bc81615f0a565b6000806040838503121561575657600080fd5b50508035926020909101359150565b60006020828403121561577757600080fd5b6139b8826152f7565b600080600080600060a0868803121561579857600080fd5b6157a18661530b565b94506020860151935060408601519250606086015191506157c46080870161530b565b90509295509295909350565b600081518084526020808501945080840160005b838110156158095781516001600160a01b0316875295820195908201906001016157e4565b509495945050505050565b8060005b6002811015610da6578151845260209384019390910190600101615818565b600081518084526020808501945080840160005b838110156158095781518752958201959082019060010161584b565b6000815180845261587f816020860160208601615e1a565b601f01601f19169290920160200192915050565b61589d8183615814565b604001919050565b600083516158b7818460208801615e1a565b8351908301906158cb818360208801615e1a565b01949350505050565b8681526158e46020820187615814565b6158f16060820186615814565b6158fe60a0820185615814565b61590b60e0820184615814565b60609190911b6001600160601b0319166101208201526101340195945050505050565b83815261593e6020820184615814565b606081019190915260800192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b604081016114078284615814565b6020815260006139b86020830184615837565b6020815260006139b86020830184615867565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c06080840152615a3160e08401826157d0565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615ab257845183529383019391830191600101615a96565b509098975050505050505050565b9182526001600160a01b0316602082015260400190565b828152606081016139b86020830184615814565b828152604060208201526000613a066040830184615837565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a083015261416660c0830184615867565b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c0820181905260009061428b90830184615867565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c0820181905260009061428b90830184615867565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a060808201819052600090615c2d908301846157d0565b979650505050505050565b6000808335601e19843603018112615c4f57600080fd5b8301803591506001600160401b03821115615c6957600080fd5b602001915036819003821315615c7e57600080fd5b9250929050565b604080519081016001600160401b0381118282101715615ca757615ca7615ef4565b60405290565b60405160c081016001600160401b0381118282101715615ca757615ca7615ef4565b60405161012081016001600160401b0381118282101715615ca757615ca7615ef4565b60008085851115615d0257600080fd5b83861115615d0f57600080fd5b5050820193919092039150565b60008219821115615d2f57615d2f615e9c565b500190565b60006001600160401b038083168185168083038211156158cb576158cb615e9c565b60006001600160601b038281168482168083038211156158cb576158cb615e9c565b600082615d8757615d87615eb2565b500490565b6000816000190483118215151615615da657615da6615e9c565b500290565b600082821015615dbd57615dbd615e9c565b500390565b60006001600160601b0383811690831681811015615de257615de2615e9c565b039392505050565b6001600160e01b03198135818116916004851015615e125780818660040360031b1b83161692505b505092915050565b60005b83811015615e35578181015183820152602001615e1d565b83811115610da65750506000910152565b6000600019821415615e5a57615e5a615e9c565b5060010190565b60006001600160401b0380831681811415615e7e57615e7e615e9c565b6001019392505050565b600082615e9757615e97615eb2565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610b5057600080fd5b8015158114610b5057600080fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", + 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\":[{\"internalType\":\"uint256\",\"name\":\"have\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"want\",\"type\":\"uint256\"}],\"name\":\"InsufficientGasForConsumer\",\"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\":\"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\":[],\"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\":\"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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2_5.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"coordinatorAddress\",\"type\":\"address\"}],\"name\":\"CoordinatorDeregistered\",\"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\":\"ProvingKeyDeregistered\",\"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\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"deregisterMigratableCoordinator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"publicProvingKey\",\"type\":\"uint256[2]\"}],\"name\":\"deregisterProvingKey\",\"outputs\":[],\"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\":\"structVRFCoordinatorV2_5.RequestCommitment\",\"name\":\"rc\",\"type\":\"tuple\"}],\"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\":\"\",\"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\":\"owner\",\"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\":\"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\"}],\"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\":[],\"name\":\"s_feeConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"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\":\"\",\"type\":\"bool\"}],\"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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinatorV2_5.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"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: "0x60a06040523480156200001157600080fd5b506040516200606038038062006060833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615e85620001db6000396000818161056601526137d10152615e856000f3fe60806040526004361061023c5760003560e01c80637bce14d11161012f578063b08c8795116100b1578063b08c87951461076d578063b2a7cac51461078d578063bec4c08c146107ad578063caf70c4a146107cd578063cb631797146107ed578063d98e620e1461080d578063da2f26101461082d578063dac83d291461085d578063dc311dd31461087d578063e72f6e30146108ae578063ee9d2d38146108ce578063f2fde38b146108fb57600080fd5b80637bce14d1146106025780638402595e1461062257806386fe91c7146106425780638da5cb5b1461066257806395b55cfc146106805780639b1c385e146106935780639d40a6fd146106b3578063a21a23e4146106eb578063a4c0ed3614610700578063aa433aff14610720578063aefb212f1461074057600080fd5b8063330987b3116101c3578063330987b314610444578063405b84fa1461046457806340d6bb821461048457806341af6c87146104af57806351cff8d9146104df5780635d06b4ab146104ff57806364d51a2a1461051f5780636598274414610534578063689c4517146105545780636b6feccc1461058857806372e9d565146105cd57806379ba5097146105ed57600080fd5b80620122911461024157806304104edb1461026e578063043bd6ae14610290578063088070f5146102b457806308821d58146103345780630ae095401461035457806315c48b841461037457806318e3dd271461039c5780631b6b6d23146103db578063294daa49146104085780632f622e6b14610424575b600080fd5b34801561024d57600080fd5b5061025661091b565b60405161026593929190615964565b60405180910390f35b34801561027a57600080fd5b5061028e610289366004615295565b610997565b005b34801561029c57600080fd5b506102a660105481565b604051908152602001610265565b3480156102c057600080fd5b50600c546102fc9061ffff81169063ffffffff62010000820481169160ff600160301b82041691600160381b8204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610265565b34801561034057600080fd5b5061028e61034f366004615373565b610b4d565b34801561036057600080fd5b5061028e61036f366004615621565b610cc4565b34801561038057600080fd5b5061038960c881565b60405161ffff9091168152602001610265565b3480156103a857600080fd5b50600a546103c390600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610265565b3480156103e757600080fd5b506002546103fb906001600160a01b031681565b6040516102659190615852565b34801561041457600080fd5b5060405160018152602001610265565b34801561043057600080fd5b5061028e61043f366004615295565b610d89565b34801561045057600080fd5b506103c361045f366004615451565b610efd565b34801561047057600080fd5b5061028e61047f366004615621565b6113bf565b34801561049057600080fd5b5061049a6101f481565b60405163ffffffff9091168152602001610265565b3480156104bb57600080fd5b506104cf6104ca3660046153d4565b6117aa565b6040519015158152602001610265565b3480156104eb57600080fd5b5061028e6104fa366004615295565b61194b565b34801561050b57600080fd5b5061028e61051a366004615295565b611afc565b34801561052b57600080fd5b50610389606481565b34801561054057600080fd5b5061028e61054f3660046152b2565b611bb3565b34801561056057600080fd5b506103fb7f000000000000000000000000000000000000000000000000000000000000000081565b34801561059457600080fd5b506011546105b09063ffffffff80821691600160201b90041682565b6040805163ffffffff938416815292909116602083015201610265565b3480156105d957600080fd5b506003546103fb906001600160a01b031681565b3480156105f957600080fd5b5061028e611c13565b34801561060e57600080fd5b5061028e61061d366004615373565b611cbd565b34801561062e57600080fd5b5061028e61063d366004615295565b611daa565b34801561064e57600080fd5b50600a546103c3906001600160601b031681565b34801561066e57600080fd5b506000546001600160a01b03166103fb565b61028e61068e3660046153d4565b611ebc565b34801561069f57600080fd5b506102a66106ae36600461552e565b612003565b3480156106bf57600080fd5b506007546106d3906001600160401b031681565b6040516001600160401b039091168152602001610265565b3480156106f757600080fd5b506102a6612395565b34801561070c57600080fd5b5061028e61071b3660046152eb565b6125e3565b34801561072c57600080fd5b5061028e61073b3660046153d4565b612783565b34801561074c57600080fd5b5061076061075b366004615646565b6127e3565b60405161026591906158c9565b34801561077957600080fd5b5061028e610788366004615583565b6128e4565b34801561079957600080fd5b5061028e6107a83660046153d4565b612a67565b3480156107b957600080fd5b5061028e6107c8366004615621565b612b8b565b3480156107d957600080fd5b506102a66107e836600461539b565b612d22565b3480156107f957600080fd5b5061028e610808366004615621565b612d52565b34801561081957600080fd5b506102a66108283660046153d4565b61303f565b34801561083957600080fd5b506104cf6108483660046153d4565b600d6020526000908152604090205460ff1681565b34801561086957600080fd5b5061028e610878366004615621565b613060565b34801561088957600080fd5b5061089d6108983660046153d4565b613170565b604051610265959493929190615ae6565b3480156108ba57600080fd5b5061028e6108c9366004615295565b61326b565b3480156108da57600080fd5b506102a66108e93660046153d4565b600f6020526000908152604090205481565b34801561090757600080fd5b5061028e610916366004615295565b61344c565b600c54600e805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561098557602002820191906000526020600020905b815481526020019060010190808311610971575b50505050509050925092509250909192565b61099f61345d565b60125460005b81811015610b2557826001600160a01b0316601282815481106109ca576109ca615de1565b6000918252602090912001546001600160a01b03161415610b135760126109f2600184615cae565b81548110610a0257610a02615de1565b600091825260209091200154601280546001600160a01b039092169183908110610a2e57610a2e615de1565b600091825260209091200180546001600160a01b0319166001600160a01b0392909216919091179055826012610a65600185615cae565b81548110610a7557610a75615de1565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506012805480610ab457610ab4615dcb565b600082815260209020810160001990810180546001600160a01b03191690550190556040517ff80a1a97fd42251f3c33cda98635e7399253033a6774fe37cd3f650b5282af3790610b06908590615852565b60405180910390a1505050565b80610b1d81615d49565b9150506109a5565b5081604051635428d44960e01b8152600401610b419190615852565b60405180910390fd5b50565b610b5561345d565b604080518082018252600091610b84919084906002908390839080828437600092019190915250612d22915050565b6000818152600d602052604090205490915060ff16610bb957604051631dfd6e1360e21b815260048101829052602401610b41565b6000818152600d60205260408120805460ff191690555b600e54811015610c8b5781600e8281548110610bee57610bee615de1565b90600052602060002001541415610c7957600e805460009190610c1390600190615cae565b81548110610c2357610c23615de1565b9060005260206000200154905080600e8381548110610c4457610c44615de1565b600091825260209091200155600e805480610c6157610c61615dcb565b60019003818190600052602060002001600090559055505b80610c8381615d49565b915050610bd0565b506040518181527fbd242ec01625c15ecbc02cf700ac8b02c86f7346fa91a08e186810221ae509d0906020015b60405180910390a15050565b60008281526005602052604090205482906001600160a01b031680610cfc57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614610d275780604051636c51fda960e11b8152600401610b419190615852565b600c54600160301b900460ff1615610d525760405163769dd35360e11b815260040160405180910390fd5b610d5b846117aa565b15610d7957604051631685ecdd60e31b815260040160405180910390fd5b610d8384846134b2565b50505050565b600c54600160301b900460ff1615610db45760405163769dd35360e11b815260040160405180910390fd5b610dbc61345d565b600b54600160601b90046001600160601b0316610dec57604051631e9acf1760e31b815260040160405180910390fd5b600b8054600160601b90046001600160601b0316908190600c610e0f8380615cc5565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610e579190615cc5565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610ed1576040519150601f19603f3d011682016040523d82523d6000602084013e610ed6565b606091505b5050905080610ef85760405163950b247960e01b815260040160405180910390fd5b505050565b600c54600090600160301b900460ff1615610f2b5760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610f3c858561366d565b90506000846060015163ffffffff166001600160401b03811115610f6257610f62615df7565b604051908082528060200260200182016040528015610f8b578160200160208202803683370190505b50905060005b856060015163ffffffff1681101561100b57826040015181604051602001610fc3929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c828281518110610fee57610fee615de1565b60209081029190910101528061100381615d49565b915050610f91565b50602080830180516000908152600f9092526040808320839055905190518291631fe543e360e01b91611043919086906024016159ee565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600c805460ff60301b1916600160301b1790559088015160808901519192506000916110a89163ffffffff1690846138f2565b600c805460ff60301b19169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b03166110e8816001615c37565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a0151805161113590600190615cae565b8151811061114557611145615de1565b602091010151600c5460f89190911c6001149150600090611176908a90600160581b900463ffffffff163a85613940565b9050811561126e576020808c01516000908152600690915260409020546001600160601b03808316600160601b9092041610156111c657604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c906111fd908490600160601b90046001600160601b0316615cc5565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600b600c8282829054906101000a90046001600160601b03166112459190615c59565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550611349565b6020808c01516000908152600690915260409020546001600160601b03808316911610156112af57604051631e9acf1760e31b815260040160405180910390fd5b6020808c0151600090815260069091526040812080548392906112dc9084906001600160601b0316615cc5565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600b60008282829054906101000a90046001600160601b03166113249190615c59565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a6040015184886040516113a6939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600c54600160301b900460ff16156113ea5760405163769dd35360e11b815260040160405180910390fd5b6113f38161398f565b6114125780604051635428d44960e01b8152600401610b419190615852565b60008060008061142186613170565b945094505093509350336001600160a01b0316826001600160a01b0316146114845760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b6044820152606401610b41565b61148d866117aa565b156114d35760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b6044820152606401610b41565b60006040518060c001604052806114e8600190565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b0316815250905060008160405160200161153c91906158ef565b6040516020818303038152906040529050611556886139f9565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b0388169061158f9085906004016158dc565b6000604051808303818588803b1580156115a857600080fd5b505af11580156115bc573d6000803e3d6000fd5b50506002546001600160a01b0316158015935091506115e5905057506001600160601b03861615155b156116af5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061161c908a908a90600401615899565b602060405180830381600087803b15801561163657600080fd5b505af115801561164a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166e91906153b7565b6116af5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610b41565b600c805460ff60301b1916600160301b17905560005b8351811015611758578381815181106116e0576116e0615de1565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b81526004016117139190615852565b600060405180830381600087803b15801561172d57600080fd5b505af1158015611741573d6000803e3d6000fd5b50505050808061175090615d49565b9150506116c5565b50600c805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187906117989089908b90615866565b60405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561183457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611816575b505050505081525050905060005b8160400151518110156119415760005b600e5481101561192e5760006118f7600e838154811061187457611874615de1565b90600052602060002001548560400151858151811061189557611895615de1565b60200260200101518860046000896040015189815181106118b8576118b8615de1565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208d82529092529020546001600160401b0316613c47565b506000818152600f60205260409020549091501561191b5750600195945050505050565b508061192681615d49565b915050611852565b508061193981615d49565b915050611842565b5060009392505050565b600c54600160301b900460ff16156119765760405163769dd35360e11b815260040160405180910390fd5b61197e61345d565b6002546001600160a01b03166119a75760405163c1f0c0a160e01b815260040160405180910390fd5b600b546001600160601b03166119d057604051631e9acf1760e31b815260040160405180910390fd5b600b80546001600160601b031690819060006119ec8380615cc5565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b0316611a349190615cc5565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611a899085908590600401615899565b602060405180830381600087803b158015611aa357600080fd5b505af1158015611ab7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611adb91906153b7565b611af857604051631e9acf1760e31b815260040160405180910390fd5b5050565b611b0461345d565b611b0d8161398f565b15611b2d578060405163ac8a27ef60e01b8152600401610b419190615852565b601280546001810182556000919091527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec34440180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af0162590611ba8908390615852565b60405180910390a150565b611bbb61345d565b6002546001600160a01b031615611be557604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b6001546001600160a01b03163314611c665760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b6044820152606401610b41565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b611cc561345d565b604080518082018252600091611cf4919084906002908390839080828437600092019190915250612d22915050565b6000818152600d602052604090205490915060ff1615611d2a57604051634a0b8fa760e01b815260048101829052602401610b41565b6000818152600d6020526040808220805460ff19166001908117909155600e805491820181559092527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd909101829055517fc9583fd3afa3d7f16eb0b88d0268e7d05c09bafa4b21e092cbd1320e1bc8089d90610cb89083815260200190565b611db261345d565b600a544790600160601b90046001600160601b031681811115611df2576040516354ced18160e11b81526004810182905260248101839052604401610b41565b81811015610ef8576000611e068284615cae565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611e55576040519150601f19603f3d011682016040523d82523d6000602084013e611e5a565b606091505b5050905080611e7c5760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c8583604051611ead929190615866565b60405180910390a15050505050565b600c54600160301b900460ff1615611ee75760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316611f1c57604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611f4b8385615c59565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611f939190615c59565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e902823484611fe69190615c1f565b604080519283526020830191909152015b60405180910390a25050565b600c54600090600160301b900460ff16156120315760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b031661206c57604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b0316806120b9578260200135336040516379bfd40160e01b8152600401610b419291906159c3565b600c5461ffff166120d06060850160408601615568565b61ffff1610806120f3575060c86120ed6060850160408601615568565b61ffff16115b15612139576121086060840160408501615568565b600c5460405163539c34bb60e11b815261ffff92831660048201529116602482015260c86044820152606401610b41565b600c5462010000900463ffffffff166121586080850160608601615668565b63ffffffff1611156121a8576121746080840160608501615668565b600c54604051637aebf00f60e11b815263ffffffff9283166004820152620100009091049091166024820152604401610b41565b6101f46121bb60a0850160808601615668565b63ffffffff161115612201576121d760a0840160808501615668565b6040516311ce1afb60e21b815263ffffffff90911660048201526101f46024820152604401610b41565b600061220e826001615c37565b9050600080612224863533602089013586613c47565b9092509050600061224061223b60a0890189615b3b565b613cc0565b9050600061224d82613d3d565b905083612258613dae565b60208a013561226d60808c0160608d01615668565b61227d60a08d0160808e01615668565b33866040516020016122959796959493929190615a46565b60405160208183030381529060405280519060200120600f600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d604001602081019061230c9190615568565b8e606001602081019061231f9190615668565b8f60800160208101906123329190615668565b8960405161234596959493929190615a07565b60405180910390a45050336000908152600460209081526040808320898301358452909152902080546001600160401b0319166001600160401b039490941693909317909255925050505b919050565b600c54600090600160301b900460ff16156123c35760405163769dd35360e11b815260040160405180910390fd5b6000336123d1600143615cae565b600754604051606093841b6001600160601b03199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b0390911690600061244b83615d64565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561248a5761248a615df7565b6040519080825280602002602001820160405280156124b3578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b0392831617835592516001830180549094169116179091559251805194955090936125949260028501920190614fd3565b506125a491506008905083613e3e565b50817f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d336040516125d59190615852565b60405180910390a250905090565b600c54600160301b900460ff161561260e5760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b03163314612639576040516344b0e3c360e01b815260040160405180910390fd5b6020811461265a57604051638129bbcd60e01b815260040160405180910390fd5b6000612668828401846153d4565b6000818152600560205260409020549091506001600160a01b03166126a057604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b0316918691906126c78385615c59565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b031661270f9190615c59565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846127629190615c1f565b604080519283526020830191909152015b60405180910390a2505050505050565b61278b61345d565b6000818152600560205260409020546001600160a01b03166127c057604051630fb532db60e11b815260040160405180910390fd5b600081815260056020526040902054610b4a9082906001600160a01b03166134b2565b606060006127f16008613e4a565b905080841061281357604051631390f2a160e01b815260040160405180910390fd5b600061281f8486615c1f565b90508181118061282d575083155b6128375780612839565b815b905060006128478683615cae565b6001600160401b0381111561285e5761285e615df7565b604051908082528060200260200182016040528015612887578160200160208202803683370190505b50905060005b81518110156128da576128ab6128a38883615c1f565b600890613e54565b8282815181106128bd576128bd615de1565b6020908102919091010152806128d281615d49565b91505061288d565b5095945050505050565b6128ec61345d565b60c861ffff871611156129265760405163539c34bb60e11b815261ffff871660048201819052602482015260c86044820152606401610b41565b6000821361294a576040516321ea67b360e11b815260048101839052602401610b41565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600c805465ffffffffffff191688176201000087021768ffffffffffffffffff60301b1916600160381b850263ffffffff60581b191617600160581b83021790558a51601180548d8701519289166001600160401b031990911617600160201b92891692909202919091179081905560108d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600c54600160301b900460ff1615612a925760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316612ac757604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b03163314612b1e576000818152600560205260409081902060010154905163d084e97560e01b8152610b41916001600160a01b031690600401615852565b6000818152600560205260409081902080546001600160a01b031980821633908117845560019093018054909116905591516001600160a01b039092169183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691611ff791859161587f565b60008281526005602052604090205482906001600160a01b031680612bc357604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612bee5780604051636c51fda960e11b8152600401610b419190615852565b600c54600160301b900460ff1615612c195760405163769dd35360e11b815260040160405180910390fd5b60008481526005602052604090206002015460641415612c4c576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b031615612c8357610d83565b6001600160a01b0383166000818152600460209081526040808320888452825280832080546001600160401b031916600190811790915560058352818420600201805491820181558452919092200180546001600160a01b0319169092179091555184907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e190612d14908690615852565b60405180910390a250505050565b600081604051602001612d3591906158bb565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b031680612d8a57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612db55780604051636c51fda960e11b8152600401610b419190615852565b600c54600160301b900460ff1615612de05760405163769dd35360e11b815260040160405180910390fd5b612de9846117aa565b15612e0757604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316612e555783836040516379bfd40160e01b8152600401610b419291906159c3565b600084815260056020908152604080832060020180548251818502810185019093528083529192909190830182828015612eb857602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612e9a575b50505050509050600060018251612ecf9190615cae565b905060005b8251811015612fdb57856001600160a01b0316838281518110612ef957612ef9615de1565b60200260200101516001600160a01b03161415612fc9576000838381518110612f2457612f24615de1565b6020026020010151905080600560008a81526020019081526020016000206002018381548110612f5657612f56615de1565b600091825260208083209190910180546001600160a01b0319166001600160a01b039490941693909317909255898152600590915260409020600201805480612fa157612fa1615dcb565b600082815260209020810160001990810180546001600160a01b031916905501905550612fdb565b80612fd381615d49565b915050612ed4565b506001600160a01b03851660009081526004602090815260408083208984529091529081902080546001600160401b03191690555186907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a790612773908890615852565b600e818154811061304f57600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b03168061309857604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146130c35780604051636c51fda960e11b8152600401610b419190615852565b600c54600160301b900460ff16156130ee5760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610d83576000848152600560205260409081902060010180546001600160a01b0319166001600160a01b0386161790555184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a190612d14903390879061587f565b6000818152600560205260408120548190819081906060906001600160a01b03166131ae57604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b039094169391839183018282801561325157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613233575b505050505090509450945094509450945091939590929450565b61327361345d565b6002546001600160a01b031661329c5760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a08231906132cd903090600401615852565b60206040518083038186803b1580156132e557600080fd5b505afa1580156132f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061331d91906153ed565b600a549091506001600160601b031681811115613357576040516354ced18160e11b81526004810182905260248101839052604401610b41565b81811015610ef857600061336b8284615cae565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb9061339e9087908590600401615866565b602060405180830381600087803b1580156133b857600080fd5b505af11580156133cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133f091906153b7565b61340d57604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600848260405161343e929190615866565b60405180910390a150505050565b61345461345d565b610b4a81613e60565b6000546001600160a01b031633146134b05760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b6044820152606401610b41565b565b6000806134be846139f9565b60025491935091506001600160a01b0316158015906134e557506001600160601b03821615155b156135945760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906135259086906001600160601b03871690600401615866565b602060405180830381600087803b15801561353f57600080fd5b505af1158015613553573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061357791906153b7565b61359457604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d80600081146135ea576040519150601f19603f3d011682016040523d82523d6000602084013e6135ef565b606091505b50509050806136115760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b604080516060810182526000808252602082018190529181019190915260006136998460000151612d22565b6000818152600d602052604090205490915060ff166136ce57604051631dfd6e1360e21b815260048101829052602401610b41565b60008185608001516040516020016136f0929190918252602082015260400190565b60408051601f1981840301815291815281516020928301206000818152600f9093529120549091508061373657604051631b44092560e11b815260040160405180910390fd5b845160208087015160408089015160608a015160808b015160a08c01519351613765978a979096959101615a92565b60405160208183030381529060405280519060200120811461379a5760405163354a450b60e21b815260040160405180910390fd5b60006137a98660000151613f04565b905080613881578551604051631d2827a760e31b81526001600160401b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e9413d389060240160206040518083038186803b15801561381b57600080fd5b505afa15801561382f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061385391906153ed565b90508061388157855160405163175dadad60e01b81526001600160401b039091166004820152602401610b41565b60008760800151826040516020016138a3929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006138ca8983613fe6565b6040805160608101825297885260208801969096529486019490945250929695505050505050565b60005a61138881101561390457600080fd5b61138881039050846040820482031161391c57600080fd5b50823b61392857600080fd5b60008083516020850160008789f190505b9392505050565b6000811561396d576011546139669086908690600160201b900463ffffffff1686614051565b9050613987565b601154613984908690869063ffffffff16866140f3565b90505b949350505050565b6000805b6012548110156139f057826001600160a01b0316601282815481106139ba576139ba615de1565b6000918252602090912001546001600160a01b031614156139de5750600192915050565b806139e881615d49565b915050613993565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287968796949594860193919290830182828015613a8557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613a67575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b826040015151811015613b61576004600084604001518381518110613b1157613b11615de1565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120898252909252902080546001600160401b031916905580613b5981615d49565b915050613aea565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613b996002830182615038565b5050600085815260066020526040812055613bb5600886614219565b50600a8054859190600090613bd49084906001600160601b0316615cc5565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613c1c9190615cc5565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b6040805160208082018790526001600160a01b03959095168183015260608101939093526001600160401b03919091166080808401919091528151808403909101815260a08301825280519084012060c083019490945260e0808301859052815180840390910181526101009092019052805191012091565b60408051602081019091526000815281613ce957506040805160208101909152600081526113b9565b63125fa26760e31b613cfb8385615ced565b6001600160e01b03191614613d2357604051632923fee760e11b815260040160405180910390fd5b613d308260048186615bf5565b8101906139399190615406565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613d7691511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b600046613dba81614225565b15613e375760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613df957600080fd5b505afa158015613e0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e3191906153ed565b91505090565b4391505090565b60006139398383614248565b60006113b9825490565b60006139398383614297565b6001600160a01b038116331415613eb35760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b6044820152606401610b41565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613f1081614225565b15613fd757610100836001600160401b0316613f2a613dae565b613f349190615cae565b1180613f505750613f43613dae565b836001600160401b031610155b15613f5e5750600092915050565b6040516315a03d4160e11b81526001600160401b0384166004820152606490632b407a82906024015b60206040518083038186803b158015613f9f57600080fd5b505afa158015613fb3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061393991906153ed565b50506001600160401b03164090565b600061401a8360000151846020015185604001518660600151868860a001518960c001518a60e001518b61010001516142c1565b600383602001516040516020016140329291906159da565b60408051601f1981840301815291905280516020909101209392505050565b6000806140946000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506144dd92505050565b905060005a6140a38888615c1f565b6140ad9190615cae565b6140b79085615c8f565b905060006140d063ffffffff871664e8d4a51000615c8f565b9050826140dd8284615c1f565b6140e79190615c1f565b98975050505050505050565b6000806140fe6145a2565b905060008113614124576040516321ea67b360e11b815260048101829052602401610b41565b60006141666000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506144dd92505050565b9050600082825a6141778b8b615c1f565b6141819190615cae565b61418b9088615c8f565b6141959190615c1f565b6141a790670de0b6b3a7640000615c8f565b6141b19190615c7b565b905060006141ca63ffffffff881664e8d4a51000615c8f565b90506141e2816b033b2e3c9fd0803ce8000000615cae565b8211156142025760405163e80fa38160e01b815260040160405180910390fd5b61420c8183615c1f565b9998505050505050505050565b6000613939838361466d565b600061a4b1821480614239575062066eed82145b806113b957505062066eee1490565b600081815260018301602052604081205461428f575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556113b9565b5060006113b9565b60008260000182815481106142ae576142ae615de1565b9060005260206000200154905092915050565b6142ca89614760565b6143135760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b6044820152606401610b41565b61431c88614760565b6143605760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b6044820152606401610b41565b61436983614760565b6143b55760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610b41565b6143be82614760565b61440a5760405162461bcd60e51b815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610b41565b614416878a8887614823565b61445e5760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b6044820152606401610b41565b600061446a8a87614946565b9050600061447d898b878b8689896149aa565b9050600061448e838d8d8a86614abd565b9050808a146144cf5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b6044820152606401610b41565b505050505050505050505050565b6000466144e981614225565b1561452857606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b158015613f9f57600080fd5b61453181614afd565b156139f057600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615e31604891396040516020016145779291906157a8565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613f8791906158dc565b600c5460035460408051633fabe5a360e21b81529051600093600160381b900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b15801561460057600080fd5b505afa158015614614573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146389190615683565b50945090925084915050801561465c57506146538242615cae565b8463ffffffff16105b156139875750601054949350505050565b60008181526001830160205260408120548015614756576000614691600183615cae565b85549091506000906146a590600190615cae565b905081811461470a5760008660000182815481106146c5576146c5615de1565b90600052602060002001549050808760000184815481106146e8576146e8615de1565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061471b5761471b615dcb565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506113b9565b60009150506113b9565b80516000906401000003d019116147ae5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b6044820152606401610b41565b60208201516401000003d019116147fc5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b6044820152606401610b41565b60208201516401000003d01990800961481c8360005b6020020151614b37565b1492915050565b60006001600160a01b0382166148695760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b6044820152606401610b41565b60208401516000906001161561488057601c614883565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa15801561491e573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b61494e615056565b61497b6001848460405160200161496793929190615831565b604051602081830303815290604052614b5b565b90505b61498781614760565b6113b95780516040805160208101929092526149a39101614967565b905061497e565b6149b2615056565b825186516401000003d0199081900691061415614a115760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610b41565b614a1c878988614ba9565b614a615760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b6044820152606401610b41565b614a6c848685614ba9565b614ab25760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b6044820152606401610b41565b6140e7868484614cd1565b600060028686868587604051602001614adb969594939291906157d7565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a821480614b0f57506101a482145b80614b1c575062aa37dc82145b80614b28575061210582145b806113b957505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614b63615056565b614b6c82614d94565b8152614b81614b7c826000614812565b614dcf565b602082018190526002900660011415612390576020810180516401000003d019039052919050565b600082614be65760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b6044820152606401610b41565b83516020850151600090614bfc90600290615d8b565b15614c0857601c614c0b565b601b5b9050600070014551231950b75fc4402da1732fc9bebe198387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614c7d573d6000803e3d6000fd5b505050602060405103519050600086604051602001614c9c9190615796565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614cd9615056565b835160208086015185519186015160009384938493614cfa93909190614def565b919450925090506401000003d019858209600114614d565760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b6044820152606401610b41565b60405180604001604052806401000003d01980614d7557614d75615db5565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d019811061239057604080516020808201939093528151808203840181529082019091528051910120614d9c565b60006113b9826002614de86401000003d0196001615c1f565b901c614ecf565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614e2f83838585614f66565b9098509050614e4088828e88614f8a565b9098509050614e5188828c87614f8a565b90985090506000614e648d878b85614f8a565b9098509050614e7588828686614f66565b9098509050614e8688828e89614f8a565b9098509050818114614ebb576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614ebf565b8196505b5050505050509450945094915050565b600080614eda615074565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614f0c615092565b60208160c0846005600019fa925082614f5c5760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b6044820152606401610b41565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215615028579160200282015b8281111561502857825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614ff3565b506150349291506150b0565b5090565b5080546000825590600052602060002090810190610b4a91906150b0565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b8082111561503457600081556001016150b1565b803561239081615e0d565b600082601f8301126150e157600080fd5b6150e9615b88565b8083856040860111156150fb57600080fd5b60005b600281101561511d5781358452602093840193909101906001016150fe565b509095945050505050565b600082601f83011261513957600080fd5b81356001600160401b038082111561515357615153615df7565b604051601f8301601f19908116603f0116810190828211818310171561517b5761517b615df7565b8160405283815286602085880101111561519457600080fd5b836020870160208301376000602085830101528094505050505092915050565b600060c082840312156151c657600080fd5b6151ce615bb0565b905081356001600160401b0380821682146151e857600080fd5b8183526020840135602084015261520160408501615267565b604084015261521260608501615267565b6060840152615223608085016150c5565b608084015260a084013591508082111561523c57600080fd5b5061524984828501615128565b60a08301525092915050565b803561ffff8116811461239057600080fd5b803563ffffffff8116811461239057600080fd5b805169ffffffffffffffffffff8116811461239057600080fd5b6000602082840312156152a757600080fd5b813561393981615e0d565b600080604083850312156152c557600080fd5b82356152d081615e0d565b915060208301356152e081615e0d565b809150509250929050565b6000806000806060858703121561530157600080fd5b843561530c81615e0d565b93506020850135925060408501356001600160401b038082111561532f57600080fd5b818701915087601f83011261534357600080fd5b81358181111561535257600080fd5b88602082850101111561536457600080fd5b95989497505060200194505050565b60006040828403121561538557600080fd5b8260408301111561539557600080fd5b50919050565b6000604082840312156153ad57600080fd5b61393983836150d0565b6000602082840312156153c957600080fd5b815161393981615e22565b6000602082840312156153e657600080fd5b5035919050565b6000602082840312156153ff57600080fd5b5051919050565b60006020828403121561541857600080fd5b604051602081018181106001600160401b038211171561543a5761543a615df7565b604052823561544881615e22565b81529392505050565b6000808284036101c081121561546657600080fd5b6101a08082121561547657600080fd5b61547e615bd2565b915061548a86866150d0565b825261549986604087016150d0565b60208301526080850135604083015260a0850135606083015260c085013560808301526154c860e086016150c5565b60a08301526101006154dc878288016150d0565b60c08401526154ef8761014088016150d0565b60e0840152610180860135908301529092508301356001600160401b0381111561551857600080fd5b615524858286016151b4565b9150509250929050565b60006020828403121561554057600080fd5b81356001600160401b0381111561555657600080fd5b820160c0818503121561393957600080fd5b60006020828403121561557a57600080fd5b61393982615255565b60008060008060008086880360e081121561559d57600080fd5b6155a688615255565b96506155b460208901615267565b95506155c260408901615267565b94506155d060608901615267565b9350608088013592506040609f19820112156155eb57600080fd5b506155f4615b88565b61560060a08901615267565b815261560e60c08901615267565b6020820152809150509295509295509295565b6000806040838503121561563457600080fd5b8235915060208301356152e081615e0d565b6000806040838503121561565957600080fd5b50508035926020909101359150565b60006020828403121561567a57600080fd5b61393982615267565b600080600080600060a0868803121561569b57600080fd5b6156a48661527b565b94506020860151935060408601519250606086015191506156c76080870161527b565b90509295509295909350565b600081518084526020808501945080840160005b8381101561570c5781516001600160a01b0316875295820195908201906001016156e7565b509495945050505050565b8060005b6002811015610d8357815184526020938401939091019060010161571b565b600081518084526020808501945080840160005b8381101561570c5781518752958201959082019060010161574e565b60008151808452615782816020860160208601615d1d565b601f01601f19169290920160200192915050565b6157a08183615717565b604001919050565b600083516157ba818460208801615d1d565b8351908301906157ce818360208801615d1d565b01949350505050565b8681526157e76020820187615717565b6157f46060820186615717565b61580160a0820185615717565b61580e60e0820184615717565b60609190911b6001600160601b0319166101208201526101340195945050505050565b8381526158416020820184615717565b606081019190915260800192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b604081016113b98284615717565b602081526000613939602083018461573a565b602081526000613939602083018461576a565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c0608084015261593460e08401826156d3565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b818110156159b557845183529383019391830191600101615999565b509098975050505050505050565b9182526001600160a01b0316602082015260400190565b828152606081016139396020830184615717565b828152604060208201526000613987604083018461573a565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a08301526140e760c083018461576a565b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c0820181905260009061420c9083018461576a565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c0820181905260009061420c9083018461576a565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a060808201819052600090615b30908301846156d3565b979650505050505050565b6000808335601e19843603018112615b5257600080fd5b8301803591506001600160401b03821115615b6c57600080fd5b602001915036819003821315615b8157600080fd5b9250929050565b604080519081016001600160401b0381118282101715615baa57615baa615df7565b60405290565b60405160c081016001600160401b0381118282101715615baa57615baa615df7565b60405161012081016001600160401b0381118282101715615baa57615baa615df7565b60008085851115615c0557600080fd5b83861115615c1257600080fd5b5050820193919092039150565b60008219821115615c3257615c32615d9f565b500190565b60006001600160401b038083168185168083038211156157ce576157ce615d9f565b60006001600160601b038281168482168083038211156157ce576157ce615d9f565b600082615c8a57615c8a615db5565b500490565b6000816000190483118215151615615ca957615ca9615d9f565b500290565b600082821015615cc057615cc0615d9f565b500390565b60006001600160601b0383811690831681811015615ce557615ce5615d9f565b039392505050565b6001600160e01b03198135818116916004851015615d155780818660040360031b1b83161692505b505092915050565b60005b83811015615d38578181015183820152602001615d20565b83811115610d835750506000910152565b6000600019821415615d5d57615d5d615d9f565b5060010190565b60006001600160401b0380831681811415615d8157615d81615d9f565b6001019392505050565b600082615d9a57615d9a615db5565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610b4a57600080fd5b8015158114610b4a57600080fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", } var VRFCoordinatorV25ABI = VRFCoordinatorV25MetaData.ABI @@ -634,25 +634,25 @@ func (_VRFCoordinatorV25 *VRFCoordinatorV25CallerSession) SProvingKeyHashes(arg0 return _VRFCoordinatorV25.Contract.SProvingKeyHashes(&_VRFCoordinatorV25.CallOpts, arg0) } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Caller) SProvingKeys(opts *bind.CallOpts, arg0 [32]byte) (common.Address, error) { +func (_VRFCoordinatorV25 *VRFCoordinatorV25Caller) SProvingKeys(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { var out []interface{} err := _VRFCoordinatorV25.contract.Call(opts, &out, "s_provingKeys", arg0) if err != nil { - return *new(common.Address), err + return *new(bool), err } - out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) return out0, err } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Session) SProvingKeys(arg0 [32]byte) (common.Address, error) { +func (_VRFCoordinatorV25 *VRFCoordinatorV25Session) SProvingKeys(arg0 [32]byte) (bool, error) { return _VRFCoordinatorV25.Contract.SProvingKeys(&_VRFCoordinatorV25.CallOpts, arg0) } -func (_VRFCoordinatorV25 *VRFCoordinatorV25CallerSession) SProvingKeys(arg0 [32]byte) (common.Address, error) { +func (_VRFCoordinatorV25 *VRFCoordinatorV25CallerSession) SProvingKeys(arg0 [32]byte) (bool, error) { return _VRFCoordinatorV25.Contract.SProvingKeys(&_VRFCoordinatorV25.CallOpts, arg0) } @@ -854,30 +854,6 @@ func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) OnTokenTransfer(ar return _VRFCoordinatorV25.Contract.OnTokenTransfer(&_VRFCoordinatorV25.TransactOpts, arg0, amount, data) } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Transactor) OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV25.contract.Transact(opts, "oracleWithdraw", recipient, amount) -} - -func (_VRFCoordinatorV25 *VRFCoordinatorV25Session) OracleWithdraw(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV25.Contract.OracleWithdraw(&_VRFCoordinatorV25.TransactOpts, recipient, amount) -} - -func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) OracleWithdraw(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV25.Contract.OracleWithdraw(&_VRFCoordinatorV25.TransactOpts, recipient, amount) -} - -func (_VRFCoordinatorV25 *VRFCoordinatorV25Transactor) OracleWithdrawNative(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV25.contract.Transact(opts, "oracleWithdrawNative", recipient, amount) -} - -func (_VRFCoordinatorV25 *VRFCoordinatorV25Session) OracleWithdrawNative(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV25.Contract.OracleWithdrawNative(&_VRFCoordinatorV25.TransactOpts, recipient, amount) -} - -func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) OracleWithdrawNative(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV25.Contract.OracleWithdrawNative(&_VRFCoordinatorV25.TransactOpts, recipient, amount) -} - func (_VRFCoordinatorV25 *VRFCoordinatorV25Transactor) OwnerCancelSubscription(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) { return _VRFCoordinatorV25.contract.Transact(opts, "ownerCancelSubscription", subId) } @@ -926,16 +902,16 @@ func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) RegisterMigratable return _VRFCoordinatorV25.Contract.RegisterMigratableCoordinator(&_VRFCoordinatorV25.TransactOpts, target) } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Transactor) RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV25.contract.Transact(opts, "registerProvingKey", oracle, publicProvingKey) +func (_VRFCoordinatorV25 *VRFCoordinatorV25Transactor) RegisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorV25.contract.Transact(opts, "registerProvingKey", publicProvingKey) } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Session) RegisterProvingKey(oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV25.Contract.RegisterProvingKey(&_VRFCoordinatorV25.TransactOpts, oracle, publicProvingKey) +func (_VRFCoordinatorV25 *VRFCoordinatorV25Session) RegisterProvingKey(publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorV25.Contract.RegisterProvingKey(&_VRFCoordinatorV25.TransactOpts, publicProvingKey) } -func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) RegisterProvingKey(oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV25.Contract.RegisterProvingKey(&_VRFCoordinatorV25.TransactOpts, oracle, publicProvingKey) +func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) RegisterProvingKey(publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorV25.Contract.RegisterProvingKey(&_VRFCoordinatorV25.TransactOpts, publicProvingKey) } func (_VRFCoordinatorV25 *VRFCoordinatorV25Transactor) RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { @@ -1010,6 +986,30 @@ func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) TransferOwnership( return _VRFCoordinatorV25.Contract.TransferOwnership(&_VRFCoordinatorV25.TransactOpts, to) } +func (_VRFCoordinatorV25 *VRFCoordinatorV25Transactor) Withdraw(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV25.contract.Transact(opts, "withdraw", recipient) +} + +func (_VRFCoordinatorV25 *VRFCoordinatorV25Session) Withdraw(recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV25.Contract.Withdraw(&_VRFCoordinatorV25.TransactOpts, recipient) +} + +func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) Withdraw(recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV25.Contract.Withdraw(&_VRFCoordinatorV25.TransactOpts, recipient) +} + +func (_VRFCoordinatorV25 *VRFCoordinatorV25Transactor) WithdrawNative(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV25.contract.Transact(opts, "withdrawNative", recipient) +} + +func (_VRFCoordinatorV25 *VRFCoordinatorV25Session) WithdrawNative(recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV25.Contract.WithdrawNative(&_VRFCoordinatorV25.TransactOpts, recipient) +} + +func (_VRFCoordinatorV25 *VRFCoordinatorV25TransactorSession) WithdrawNative(recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV25.Contract.WithdrawNative(&_VRFCoordinatorV25.TransactOpts, recipient) +} + type VRFCoordinatorV25ConfigSetIterator struct { Event *VRFCoordinatorV25ConfigSet @@ -2054,32 +2054,21 @@ func (it *VRFCoordinatorV25ProvingKeyDeregisteredIterator) Close() error { type VRFCoordinatorV25ProvingKeyDeregistered struct { KeyHash [32]byte - Oracle common.Address Raw types.Log } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Filterer) FilterProvingKeyDeregistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorV25ProvingKeyDeregisteredIterator, error) { - - var oracleRule []interface{} - for _, oracleItem := range oracle { - oracleRule = append(oracleRule, oracleItem) - } +func (_VRFCoordinatorV25 *VRFCoordinatorV25Filterer) FilterProvingKeyDeregistered(opts *bind.FilterOpts) (*VRFCoordinatorV25ProvingKeyDeregisteredIterator, error) { - logs, sub, err := _VRFCoordinatorV25.contract.FilterLogs(opts, "ProvingKeyDeregistered", oracleRule) + logs, sub, err := _VRFCoordinatorV25.contract.FilterLogs(opts, "ProvingKeyDeregistered") if err != nil { return nil, err } return &VRFCoordinatorV25ProvingKeyDeregisteredIterator{contract: _VRFCoordinatorV25.contract, event: "ProvingKeyDeregistered", logs: logs, sub: sub}, nil } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Filterer) WatchProvingKeyDeregistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV25ProvingKeyDeregistered, oracle []common.Address) (event.Subscription, error) { +func (_VRFCoordinatorV25 *VRFCoordinatorV25Filterer) WatchProvingKeyDeregistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV25ProvingKeyDeregistered) (event.Subscription, error) { - var oracleRule []interface{} - for _, oracleItem := range oracle { - oracleRule = append(oracleRule, oracleItem) - } - - logs, sub, err := _VRFCoordinatorV25.contract.WatchLogs(opts, "ProvingKeyDeregistered", oracleRule) + logs, sub, err := _VRFCoordinatorV25.contract.WatchLogs(opts, "ProvingKeyDeregistered") if err != nil { return nil, err } @@ -2182,32 +2171,21 @@ func (it *VRFCoordinatorV25ProvingKeyRegisteredIterator) Close() error { type VRFCoordinatorV25ProvingKeyRegistered struct { KeyHash [32]byte - Oracle common.Address Raw types.Log } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Filterer) FilterProvingKeyRegistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorV25ProvingKeyRegisteredIterator, error) { +func (_VRFCoordinatorV25 *VRFCoordinatorV25Filterer) FilterProvingKeyRegistered(opts *bind.FilterOpts) (*VRFCoordinatorV25ProvingKeyRegisteredIterator, error) { - var oracleRule []interface{} - for _, oracleItem := range oracle { - oracleRule = append(oracleRule, oracleItem) - } - - logs, sub, err := _VRFCoordinatorV25.contract.FilterLogs(opts, "ProvingKeyRegistered", oracleRule) + logs, sub, err := _VRFCoordinatorV25.contract.FilterLogs(opts, "ProvingKeyRegistered") if err != nil { return nil, err } return &VRFCoordinatorV25ProvingKeyRegisteredIterator{contract: _VRFCoordinatorV25.contract, event: "ProvingKeyRegistered", logs: logs, sub: sub}, nil } -func (_VRFCoordinatorV25 *VRFCoordinatorV25Filterer) WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV25ProvingKeyRegistered, oracle []common.Address) (event.Subscription, error) { - - var oracleRule []interface{} - for _, oracleItem := range oracle { - oracleRule = append(oracleRule, oracleItem) - } +func (_VRFCoordinatorV25 *VRFCoordinatorV25Filterer) WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV25ProvingKeyRegistered) (event.Subscription, error) { - logs, sub, err := _VRFCoordinatorV25.contract.WatchLogs(opts, "ProvingKeyRegistered", oracleRule) + logs, sub, err := _VRFCoordinatorV25.contract.WatchLogs(opts, "ProvingKeyRegistered") if err != nil { return nil, err } @@ -3674,11 +3652,11 @@ func (VRFCoordinatorV25OwnershipTransferred) Topic() common.Hash { } func (VRFCoordinatorV25ProvingKeyDeregistered) Topic() common.Hash { - return common.HexToHash("0x72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d") + return common.HexToHash("0xbd242ec01625c15ecbc02cf700ac8b02c86f7346fa91a08e186810221ae509d0") } func (VRFCoordinatorV25ProvingKeyRegistered) Topic() common.Hash { - return common.HexToHash("0xe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b8") + return common.HexToHash("0xc9583fd3afa3d7f16eb0b88d0268e7d05c09bafa4b21e092cbd1320e1bc8089d") } func (VRFCoordinatorV25RandomWordsFulfilled) Topic() common.Hash { @@ -3768,7 +3746,7 @@ type VRFCoordinatorV25Interface interface { SProvingKeyHashes(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) - SProvingKeys(opts *bind.CallOpts, arg0 [32]byte) (common.Address, error) + SProvingKeys(opts *bind.CallOpts, arg0 [32]byte) (bool, error) SRequestCommitments(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) @@ -3798,10 +3776,6 @@ type VRFCoordinatorV25Interface interface { OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) - OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) - - OracleWithdrawNative(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) - OwnerCancelSubscription(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) RecoverFunds(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) @@ -3810,7 +3784,7 @@ type VRFCoordinatorV25Interface interface { RegisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) - RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) + RegisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) @@ -3824,6 +3798,10 @@ type VRFCoordinatorV25Interface interface { TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + Withdraw(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) + + WithdrawNative(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) + FilterConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorV25ConfigSetIterator, error) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV25ConfigSet) (event.Subscription, error) @@ -3872,15 +3850,15 @@ type VRFCoordinatorV25Interface interface { ParseOwnershipTransferred(log types.Log) (*VRFCoordinatorV25OwnershipTransferred, error) - FilterProvingKeyDeregistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorV25ProvingKeyDeregisteredIterator, error) + FilterProvingKeyDeregistered(opts *bind.FilterOpts) (*VRFCoordinatorV25ProvingKeyDeregisteredIterator, error) - WatchProvingKeyDeregistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV25ProvingKeyDeregistered, oracle []common.Address) (event.Subscription, error) + WatchProvingKeyDeregistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV25ProvingKeyDeregistered) (event.Subscription, error) ParseProvingKeyDeregistered(log types.Log) (*VRFCoordinatorV25ProvingKeyDeregistered, error) - FilterProvingKeyRegistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorV25ProvingKeyRegisteredIterator, error) + FilterProvingKeyRegistered(opts *bind.FilterOpts) (*VRFCoordinatorV25ProvingKeyRegisteredIterator, error) - WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV25ProvingKeyRegistered, oracle []common.Address) (event.Subscription, error) + WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV25ProvingKeyRegistered) (event.Subscription, error) ParseProvingKeyRegistered(log types.Log) (*VRFCoordinatorV25ProvingKeyRegistered, error) diff --git a/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go b/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go index 76b5e267d3b..cbd84c86a63 100644 --- a/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go +++ b/core/gethwrappers/generated/vrf_load_test_with_metrics/vrf_load_test_with_metrics.go @@ -31,8 +31,8 @@ var ( ) var VRFV2LoadTestWithMetricsMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"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\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractVRFCoordinatorV2Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"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\":\"uint64\",\"name\":\"_subId\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c0604052600060045560006005556103e760065534801561002057600080fd5b5060405161111138038061111183398101604081905261003f91610199565b6001600160601b0319606082901b1660805233806000816100a75760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b03848116919091179091558116156100d7576100d7816100ef565b50505060601b6001600160601b03191660a0526101c9565b6001600160a01b0381163314156101485760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161009e565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156101ab57600080fd5b81516001600160a01b03811681146101c257600080fd5b9392505050565b60805160601c60a05160601c610f0f6102026000396000818161014301526103da0152600081816102b7015261031f0152610f0f6000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806379ba509711610097578063d826f88f11610066578063d826f88f1461023f578063d8a4676f1461025e578063dc1670db14610283578063f2fde38b1461028c57600080fd5b806379ba5097146101a55780638da5cb5b146101ad578063a168fa89146101cb578063b1e217491461023657600080fd5b80633b2bcbf1116100d35780633b2bcbf11461013e578063557d2e921461018a578063737144bc1461019357806374dba1241461019c57600080fd5b80631757f11c146100fa5780631fe543e314610116578063271095ef1461012b575b600080fd5b61010360055481565b6040519081526020015b60405180910390f35b610129610124366004610bcb565b61029f565b005b610129610139366004610cba565b61035f565b6101657f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010d565b61010360035481565b61010360045481565b61010360065481565b610129610577565b60005473ffffffffffffffffffffffffffffffffffffffff16610165565b61020c6101d9366004610b99565b6009602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a00161010d565b61010360075481565b6101296000600481905560058190556103e76006556003819055600255565b61027161026c366004610b99565b610674565b60405161010d96959493929190610d36565b61010360025481565b61012961029a366004610b5c565b610759565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610351576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b61035b828261076d565b5050565b610367610894565b60005b8161ffff168161ffff16101561056e576040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810186905267ffffffffffffffff8816602482015261ffff8716604482015263ffffffff8086166064830152841660848201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b15801561043357600080fd5b505af1158015610447573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061046b9190610bb2565b60078190559050600061047c610917565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a084018390528783526009815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016901515178155905180519495509193909261050a926001850192910190610ad1565b506040820151600282015560608201516003808301919091556080830151600483015560a090920151600590910155805490600061054783610e6b565b9091555050600091825260086020526040909120558061056681610e49565b91505061036a565b50505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146105f8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610348565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6000818152600960209081526040808320815160c081018352815460ff16151581526001820180548451818702810187019095528085526060958795869586958695869591949293858401939092908301828280156106f257602002820191906000526020600020905b8154815260200190600101908083116106de575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b610761610894565b61076a816109b4565b50565b6000610777610917565b600084815260086020526040812054919250906107949083610e32565b905060006107a582620f4240610df5565b90506005548211156107b75760058290555b60065482106107c8576006546107ca565b815b6006556002546107da578061080d565b6002546107e8906001610da2565b816002546004546107f99190610df5565b6108039190610da2565b61080d9190610dba565b600455600085815260096020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081178255865161085f939290910191870190610ad1565b506000858152600960205260408120426003820155600501849055600280549161088883610e6b565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610915576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610348565b565b60004661092381610aaa565b156109ad57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561096f57600080fd5b505afa158015610983573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a79190610bb2565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610a34576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610348565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480610abe575062066eed82145b80610acb575062066eee82145b92915050565b828054828255906000526020600020908101928215610b0c579160200282015b82811115610b0c578251825591602001919060010190610af1565b50610b18929150610b1c565b5090565b5b80821115610b185760008155600101610b1d565b803561ffff81168114610b4357600080fd5b919050565b803563ffffffff81168114610b4357600080fd5b600060208284031215610b6e57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610b9257600080fd5b9392505050565b600060208284031215610bab57600080fd5b5035919050565b600060208284031215610bc457600080fd5b5051919050565b60008060408385031215610bde57600080fd5b8235915060208084013567ffffffffffffffff80821115610bfe57600080fd5b818601915086601f830112610c1257600080fd5b813581811115610c2457610c24610ed3565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610c6757610c67610ed3565b604052828152858101935084860182860187018b1015610c8657600080fd5b600095505b83861015610ca9578035855260019590950194938601938601610c8b565b508096505050505050509250929050565b60008060008060008060c08789031215610cd357600080fd5b863567ffffffffffffffff81168114610ceb57600080fd5b9550610cf960208801610b31565b945060408701359350610d0e60608801610b48565b9250610d1c60808801610b48565b9150610d2a60a08801610b31565b90509295509295509295565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015610d7957845183529383019391830191600101610d5d565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b60008219821115610db557610db5610ea4565b500190565b600082610df0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610e2d57610e2d610ea4565b500290565b600082821015610e4457610e44610ea4565b500390565b600061ffff80831681811415610e6157610e61610ea4565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610e9d57610e9d610ea4565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCreatedFundedAndConsumerAdded\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractVRFCoordinatorV2Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINKTOKEN\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"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\":\"uint64\",\"name\":\"_subId\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"_subTopUpAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"requestRandomWordsWithForceFulfill\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_subId\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"name\":\"topUpSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60c0604052600060035560006004556103e760055534801561002057600080fd5b5060405161133038038061133083398101604081905261003f91610059565b60601b6001600160601b031916608081905260a052610089565b60006020828403121561006b57600080fd5b81516001600160a01b038116811461008257600080fd5b9392505050565b60805160601c60a05160601c61124b6100e560003960008181610156015281816103e00152818161048c0152818161056b0152818161067d0152818161072a0152610a250152600081816102c4015261032c015261124b6000f3fe608060405234801561001057600080fd5b50600436106100f55760003560e01c806362cce24411610097578063b1e2174911610066578063b1e2174914610256578063d826f88f1461025f578063d8a4676f1461027e578063dc1670db146102a357600080fd5b806362cce244146101c6578063737144bc146101d957806374dba124146101e2578063a168fa89146101eb57600080fd5b80632be555da116100d35780632be555da1461013e5780633b2bcbf11461015157806355380dfb1461019d578063557d2e92146101bd57600080fd5b80631757f11c146100fa5780631fe543e314610116578063271095ef1461012b575b600080fd5b61010360045481565b6040519081526020015b60405180910390f35b610129610124366004610e08565b6102ac565b005b610129610139366004610f14565b61036b565b61012961014c366004610f83565b610381565b6101787f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161010d565b6000546101789073ffffffffffffffffffffffffffffffffffffffff1681565b61010360025481565b6101296101d4366004610d5e565b610488565b61010360035481565b61010360055481565b61022c6101f9366004610dd6565b6008602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a00161010d565b61010360065481565b6101296000600381905560048190556103e76005556002819055600155565b61029161028c366004610dd6565b6107a7565b60405161010d96959493929190611059565b61010360015481565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461035d576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016602482015260440160405180910390fd5b610367828261088c565b5050565b6103798686868686866109b2565b505050505050565b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040805167ffffffffffffffff86166020820152634000aea0917f0000000000000000000000000000000000000000000000000000000000000000918691016040516020818303038152906040526040518463ffffffff1660e01b815260040161043093929190610fc1565b602060405180830381600087803b15801561044a57600080fd5b505af115801561045e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104829190610d35565b50505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156104f257600080fd5b505af1158015610506573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052a9190610ef7565b6040517f7341c10c00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201523060248201529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690637341c10c90604401600060405180830381600087803b1580156105c457600080fd5b505af11580156105d8573d6000803e3d6000fd5b505050506105e7818484610381565b6040805167ffffffffffffffff831681523060208201529081018490527f56c142509574e8340ca0190b029c74464b84037d2876278ea0ade3ffb1f0042c9060600160405180910390a161063f8189898989896109b2565b6040517f9f87fad700000000000000000000000000000000000000000000000000000000815267ffffffffffffffff821660048201523060248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690639f87fad790604401600060405180830381600087803b1580156106d657600080fd5b505af11580156106ea573d6000803e3d6000fd5b50506040517fd7ae1d3000000000000000000000000000000000000000000000000000000000815267ffffffffffffffff841660048201523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16925063d7ae1d309150604401600060405180830381600087803b15801561078557600080fd5b505af1158015610799573d6000803e3d6000fd5b505050505050505050505050565b6000818152600860209081526040808320815160c081018352815460ff161515815260018201805484518187028101870190955280855260609587958695869586958695919492938584019390929083018282801561082557602002820191906000526020600020905b815481526020019060010190808311610811575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b6000610896610bc2565b600084815260076020526040812054919250906108b39083611155565b905060006108c482620f4240611118565b90506004548211156108d65760048290555b60055482106108e7576005546108e9565b815b6005556001546108f9578061092b565b60018054610906916110c5565b816001546003546109179190611118565b61092191906110c5565b61092b91906110dd565b600355600085815260086020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081178255865161097d939290910191870190610c86565b50600085815260086020526040812042600382015560050184905560018054916109a68361118e565b91905055505050505050565b60005b8161ffff168161ffff161015610bb9576040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810186905267ffffffffffffffff8816602482015261ffff8716604482015263ffffffff8086166064830152841660848201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b158015610a7e57600080fd5b505af1158015610a92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab69190610def565b600681905590506000610ac7610bc2565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a084018390528783526008815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169015151781559051805194955091939092610b55926001850192910190610c86565b506040820151600280830191909155606083015160038301556080830151600483015560a0909201516005909101558054906000610b928361118e565b90915550506000918252600760205260409091205580610bb18161116c565b9150506109b5565b50505050505050565b600046610bce81610c5f565b15610c5857606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610c1a57600080fd5b505afa158015610c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c529190610def565b91505090565b4391505090565b600061a4b1821480610c73575062066eed82145b80610c80575062066eee82145b92915050565b828054828255906000526020600020908101928215610cc1579160200282015b82811115610cc1578251825591602001919060010190610ca6565b50610ccd929150610cd1565b5090565b5b80821115610ccd5760008155600101610cd2565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d0a57600080fd5b919050565b803561ffff81168114610d0a57600080fd5b803563ffffffff81168114610d0a57600080fd5b600060208284031215610d4757600080fd5b81518015158114610d5757600080fd5b9392505050565b600080600080600080600060e0888a031215610d7957600080fd5b610d8288610d0f565b965060208801359550610d9760408901610d21565b9450610da560608901610d21565b9350610db360808901610d0f565b925060a08801359150610dc860c08901610ce6565b905092959891949750929550565b600060208284031215610de857600080fd5b5035919050565b600060208284031215610e0157600080fd5b5051919050565b60008060408385031215610e1b57600080fd5b8235915060208084013567ffffffffffffffff80821115610e3b57600080fd5b818601915086601f830112610e4f57600080fd5b813581811115610e6157610e616111f6565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610ea457610ea46111f6565b604052828152858101935084860182860187018b1015610ec357600080fd5b600095505b83861015610ee6578035855260019590950194938601938601610ec8565b508096505050505050509250929050565b600060208284031215610f0957600080fd5b8151610d5781611225565b60008060008060008060c08789031215610f2d57600080fd5b8635610f3881611225565b9550610f4660208801610d0f565b945060408701359350610f5b60608801610d21565b9250610f6960808801610d21565b9150610f7760a08801610d0f565b90509295509295509295565b600080600060608486031215610f9857600080fd5b8335610fa381611225565b925060208401359150610fb860408501610ce6565b90509250925092565b73ffffffffffffffffffffffffffffffffffffffff8416815260006020848184015260606040840152835180606085015260005b8181101561101157858101830151858201608001528201610ff5565b81811115611023576000608083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160800195945050505050565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b8181101561109c57845183529383019391830191600101611080565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b600082198211156110d8576110d86111c7565b500190565b600082611113577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611150576111506111c7565b500290565b600082821015611167576111676111c7565b500390565b600061ffff80831681811415611184576111846111c7565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156111c0576111c06111c7565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8116811461123b57600080fd5b5056fea164736f6c6343000806000a", } var VRFV2LoadTestWithMetricsABI = VRFV2LoadTestWithMetricsMetaData.ABI @@ -193,6 +193,28 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCallerSession) COORDINA return _VRFV2LoadTestWithMetrics.Contract.COORDINATOR(&_VRFV2LoadTestWithMetrics.CallOpts) } +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCaller) LINKTOKEN(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2LoadTestWithMetrics.contract.Call(opts, &out, "LINKTOKEN") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) LINKTOKEN() (common.Address, error) { + return _VRFV2LoadTestWithMetrics.Contract.LINKTOKEN(&_VRFV2LoadTestWithMetrics.CallOpts) +} + +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCallerSession) LINKTOKEN() (common.Address, error) { + return _VRFV2LoadTestWithMetrics.Contract.LINKTOKEN(&_VRFV2LoadTestWithMetrics.CallOpts) +} + func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) { @@ -227,28 +249,6 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCallerSession) GetReque return _VRFV2LoadTestWithMetrics.Contract.GetRequestStatus(&_VRFV2LoadTestWithMetrics.CallOpts, _requestId) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCaller) Owner(opts *bind.CallOpts) (common.Address, error) { - var out []interface{} - err := _VRFV2LoadTestWithMetrics.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 (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) Owner() (common.Address, error) { - return _VRFV2LoadTestWithMetrics.Contract.Owner(&_VRFV2LoadTestWithMetrics.CallOpts) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCallerSession) Owner() (common.Address, error) { - return _VRFV2LoadTestWithMetrics.Contract.Owner(&_VRFV2LoadTestWithMetrics.CallOpts) -} - func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCaller) SAverageFulfillmentInMillions(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _VRFV2LoadTestWithMetrics.contract.Call(opts, &out, "s_averageFulfillmentInMillions") @@ -414,18 +414,6 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsCallerSession) SSlowest return _VRFV2LoadTestWithMetrics.Contract.SSlowestFulfillment(&_VRFV2LoadTestWithMetrics.CallOpts) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "acceptOwnership") -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) AcceptOwnership() (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.AcceptOwnership(&_VRFV2LoadTestWithMetrics.TransactOpts) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) AcceptOwnership() (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.AcceptOwnership(&_VRFV2LoadTestWithMetrics.TransactOpts) -} - func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) RawFulfillRandomWords(opts *bind.TransactOpts, requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) { return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "rawFulfillRandomWords", requestId, randomWords) } @@ -450,168 +438,44 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) Requ return _VRFV2LoadTestWithMetrics.Contract.RequestRandomWords(&_VRFV2LoadTestWithMetrics.TransactOpts, _subId, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "reset") +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) RequestRandomWordsWithForceFulfill(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "requestRandomWordsWithForceFulfill", _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount, _link) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) Reset() (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.Reset(&_VRFV2LoadTestWithMetrics.TransactOpts) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) Reset() (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.Reset(&_VRFV2LoadTestWithMetrics.TransactOpts) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "transferOwnership", to) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.TransferOwnership(&_VRFV2LoadTestWithMetrics.TransactOpts, to) -} - -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { - return _VRFV2LoadTestWithMetrics.Contract.TransferOwnership(&_VRFV2LoadTestWithMetrics.TransactOpts, to) -} - -type VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator struct { - Event *VRFV2LoadTestWithMetricsOwnershipTransferRequested - - contract *bind.BoundContract - event string - - logs chan types.Log - sub ethereum.Subscription - done bool - fail error +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) RequestRandomWordsWithForceFulfill(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.RequestRandomWordsWithForceFulfill(&_VRFV2LoadTestWithMetrics.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount, _link) } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator) Next() bool { - - if it.fail != nil { - return false - } - - if it.done { - select { - case log := <-it.logs: - it.Event = new(VRFV2LoadTestWithMetricsOwnershipTransferRequested) - 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(VRFV2LoadTestWithMetricsOwnershipTransferRequested) - 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 (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) RequestRandomWordsWithForceFulfill(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.RequestRandomWordsWithForceFulfill(&_VRFV2LoadTestWithMetrics.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount, _link) } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator) Error() error { - return it.fail +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "reset") } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator) Close() error { - it.sub.Unsubscribe() - return nil +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) Reset() (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.Reset(&_VRFV2LoadTestWithMetrics.TransactOpts) } -type VRFV2LoadTestWithMetricsOwnershipTransferRequested struct { - From common.Address - To common.Address - Raw types.Log +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) Reset() (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.Reset(&_VRFV2LoadTestWithMetrics.TransactOpts) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator, 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 := _VRFV2LoadTestWithMetrics.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) - if err != nil { - return nil, err - } - return &VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator{contract: _VRFV2LoadTestWithMetrics.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactor) TopUpSubscription(opts *bind.TransactOpts, _subId uint64, _amount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.contract.Transact(opts, "topUpSubscription", _subId, _amount, _link) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsOwnershipTransferRequested, 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 := _VRFV2LoadTestWithMetrics.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(VRFV2LoadTestWithMetricsOwnershipTransferRequested) - if err := _VRFV2LoadTestWithMetrics.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 (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsSession) TopUpSubscription(_subId uint64, _amount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.TopUpSubscription(&_VRFV2LoadTestWithMetrics.TransactOpts, _subId, _amount, _link) } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) ParseOwnershipTransferRequested(log types.Log) (*VRFV2LoadTestWithMetricsOwnershipTransferRequested, error) { - event := new(VRFV2LoadTestWithMetricsOwnershipTransferRequested) - if err := _VRFV2LoadTestWithMetrics.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { - return nil, err - } - event.Raw = log - return event, nil +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsTransactorSession) TopUpSubscription(_subId uint64, _amount *big.Int, _link common.Address) (*types.Transaction, error) { + return _VRFV2LoadTestWithMetrics.Contract.TopUpSubscription(&_VRFV2LoadTestWithMetrics.TransactOpts, _subId, _amount, _link) } -type VRFV2LoadTestWithMetricsOwnershipTransferredIterator struct { - Event *VRFV2LoadTestWithMetricsOwnershipTransferred +type VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator struct { + Event *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded contract *bind.BoundContract event string @@ -622,7 +486,7 @@ type VRFV2LoadTestWithMetricsOwnershipTransferredIterator struct { fail error } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Next() bool { +func (it *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator) Next() bool { if it.fail != nil { return false @@ -631,7 +495,7 @@ func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Next() bool { if it.done { select { case log := <-it.logs: - it.Event = new(VRFV2LoadTestWithMetricsOwnershipTransferred) + it.Event = new(VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -646,7 +510,7 @@ func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Next() bool { select { case log := <-it.logs: - it.Event = new(VRFV2LoadTestWithMetricsOwnershipTransferred) + it.Event = new(VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false @@ -661,51 +525,34 @@ func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Next() bool { } } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Error() error { +func (it *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator) Error() error { return it.fail } -func (it *VRFV2LoadTestWithMetricsOwnershipTransferredIterator) Close() error { +func (it *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator) Close() error { it.sub.Unsubscribe() return nil } -type VRFV2LoadTestWithMetricsOwnershipTransferred struct { - From common.Address - To common.Address - Raw types.Log +type VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded struct { + SubId uint64 + Consumer common.Address + Amount *big.Int + Raw types.Log } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2LoadTestWithMetricsOwnershipTransferredIterator, error) { +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) FilterSubscriptionCreatedFundedAndConsumerAdded(opts *bind.FilterOpts) (*VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator, 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 := _VRFV2LoadTestWithMetrics.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + logs, sub, err := _VRFV2LoadTestWithMetrics.contract.FilterLogs(opts, "SubscriptionCreatedFundedAndConsumerAdded") if err != nil { return nil, err } - return &VRFV2LoadTestWithMetricsOwnershipTransferredIterator{contract: _VRFV2LoadTestWithMetrics.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil + return &VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator{contract: _VRFV2LoadTestWithMetrics.contract, event: "SubscriptionCreatedFundedAndConsumerAdded", logs: logs, sub: sub}, nil } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsOwnershipTransferred, 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) - } +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) WatchSubscriptionCreatedFundedAndConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) (event.Subscription, error) { - logs, sub, err := _VRFV2LoadTestWithMetrics.contract.WatchLogs(opts, "OwnershipTransferred", fromRule, toRule) + logs, sub, err := _VRFV2LoadTestWithMetrics.contract.WatchLogs(opts, "SubscriptionCreatedFundedAndConsumerAdded") if err != nil { return nil, err } @@ -715,8 +562,8 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) WatchOwnershi select { case log := <-logs: - event := new(VRFV2LoadTestWithMetricsOwnershipTransferred) - if err := _VRFV2LoadTestWithMetrics.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + event := new(VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) + if err := _VRFV2LoadTestWithMetrics.contract.UnpackLog(event, "SubscriptionCreatedFundedAndConsumerAdded", log); err != nil { return err } event.Raw = log @@ -737,9 +584,9 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) WatchOwnershi }), nil } -func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) ParseOwnershipTransferred(log types.Log) (*VRFV2LoadTestWithMetricsOwnershipTransferred, error) { - event := new(VRFV2LoadTestWithMetricsOwnershipTransferred) - if err := _VRFV2LoadTestWithMetrics.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { +func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetricsFilterer) ParseSubscriptionCreatedFundedAndConsumerAdded(log types.Log) (*VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded, error) { + event := new(VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) + if err := _VRFV2LoadTestWithMetrics.contract.UnpackLog(event, "SubscriptionCreatedFundedAndConsumerAdded", log); err != nil { return nil, err } event.Raw = log @@ -764,22 +611,16 @@ type SRequests struct { func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetrics) ParseLog(log types.Log) (generated.AbigenLog, error) { switch log.Topics[0] { - case _VRFV2LoadTestWithMetrics.abi.Events["OwnershipTransferRequested"].ID: - return _VRFV2LoadTestWithMetrics.ParseOwnershipTransferRequested(log) - case _VRFV2LoadTestWithMetrics.abi.Events["OwnershipTransferred"].ID: - return _VRFV2LoadTestWithMetrics.ParseOwnershipTransferred(log) + case _VRFV2LoadTestWithMetrics.abi.Events["SubscriptionCreatedFundedAndConsumerAdded"].ID: + return _VRFV2LoadTestWithMetrics.ParseSubscriptionCreatedFundedAndConsumerAdded(log) default: return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) } } -func (VRFV2LoadTestWithMetricsOwnershipTransferRequested) Topic() common.Hash { - return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") -} - -func (VRFV2LoadTestWithMetricsOwnershipTransferred) Topic() common.Hash { - return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +func (VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) Topic() common.Hash { + return common.HexToHash("0x56c142509574e8340ca0190b029c74464b84037d2876278ea0ade3ffb1f0042c") } func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetrics) Address() common.Address { @@ -789,12 +630,12 @@ func (_VRFV2LoadTestWithMetrics *VRFV2LoadTestWithMetrics) Address() common.Addr type VRFV2LoadTestWithMetricsInterface interface { COORDINATOR(opts *bind.CallOpts) (common.Address, error) + LINKTOKEN(opts *bind.CallOpts) (common.Address, error) + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) - Owner(opts *bind.CallOpts) (common.Address, error) - SAverageFulfillmentInMillions(opts *bind.CallOpts) (*big.Int, error) SFastestFulfillment(opts *bind.CallOpts) (*big.Int, error) @@ -811,27 +652,21 @@ type VRFV2LoadTestWithMetricsInterface interface { SSlowestFulfillment(opts *bind.CallOpts) (*big.Int, error) - AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) - RawFulfillRandomWords(opts *bind.TransactOpts, requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) RequestRandomWords(opts *bind.TransactOpts, _subId uint64, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16) (*types.Transaction, error) - Reset(opts *bind.TransactOpts) (*types.Transaction, error) - - TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + RequestRandomWordsWithForceFulfill(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int, _link common.Address) (*types.Transaction, error) - FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2LoadTestWithMetricsOwnershipTransferRequestedIterator, error) - - WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + Reset(opts *bind.TransactOpts) (*types.Transaction, error) - ParseOwnershipTransferRequested(log types.Log) (*VRFV2LoadTestWithMetricsOwnershipTransferRequested, error) + TopUpSubscription(opts *bind.TransactOpts, _subId uint64, _amount *big.Int, _link common.Address) (*types.Transaction, error) - FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2LoadTestWithMetricsOwnershipTransferredIterator, error) + FilterSubscriptionCreatedFundedAndConsumerAdded(opts *bind.FilterOpts) (*VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAddedIterator, error) - WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + WatchSubscriptionCreatedFundedAndConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded) (event.Subscription, error) - ParseOwnershipTransferred(log types.Log) (*VRFV2LoadTestWithMetricsOwnershipTransferred, error) + ParseSubscriptionCreatedFundedAndConsumerAdded(log types.Log) (*VRFV2LoadTestWithMetricsSubscriptionCreatedFundedAndConsumerAdded, error) ParseLog(log types.Log) (generated.AbigenLog, error) diff --git a/core/gethwrappers/generated/vrf_log_emitter/vrf_log_emitter.go b/core/gethwrappers/generated/vrf_log_emitter/vrf_log_emitter.go new file mode 100644 index 00000000000..2cdeaa6c3a8 --- /dev/null +++ b/core/gethwrappers/generated/vrf_log_emitter/vrf_log_emitter.go @@ -0,0 +1,526 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package vrf_log_emitter + +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 +) + +var VRFLogEmitterMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"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\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"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\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RandomWordsRequested\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"outputSeed\",\"type\":\"uint256\"},{\"internalType\":\"uint96\",\"name\":\"payment\",\"type\":\"uint96\"},{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"emitRandomWordsFulfilled\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"preSeed\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"internalType\":\"uint16\",\"name\":\"minimumRequestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"numWords\",\"type\":\"uint32\"},{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"emitRandomWordsRequested\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b5061027f806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063ca920adb1461003b578063fe62d3e914610050575b600080fd5b61004e61004936600461015b565b610063565b005b61004e61005e366004610212565b6100eb565b604080518881526020810188905261ffff86168183015263ffffffff858116606083015284166080820152905173ffffffffffffffffffffffffffffffffffffffff83169167ffffffffffffffff8816918b917f63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772919081900360a00190a45050505050505050565b604080518481526bffffffffffffffffffffffff8416602082015282151581830152905185917f7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4919081900360600190a250505050565b803563ffffffff8116811461015657600080fd5b919050565b600080600080600080600080610100898b03121561017857600080fd5b883597506020890135965060408901359550606089013567ffffffffffffffff811681146101a557600080fd5b9450608089013561ffff811681146101bc57600080fd5b93506101ca60a08a01610142565b92506101d860c08a01610142565b915060e089013573ffffffffffffffffffffffffffffffffffffffff8116811461020157600080fd5b809150509295985092959890939650565b6000806000806080858703121561022857600080fd5b843593506020850135925060408501356bffffffffffffffffffffffff8116811461025257600080fd5b91506060850135801515811461026757600080fd5b93969295509093505056fea164736f6c6343000813000a", +} + +var VRFLogEmitterABI = VRFLogEmitterMetaData.ABI + +var VRFLogEmitterBin = VRFLogEmitterMetaData.Bin + +func DeployVRFLogEmitter(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *VRFLogEmitter, error) { + parsed, err := VRFLogEmitterMetaData.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(VRFLogEmitterBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VRFLogEmitter{address: address, abi: *parsed, VRFLogEmitterCaller: VRFLogEmitterCaller{contract: contract}, VRFLogEmitterTransactor: VRFLogEmitterTransactor{contract: contract}, VRFLogEmitterFilterer: VRFLogEmitterFilterer{contract: contract}}, nil +} + +type VRFLogEmitter struct { + address common.Address + abi abi.ABI + VRFLogEmitterCaller + VRFLogEmitterTransactor + VRFLogEmitterFilterer +} + +type VRFLogEmitterCaller struct { + contract *bind.BoundContract +} + +type VRFLogEmitterTransactor struct { + contract *bind.BoundContract +} + +type VRFLogEmitterFilterer struct { + contract *bind.BoundContract +} + +type VRFLogEmitterSession struct { + Contract *VRFLogEmitter + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type VRFLogEmitterCallerSession struct { + Contract *VRFLogEmitterCaller + CallOpts bind.CallOpts +} + +type VRFLogEmitterTransactorSession struct { + Contract *VRFLogEmitterTransactor + TransactOpts bind.TransactOpts +} + +type VRFLogEmitterRaw struct { + Contract *VRFLogEmitter +} + +type VRFLogEmitterCallerRaw struct { + Contract *VRFLogEmitterCaller +} + +type VRFLogEmitterTransactorRaw struct { + Contract *VRFLogEmitterTransactor +} + +func NewVRFLogEmitter(address common.Address, backend bind.ContractBackend) (*VRFLogEmitter, error) { + abi, err := abi.JSON(strings.NewReader(VRFLogEmitterABI)) + if err != nil { + return nil, err + } + contract, err := bindVRFLogEmitter(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VRFLogEmitter{address: address, abi: abi, VRFLogEmitterCaller: VRFLogEmitterCaller{contract: contract}, VRFLogEmitterTransactor: VRFLogEmitterTransactor{contract: contract}, VRFLogEmitterFilterer: VRFLogEmitterFilterer{contract: contract}}, nil +} + +func NewVRFLogEmitterCaller(address common.Address, caller bind.ContractCaller) (*VRFLogEmitterCaller, error) { + contract, err := bindVRFLogEmitter(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VRFLogEmitterCaller{contract: contract}, nil +} + +func NewVRFLogEmitterTransactor(address common.Address, transactor bind.ContractTransactor) (*VRFLogEmitterTransactor, error) { + contract, err := bindVRFLogEmitter(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VRFLogEmitterTransactor{contract: contract}, nil +} + +func NewVRFLogEmitterFilterer(address common.Address, filterer bind.ContractFilterer) (*VRFLogEmitterFilterer, error) { + contract, err := bindVRFLogEmitter(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VRFLogEmitterFilterer{contract: contract}, nil +} + +func bindVRFLogEmitter(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := VRFLogEmitterMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_VRFLogEmitter *VRFLogEmitterRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFLogEmitter.Contract.VRFLogEmitterCaller.contract.Call(opts, result, method, params...) +} + +func (_VRFLogEmitter *VRFLogEmitterRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.VRFLogEmitterTransactor.contract.Transfer(opts) +} + +func (_VRFLogEmitter *VRFLogEmitterRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.VRFLogEmitterTransactor.contract.Transact(opts, method, params...) +} + +func (_VRFLogEmitter *VRFLogEmitterCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFLogEmitter.Contract.contract.Call(opts, result, method, params...) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.contract.Transfer(opts) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.contract.Transact(opts, method, params...) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactor) EmitRandomWordsFulfilled(opts *bind.TransactOpts, requestId *big.Int, outputSeed *big.Int, payment *big.Int, success bool) (*types.Transaction, error) { + return _VRFLogEmitter.contract.Transact(opts, "emitRandomWordsFulfilled", requestId, outputSeed, payment, success) +} + +func (_VRFLogEmitter *VRFLogEmitterSession) EmitRandomWordsFulfilled(requestId *big.Int, outputSeed *big.Int, payment *big.Int, success bool) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.EmitRandomWordsFulfilled(&_VRFLogEmitter.TransactOpts, requestId, outputSeed, payment, success) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactorSession) EmitRandomWordsFulfilled(requestId *big.Int, outputSeed *big.Int, payment *big.Int, success bool) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.EmitRandomWordsFulfilled(&_VRFLogEmitter.TransactOpts, requestId, outputSeed, payment, success) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactor) EmitRandomWordsRequested(opts *bind.TransactOpts, keyHash [32]byte, requestId *big.Int, preSeed *big.Int, subId uint64, minimumRequestConfirmations uint16, callbackGasLimit uint32, numWords uint32, sender common.Address) (*types.Transaction, error) { + return _VRFLogEmitter.contract.Transact(opts, "emitRandomWordsRequested", keyHash, requestId, preSeed, subId, minimumRequestConfirmations, callbackGasLimit, numWords, sender) +} + +func (_VRFLogEmitter *VRFLogEmitterSession) EmitRandomWordsRequested(keyHash [32]byte, requestId *big.Int, preSeed *big.Int, subId uint64, minimumRequestConfirmations uint16, callbackGasLimit uint32, numWords uint32, sender common.Address) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.EmitRandomWordsRequested(&_VRFLogEmitter.TransactOpts, keyHash, requestId, preSeed, subId, minimumRequestConfirmations, callbackGasLimit, numWords, sender) +} + +func (_VRFLogEmitter *VRFLogEmitterTransactorSession) EmitRandomWordsRequested(keyHash [32]byte, requestId *big.Int, preSeed *big.Int, subId uint64, minimumRequestConfirmations uint16, callbackGasLimit uint32, numWords uint32, sender common.Address) (*types.Transaction, error) { + return _VRFLogEmitter.Contract.EmitRandomWordsRequested(&_VRFLogEmitter.TransactOpts, keyHash, requestId, preSeed, subId, minimumRequestConfirmations, callbackGasLimit, numWords, sender) +} + +type VRFLogEmitterRandomWordsFulfilledIterator struct { + Event *VRFLogEmitterRandomWordsFulfilled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFLogEmitterRandomWordsFulfilledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFLogEmitterRandomWordsFulfilled) + 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(VRFLogEmitterRandomWordsFulfilled) + 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 *VRFLogEmitterRandomWordsFulfilledIterator) Error() error { + return it.fail +} + +func (it *VRFLogEmitterRandomWordsFulfilledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFLogEmitterRandomWordsFulfilled struct { + RequestId *big.Int + OutputSeed *big.Int + Payment *big.Int + Success bool + Raw types.Log +} + +func (_VRFLogEmitter *VRFLogEmitterFilterer) FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int) (*VRFLogEmitterRandomWordsFulfilledIterator, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFLogEmitter.contract.FilterLogs(opts, "RandomWordsFulfilled", requestIdRule) + if err != nil { + return nil, err + } + return &VRFLogEmitterRandomWordsFulfilledIterator{contract: _VRFLogEmitter.contract, event: "RandomWordsFulfilled", logs: logs, sub: sub}, nil +} + +func (_VRFLogEmitter *VRFLogEmitterFilterer) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFLogEmitterRandomWordsFulfilled, requestId []*big.Int) (event.Subscription, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFLogEmitter.contract.WatchLogs(opts, "RandomWordsFulfilled", requestIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFLogEmitterRandomWordsFulfilled) + if err := _VRFLogEmitter.contract.UnpackLog(event, "RandomWordsFulfilled", 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 (_VRFLogEmitter *VRFLogEmitterFilterer) ParseRandomWordsFulfilled(log types.Log) (*VRFLogEmitterRandomWordsFulfilled, error) { + event := new(VRFLogEmitterRandomWordsFulfilled) + if err := _VRFLogEmitter.contract.UnpackLog(event, "RandomWordsFulfilled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFLogEmitterRandomWordsRequestedIterator struct { + Event *VRFLogEmitterRandomWordsRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFLogEmitterRandomWordsRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFLogEmitterRandomWordsRequested) + 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(VRFLogEmitterRandomWordsRequested) + 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 *VRFLogEmitterRandomWordsRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFLogEmitterRandomWordsRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFLogEmitterRandomWordsRequested struct { + KeyHash [32]byte + RequestId *big.Int + PreSeed *big.Int + SubId uint64 + MinimumRequestConfirmations uint16 + CallbackGasLimit uint32 + NumWords uint32 + Sender common.Address + Raw types.Log +} + +func (_VRFLogEmitter *VRFLogEmitterFilterer) FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subId []uint64, sender []common.Address) (*VRFLogEmitterRandomWordsRequestedIterator, error) { + + var keyHashRule []interface{} + for _, keyHashItem := range keyHash { + keyHashRule = append(keyHashRule, keyHashItem) + } + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _VRFLogEmitter.contract.FilterLogs(opts, "RandomWordsRequested", keyHashRule, subIdRule, senderRule) + if err != nil { + return nil, err + } + return &VRFLogEmitterRandomWordsRequestedIterator{contract: _VRFLogEmitter.contract, event: "RandomWordsRequested", logs: logs, sub: sub}, nil +} + +func (_VRFLogEmitter *VRFLogEmitterFilterer) WatchRandomWordsRequested(opts *bind.WatchOpts, sink chan<- *VRFLogEmitterRandomWordsRequested, keyHash [][32]byte, subId []uint64, sender []common.Address) (event.Subscription, error) { + + var keyHashRule []interface{} + for _, keyHashItem := range keyHash { + keyHashRule = append(keyHashRule, keyHashItem) + } + + var subIdRule []interface{} + for _, subIdItem := range subId { + subIdRule = append(subIdRule, subIdItem) + } + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + + logs, sub, err := _VRFLogEmitter.contract.WatchLogs(opts, "RandomWordsRequested", keyHashRule, subIdRule, senderRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFLogEmitterRandomWordsRequested) + if err := _VRFLogEmitter.contract.UnpackLog(event, "RandomWordsRequested", 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 (_VRFLogEmitter *VRFLogEmitterFilterer) ParseRandomWordsRequested(log types.Log) (*VRFLogEmitterRandomWordsRequested, error) { + event := new(VRFLogEmitterRandomWordsRequested) + if err := _VRFLogEmitter.contract.UnpackLog(event, "RandomWordsRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +func (_VRFLogEmitter *VRFLogEmitter) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _VRFLogEmitter.abi.Events["RandomWordsFulfilled"].ID: + return _VRFLogEmitter.ParseRandomWordsFulfilled(log) + case _VRFLogEmitter.abi.Events["RandomWordsRequested"].ID: + return _VRFLogEmitter.ParseRandomWordsRequested(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (VRFLogEmitterRandomWordsFulfilled) Topic() common.Hash { + return common.HexToHash("0x7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4") +} + +func (VRFLogEmitterRandomWordsRequested) Topic() common.Hash { + return common.HexToHash("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772") +} + +func (_VRFLogEmitter *VRFLogEmitter) Address() common.Address { + return _VRFLogEmitter.address +} + +type VRFLogEmitterInterface interface { + EmitRandomWordsFulfilled(opts *bind.TransactOpts, requestId *big.Int, outputSeed *big.Int, payment *big.Int, success bool) (*types.Transaction, error) + + EmitRandomWordsRequested(opts *bind.TransactOpts, keyHash [32]byte, requestId *big.Int, preSeed *big.Int, subId uint64, minimumRequestConfirmations uint16, callbackGasLimit uint32, numWords uint32, sender common.Address) (*types.Transaction, error) + + FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int) (*VRFLogEmitterRandomWordsFulfilledIterator, error) + + WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *VRFLogEmitterRandomWordsFulfilled, requestId []*big.Int) (event.Subscription, error) + + ParseRandomWordsFulfilled(log types.Log) (*VRFLogEmitterRandomWordsFulfilled, error) + + FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subId []uint64, sender []common.Address) (*VRFLogEmitterRandomWordsRequestedIterator, error) + + WatchRandomWordsRequested(opts *bind.WatchOpts, sink chan<- *VRFLogEmitterRandomWordsRequested, keyHash [][32]byte, subId []uint64, sender []common.Address) (event.Subscription, error) + + ParseRandomWordsRequested(log types.Log) (*VRFLogEmitterRandomWordsRequested, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/vrf_mock_ethlink_aggregator/vrf_mock_ethlink_aggregator.go b/core/gethwrappers/generated/vrf_mock_ethlink_aggregator/vrf_mock_ethlink_aggregator.go new file mode 100644 index 00000000000..d6736acfb9b --- /dev/null +++ b/core/gethwrappers/generated/vrf_mock_ethlink_aggregator/vrf_mock_ethlink_aggregator.go @@ -0,0 +1,377 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package vrf_mock_ethlink_aggregator + +import ( + "errors" + "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" +) + +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +var VRFMockETHLINKAggregatorMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"_answer\",\"type\":\"int256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"answer\",\"outputs\":[{\"internalType\":\"int256\",\"name\":\"\",\"type\":\"int256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"description\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint80\",\"name\":\"_roundId\",\"type\":\"uint80\"}],\"name\":\"getRoundData\",\"outputs\":[{\"internalType\":\"uint80\",\"name\":\"roundId\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"ans\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"startedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint80\",\"name\":\"answeredInRound\",\"type\":\"uint80\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestRoundData\",\"outputs\":[{\"internalType\":\"uint80\",\"name\":\"roundId\",\"type\":\"uint80\"},{\"internalType\":\"int256\",\"name\":\"ans\",\"type\":\"int256\"},{\"internalType\":\"uint256\",\"name\":\"startedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"updatedAt\",\"type\":\"uint256\"},{\"internalType\":\"uint80\",\"name\":\"answeredInRound\",\"type\":\"uint80\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_blockTimestampDeduction\",\"type\":\"uint256\"}],\"name\":\"setBlockTimestampDeduction\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + Bin: "0x6080604052600060015534801561001557600080fd5b506040516103383803806103388339810160408190526100349161003c565b600055610055565b60006020828403121561004e57600080fd5b5051919050565b6102d4806100646000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c806385bb7d691161005b57806385bb7d69146100e65780639a6fc8f5146100ef578063f0ad37df14610139578063feaf968c1461014e57600080fd5b8063313ce5671461008257806354fd4d50146100965780637284e416146100a7575b600080fd5b604051601281526020015b60405180910390f35b60015b60405190815260200161008d565b604080518082018252601881527f5652464d6f636b4554484c494e4b41676772656761746f7200000000000000006020820152905161008d9190610216565b61009960005481565b6101026100fd3660046101e3565b610156565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a00161008d565b61014c6101473660046101ca565b600155565b005b610102610186565b6000806000806000600160005461016b6101b5565b6101736101b5565b9299919850965090945060019350915050565b6000806000806000600160005461019b6101b5565b6101a36101b5565b92989197509550909350600192509050565b6000600154426101c59190610289565b905090565b6000602082840312156101dc57600080fd5b5035919050565b6000602082840312156101f557600080fd5b813569ffffffffffffffffffff8116811461020f57600080fd5b9392505050565b600060208083528351808285015260005b8181101561024357858101830151858201604001528201610227565b81811115610255576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000828210156102c2577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b50039056fea164736f6c6343000806000a", +} + +var VRFMockETHLINKAggregatorABI = VRFMockETHLINKAggregatorMetaData.ABI + +var VRFMockETHLINKAggregatorBin = VRFMockETHLINKAggregatorMetaData.Bin + +func DeployVRFMockETHLINKAggregator(auth *bind.TransactOpts, backend bind.ContractBackend, _answer *big.Int) (common.Address, *types.Transaction, *VRFMockETHLINKAggregator, error) { + parsed, err := VRFMockETHLINKAggregatorMetaData.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(VRFMockETHLINKAggregatorBin), backend, _answer) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VRFMockETHLINKAggregator{address: address, abi: *parsed, VRFMockETHLINKAggregatorCaller: VRFMockETHLINKAggregatorCaller{contract: contract}, VRFMockETHLINKAggregatorTransactor: VRFMockETHLINKAggregatorTransactor{contract: contract}, VRFMockETHLINKAggregatorFilterer: VRFMockETHLINKAggregatorFilterer{contract: contract}}, nil +} + +type VRFMockETHLINKAggregator struct { + address common.Address + abi abi.ABI + VRFMockETHLINKAggregatorCaller + VRFMockETHLINKAggregatorTransactor + VRFMockETHLINKAggregatorFilterer +} + +type VRFMockETHLINKAggregatorCaller struct { + contract *bind.BoundContract +} + +type VRFMockETHLINKAggregatorTransactor struct { + contract *bind.BoundContract +} + +type VRFMockETHLINKAggregatorFilterer struct { + contract *bind.BoundContract +} + +type VRFMockETHLINKAggregatorSession struct { + Contract *VRFMockETHLINKAggregator + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type VRFMockETHLINKAggregatorCallerSession struct { + Contract *VRFMockETHLINKAggregatorCaller + CallOpts bind.CallOpts +} + +type VRFMockETHLINKAggregatorTransactorSession struct { + Contract *VRFMockETHLINKAggregatorTransactor + TransactOpts bind.TransactOpts +} + +type VRFMockETHLINKAggregatorRaw struct { + Contract *VRFMockETHLINKAggregator +} + +type VRFMockETHLINKAggregatorCallerRaw struct { + Contract *VRFMockETHLINKAggregatorCaller +} + +type VRFMockETHLINKAggregatorTransactorRaw struct { + Contract *VRFMockETHLINKAggregatorTransactor +} + +func NewVRFMockETHLINKAggregator(address common.Address, backend bind.ContractBackend) (*VRFMockETHLINKAggregator, error) { + abi, err := abi.JSON(strings.NewReader(VRFMockETHLINKAggregatorABI)) + if err != nil { + return nil, err + } + contract, err := bindVRFMockETHLINKAggregator(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VRFMockETHLINKAggregator{address: address, abi: abi, VRFMockETHLINKAggregatorCaller: VRFMockETHLINKAggregatorCaller{contract: contract}, VRFMockETHLINKAggregatorTransactor: VRFMockETHLINKAggregatorTransactor{contract: contract}, VRFMockETHLINKAggregatorFilterer: VRFMockETHLINKAggregatorFilterer{contract: contract}}, nil +} + +func NewVRFMockETHLINKAggregatorCaller(address common.Address, caller bind.ContractCaller) (*VRFMockETHLINKAggregatorCaller, error) { + contract, err := bindVRFMockETHLINKAggregator(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VRFMockETHLINKAggregatorCaller{contract: contract}, nil +} + +func NewVRFMockETHLINKAggregatorTransactor(address common.Address, transactor bind.ContractTransactor) (*VRFMockETHLINKAggregatorTransactor, error) { + contract, err := bindVRFMockETHLINKAggregator(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VRFMockETHLINKAggregatorTransactor{contract: contract}, nil +} + +func NewVRFMockETHLINKAggregatorFilterer(address common.Address, filterer bind.ContractFilterer) (*VRFMockETHLINKAggregatorFilterer, error) { + contract, err := bindVRFMockETHLINKAggregator(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VRFMockETHLINKAggregatorFilterer{contract: contract}, nil +} + +func bindVRFMockETHLINKAggregator(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := VRFMockETHLINKAggregatorMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFMockETHLINKAggregator.Contract.VRFMockETHLINKAggregatorCaller.contract.Call(opts, result, method, params...) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.VRFMockETHLINKAggregatorTransactor.contract.Transfer(opts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.VRFMockETHLINKAggregatorTransactor.contract.Transact(opts, method, params...) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFMockETHLINKAggregator.Contract.contract.Call(opts, result, method, params...) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.contract.Transfer(opts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.contract.Transact(opts, method, params...) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) Answer(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.contract.Call(opts, &out, "answer") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) Answer() (*big.Int, error) { + return _VRFMockETHLINKAggregator.Contract.Answer(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) Answer() (*big.Int, error) { + return _VRFMockETHLINKAggregator.Contract.Answer(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) Decimals(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.contract.Call(opts, &out, "decimals") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) Decimals() (uint8, error) { + return _VRFMockETHLINKAggregator.Contract.Decimals(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) Decimals() (uint8, error) { + return _VRFMockETHLINKAggregator.Contract.Decimals(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) Description(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.contract.Call(opts, &out, "description") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) Description() (string, error) { + return _VRFMockETHLINKAggregator.Contract.Description(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) Description() (string, error) { + return _VRFMockETHLINKAggregator.Contract.Description(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (GetRoundData, + + error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.contract.Call(opts, &out, "getRoundData", _roundId) + + outstruct := new(GetRoundData) + if err != nil { + return *outstruct, err + } + + outstruct.RoundId = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Ans = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + outstruct.StartedAt = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.UpdatedAt = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.AnsweredInRound = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) GetRoundData(_roundId *big.Int) (GetRoundData, + + error) { + return _VRFMockETHLINKAggregator.Contract.GetRoundData(&_VRFMockETHLINKAggregator.CallOpts, _roundId) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) GetRoundData(_roundId *big.Int) (GetRoundData, + + error) { + return _VRFMockETHLINKAggregator.Contract.GetRoundData(&_VRFMockETHLINKAggregator.CallOpts, _roundId) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) LatestRoundData(opts *bind.CallOpts) (LatestRoundData, + + error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.contract.Call(opts, &out, "latestRoundData") + + outstruct := new(LatestRoundData) + if err != nil { + return *outstruct, err + } + + outstruct.RoundId = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Ans = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + outstruct.StartedAt = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.UpdatedAt = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.AnsweredInRound = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) LatestRoundData() (LatestRoundData, + + error) { + return _VRFMockETHLINKAggregator.Contract.LatestRoundData(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) LatestRoundData() (LatestRoundData, + + error) { + return _VRFMockETHLINKAggregator.Contract.LatestRoundData(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCaller) Version(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFMockETHLINKAggregator.contract.Call(opts, &out, "version") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) Version() (*big.Int, error) { + return _VRFMockETHLINKAggregator.Contract.Version(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorCallerSession) Version() (*big.Int, error) { + return _VRFMockETHLINKAggregator.Contract.Version(&_VRFMockETHLINKAggregator.CallOpts) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorTransactor) SetBlockTimestampDeduction(opts *bind.TransactOpts, _blockTimestampDeduction *big.Int) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.contract.Transact(opts, "setBlockTimestampDeduction", _blockTimestampDeduction) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorSession) SetBlockTimestampDeduction(_blockTimestampDeduction *big.Int) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.SetBlockTimestampDeduction(&_VRFMockETHLINKAggregator.TransactOpts, _blockTimestampDeduction) +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregatorTransactorSession) SetBlockTimestampDeduction(_blockTimestampDeduction *big.Int) (*types.Transaction, error) { + return _VRFMockETHLINKAggregator.Contract.SetBlockTimestampDeduction(&_VRFMockETHLINKAggregator.TransactOpts, _blockTimestampDeduction) +} + +type GetRoundData struct { + RoundId *big.Int + Ans *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int +} +type LatestRoundData struct { + RoundId *big.Int + Ans *big.Int + StartedAt *big.Int + UpdatedAt *big.Int + AnsweredInRound *big.Int +} + +func (_VRFMockETHLINKAggregator *VRFMockETHLINKAggregator) Address() common.Address { + return _VRFMockETHLINKAggregator.address +} + +type VRFMockETHLINKAggregatorInterface interface { + Answer(opts *bind.CallOpts) (*big.Int, error) + + Decimals(opts *bind.CallOpts) (uint8, error) + + Description(opts *bind.CallOpts) (string, error) + + GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (GetRoundData, + + error) + + LatestRoundData(opts *bind.CallOpts) (LatestRoundData, + + error) + + Version(opts *bind.CallOpts) (*big.Int, error) + + SetBlockTimestampDeduction(opts *bind.TransactOpts, _blockTimestampDeduction *big.Int) (*types.Transaction, error) + + Address() common.Address +} diff --git a/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go b/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go index 8a17b64378e..333bb11562d 100644 --- a/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go +++ b/core/gethwrappers/generated/vrf_owner_test_consumer/vrf_owner_test_consumer.go @@ -31,15 +31,15 @@ var ( ) var VRFV2OwnerTestConsumerMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"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\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractVRFCoordinatorV2Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"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\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"subId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60a0604052600060055560006006556103e76007553480156200002157600080fd5b50604051620013cc380380620013cc8339810160408190526200004491620002bf565b6001600160601b0319606082901b166080523380600081620000ad5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000e057620000e08162000213565b5050600280546001600160a01b0319166001600160a01b0384169081179091556040805163288688f960e21b8152905191925063a21a23e49160048083019260209291908290030181600087803b1580156200013b57600080fd5b505af115801562000150573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001769190620002f1565b600280546001600160401b03928316600160a01b908102600160a01b600160e01b03198316811793849055604051631cd0704360e21b81529190930490931660048401523060248401526001600160a01b0391821691161790637341c10c90604401600060405180830381600087803b158015620001f357600080fd5b505af115801562000208573d6000803e3d6000fd5b50505050506200031c565b6001600160a01b0381163314156200026e5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000a4565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600060208284031215620002d257600080fd5b81516001600160a01b0381168114620002ea57600080fd5b9392505050565b6000602082840312156200030457600080fd5b81516001600160401b0381168114620002ea57600080fd5b60805160601c61108a62000342600039600081816103000152610368015261108a6000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063a168fa8911610097578063d8a4676f11610066578063d8a4676f14610262578063dc1670db14610287578063eb1d28bb14610290578063f2fde38b146102d557600080fd5b8063a168fa89146101bc578063ad603ea214610227578063b1e217491461023a578063d826f88f1461024357600080fd5b8063737144bc116100d3578063737144bc1461018457806374dba1241461018d57806379ba5097146101965780638da5cb5b1461019e57600080fd5b80631757f11c146101055780631fe543e3146101215780633b2bcbf114610136578063557d2e921461017b575b600080fd5b61010e60065481565b6040519081526020015b60405180910390f35b61013461012f366004610dc2565b6102e8565b005b6002546101569073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610118565b61010e60045481565b61010e60055481565b61010e60075481565b6101346103a8565b60005473ffffffffffffffffffffffffffffffffffffffff16610156565b6101fd6101ca366004610d90565b600a602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a001610118565b610134610235366004610d32565b6104a5565b61010e60085481565b6101346000600581905560068190556103e76007556004819055600355565b610275610270366004610d90565b610809565b60405161011896959493929190610eb1565b61010e60035481565b6002546102bc9074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610118565b6101346102e3366004610cf5565b6108ee565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461039a576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b6103a48282610902565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610429576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610391565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6104ad610a2d565b60005b8161ffff168161ffff1610156106ad576002546040517f5d3b1d300000000000000000000000000000000000000000000000000000000081526004810187905274010000000000000000000000000000000000000000820467ffffffffffffffff16602482015261ffff8816604482015263ffffffff80871660648301528516608482015260009173ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b15801561057257600080fd5b505af1158015610586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105aa9190610da9565b6008819055905060006105bb610ab0565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a08401839052878352600a815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169015151781559051805194955091939092610649926001850192910190610c6a565b506040820151600282015560608201516003820155608082015160048083019190915560a090920151600590910155805490600061068683610fe6565b909155505060009182526009602052604090912055806106a581610fc4565b9150506104b0565b506002546040517f9f87fad700000000000000000000000000000000000000000000000000000000815274010000000000000000000000000000000000000000820467ffffffffffffffff16600482015230602482015273ffffffffffffffffffffffffffffffffffffffff90911690639f87fad790604401600060405180830381600087803b15801561074057600080fd5b505af1158015610754573d6000803e3d6000fd5b50506002546040517fd7ae1d3000000000000000000000000000000000000000000000000000000000815274010000000000000000000000000000000000000000820467ffffffffffffffff16600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116925063d7ae1d309150604401600060405180830381600087803b1580156107ea57600080fd5b505af11580156107fe573d6000803e3d6000fd5b505050505050505050565b6000818152600a60209081526040808320815160c081018352815460ff161515815260018201805484518187028101870190955280855260609587958695869586958695919492938584019390929083018282801561088757602002820191906000526020600020905b815481526020019060010190808311610873575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b6108f6610a2d565b6108ff81610b4d565b50565b600061090c610ab0565b600084815260096020526040812054919250906109299083610fad565b9050600061093a82620f4240610f70565b905060065482111561094c5760068290555b600754821061095d5760075461095f565b815b60075560035461096f57806109a2565b60035461097d906001610f1d565b8160035460055461098e9190610f70565b6109989190610f1d565b6109a29190610f35565b6005556000858152600a6020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117825586516109f4939290910191870190610c6a565b506000858152600a60205260408120426003808301919091556005909101859055805491610a2183610fe6565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610aae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610391565b565b600046610abc81610c43565b15610b4657606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b0857600080fd5b505afa158015610b1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b409190610da9565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610bcd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610391565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b1821480610c57575062066eed82145b80610c64575062066eee82145b92915050565b828054828255906000526020600020908101928215610ca5579160200282015b82811115610ca5578251825591602001919060010190610c8a565b50610cb1929150610cb5565b5090565b5b80821115610cb15760008155600101610cb6565b803561ffff81168114610cdc57600080fd5b919050565b803563ffffffff81168114610cdc57600080fd5b600060208284031215610d0757600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610d2b57600080fd5b9392505050565b600080600080600060a08688031215610d4a57600080fd5b610d5386610cca565b945060208601359350610d6860408701610ce1565b9250610d7660608701610ce1565b9150610d8460808701610cca565b90509295509295909350565b600060208284031215610da257600080fd5b5035919050565b600060208284031215610dbb57600080fd5b5051919050565b60008060408385031215610dd557600080fd5b8235915060208084013567ffffffffffffffff80821115610df557600080fd5b818601915086601f830112610e0957600080fd5b813581811115610e1b57610e1b61104e565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f83011681018181108582111715610e5e57610e5e61104e565b604052828152858101935084860182860187018b1015610e7d57600080fd5b600095505b83861015610ea0578035855260019590950194938601938601610e82565b508096505050505050509250929050565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015610ef457845183529383019391830191600101610ed8565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b60008219821115610f3057610f3061101f565b500190565b600082610f6b577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610fa857610fa861101f565b500290565b600082821015610fbf57610fbf61101f565b500390565b600061ffff80831681811415610fdc57610fdc61101f565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156110185761101861101f565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_vrfCoordinator\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"have\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"want\",\"type\":\"address\"}],\"name\":\"OnlyCoordinatorCanFulfill\",\"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\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"consumer\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"SubscriptionCreatedFundedAndConsumerAdded\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"COORDINATOR\",\"outputs\":[{\"internalType\":\"contractVRFCoordinatorV2Interface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"LINKTOKEN\",\"outputs\":[{\"internalType\":\"contractLinkTokenInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"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\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"bytes32\",\"name\":\"_keyHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"},{\"internalType\":\"uint256\",\"name\":\"_subTopUpAmount\",\"type\":\"uint256\"}],\"name\":\"requestRandomWords\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"subId\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"topUpSubscription\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a0604052600060065560006007556103e76008553480156200002157600080fd5b50604051620016ee380380620016ee8339810160408190526200004491620001e2565b6001600160601b0319606083901b166080523380600081620000ad5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000e057620000e08162000119565b5050600280546001600160a01b039485166001600160a01b0319918216179091556003805493909416921691909117909155506200021a565b6001600160a01b038116331415620001745760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000a4565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001dd57600080fd5b919050565b60008060408385031215620001f657600080fd5b6200020183620001c5565b91506200021160208401620001c5565b90509250929050565b60805160601c6114ae620002406000396000818161036901526103d101526114ae6000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c80638da5cb5b116100b2578063d8a4676f11610081578063eb1d28bb11610066578063eb1d28bb146102e6578063f2fde38b1461032b578063f82d24381461033e57600080fd5b8063d8a4676f146102b8578063dc1670db146102dd57600080fd5b80638da5cb5b14610207578063a168fa8914610225578063b1e2174914610290578063d826f88f1461029957600080fd5b8063557d2e921161010957806374dba124116100ee57806374dba124146101e357806379ba5097146101ec57806386850e93146101f457600080fd5b8063557d2e92146101d1578063737144bc146101da57600080fd5b80631757f11c1461013b5780631fe543e3146101575780633b2bcbf11461016c57806355380dfb146101b1575b600080fd5b61014460075481565b6040519081526020015b60405180910390f35b61016a610165366004611124565b610351565b005b60025461018c9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161014e565b60035461018c9073ffffffffffffffffffffffffffffffffffffffff1681565b61014460055481565b61014460065481565b61014460085481565b61016a610411565b61016a6102023660046110f2565b61050e565b60005473ffffffffffffffffffffffffffffffffffffffff1661018c565b6102666102333660046110f2565b600b602052600090815260409020805460028201546003830154600484015460059094015460ff90931693919290919085565b6040805195151586526020860194909452928401919091526060830152608082015260a00161014e565b61014460095481565b61016a6000600681905560078190556103e76008556005819055600455565b6102cb6102c63660046110f2565b6105ea565b60405161014e969594939291906112d5565b61014460045481565b6003546103129074010000000000000000000000000000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff909116815260200161014e565b61016a61033936600461102d565b6106cf565b61016a61034c36600461108c565b6106e3565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610403576040517f1cf993f400000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b61040d8282610c3e565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610492576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064016103fa565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610516610d65565b6003546002546040805174010000000000000000000000000000000000000000840467ffffffffffffffff16602082015273ffffffffffffffffffffffffffffffffffffffff93841693634000aea09316918591016040516020818303038152906040526040518463ffffffff1660e01b81526004016105989392919061123d565b602060405180830381600087803b1580156105b257600080fd5b505af11580156105c6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061040d919061106a565b6000818152600b60209081526040808320815160c081018352815460ff161515815260018201805484518187028101870190955280855260609587958695869586958695919492938584019390929083018282801561066857602002820191906000526020600020905b815481526020019060010190808311610654575b505050505081526020016002820154815260200160038201548152602001600482015481526020016005820154815250509050806000015181602001518260400151836060015184608001518560a001519650965096509650965096505091939550919395565b6106d7610d65565b6106e081610de8565b50565b6106eb610d65565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a21a23e46040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561075557600080fd5b505af1158015610769573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061078d9190611213565b600380547fffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000067ffffffffffffffff938416810291909117918290556002546040517f7341c10c00000000000000000000000000000000000000000000000000000000815291909204909216600483015230602483015273ffffffffffffffffffffffffffffffffffffffff1690637341c10c90604401600060405180830381600087803b15801561085457600080fd5b505af1158015610868573d6000803e3d6000fd5b505050506108758161050e565b600354604080517401000000000000000000000000000000000000000090920467ffffffffffffffff16825230602083015281018290527f56c142509574e8340ca0190b029c74464b84037d2876278ea0ade3ffb1f0042c9060600160405180910390a160005b8261ffff168161ffff161015610ad9576002546003546040517f5d3b1d30000000000000000000000000000000000000000000000000000000008152600481018990527401000000000000000000000000000000000000000090910467ffffffffffffffff16602482015261ffff8916604482015263ffffffff80881660648301528616608482015260009173ffffffffffffffffffffffffffffffffffffffff1690635d3b1d309060a401602060405180830381600087803b1580156109a257600080fd5b505af11580156109b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109da919061110b565b6009819055905060006109eb610ede565b6040805160c08101825260008082528251818152602080820185528084019182524284860152606084018390526080840186905260a08401839052878352600b815293909120825181547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169015151781559051805194955091939092610a79926001850192910190610fa2565b5060408201516002820155606082015160038201556080820151600482015560a0909101516005918201558054906000610ab28361140a565b90915550506000918252600a60205260409091205580610ad1816113e8565b9150506108dc565b506002546003546040517f9f87fad70000000000000000000000000000000000000000000000000000000081527401000000000000000000000000000000000000000090910467ffffffffffffffff16600482015230602482015273ffffffffffffffffffffffffffffffffffffffff90911690639f87fad790604401600060405180830381600087803b158015610b7057600080fd5b505af1158015610b84573d6000803e3d6000fd5b50506002546003546040517fd7ae1d300000000000000000000000000000000000000000000000000000000081527401000000000000000000000000000000000000000090910467ffffffffffffffff16600482015233602482015273ffffffffffffffffffffffffffffffffffffffff909116925063d7ae1d309150604401600060405180830381600087803b158015610c1e57600080fd5b505af1158015610c32573d6000803e3d6000fd5b50505050505050505050565b6000610c48610ede565b6000848152600a602052604081205491925090610c6590836113d1565b90506000610c7682620f4240611394565b9050600754821115610c885760078290555b6008548210610c9957600854610c9b565b815b600855600454610cab5780610cde565b600454610cb9906001611341565b81600454600654610cca9190611394565b610cd49190611341565b610cde9190611359565b6006556000858152600b6020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811782558651610d30939290910191870190610fa2565b506000858152600b602052604081204260038201556005018490556004805491610d598361140a565b91905055505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610de6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e65720000000000000000000060448201526064016103fa565b565b73ffffffffffffffffffffffffffffffffffffffff8116331415610e68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c6600000000000000000060448201526064016103fa565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046610eea81610f7b565b15610f7457606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f3657600080fd5b505afa158015610f4a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f6e919061110b565b91505090565b4391505090565b600061a4b1821480610f8f575062066eed82145b80610f9c575062066eee82145b92915050565b828054828255906000526020600020908101928215610fdd579160200282015b82811115610fdd578251825591602001919060010190610fc2565b50610fe9929150610fed565b5090565b5b80821115610fe95760008155600101610fee565b803561ffff8116811461101457600080fd5b919050565b803563ffffffff8116811461101457600080fd5b60006020828403121561103f57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461106357600080fd5b9392505050565b60006020828403121561107c57600080fd5b8151801515811461106357600080fd5b60008060008060008060c087890312156110a557600080fd5b6110ae87611002565b9550602087013594506110c360408801611019565b93506110d160608801611019565b92506110df60808801611002565b915060a087013590509295509295509295565b60006020828403121561110457600080fd5b5035919050565b60006020828403121561111d57600080fd5b5051919050565b6000806040838503121561113757600080fd5b8235915060208084013567ffffffffffffffff8082111561115757600080fd5b818601915086601f83011261116b57600080fd5b81358181111561117d5761117d611472565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156111c0576111c0611472565b604052828152858101935084860182860187018b10156111df57600080fd5b600095505b838610156112025780358552600195909501949386019386016111e4565b508096505050505050509250929050565b60006020828403121561122557600080fd5b815167ffffffffffffffff8116811461106357600080fd5b73ffffffffffffffffffffffffffffffffffffffff8416815260006020848184015260606040840152835180606085015260005b8181101561128d57858101830151858201608001528201611271565b8181111561129f576000608083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160800195945050505050565b600060c082018815158352602060c08185015281895180845260e086019150828b01935060005b81811015611318578451835293830193918301916001016112fc565b505060408501989098525050506060810193909352608083019190915260a09091015292915050565b6000821982111561135457611354611443565b500190565b60008261138f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156113cc576113cc611443565b500290565b6000828210156113e3576113e3611443565b500390565b600061ffff8083168181141561140057611400611443565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561143c5761143c611443565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", } var VRFV2OwnerTestConsumerABI = VRFV2OwnerTestConsumerMetaData.ABI var VRFV2OwnerTestConsumerBin = VRFV2OwnerTestConsumerMetaData.Bin -func DeployVRFV2OwnerTestConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, _vrfCoordinator common.Address) (common.Address, *types.Transaction, *VRFV2OwnerTestConsumer, error) { +func DeployVRFV2OwnerTestConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, _vrfCoordinator common.Address, _link common.Address) (common.Address, *types.Transaction, *VRFV2OwnerTestConsumer, error) { parsed, err := VRFV2OwnerTestConsumerMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -48,7 +48,7 @@ func DeployVRFV2OwnerTestConsumer(auth *bind.TransactOpts, backend bind.Contract return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2OwnerTestConsumerBin), backend, _vrfCoordinator) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(VRFV2OwnerTestConsumerBin), backend, _vrfCoordinator, _link) if err != nil { return common.Address{}, nil, nil, err } @@ -193,6 +193,28 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerCallerSession) COORDINATOR( return _VRFV2OwnerTestConsumer.Contract.COORDINATOR(&_VRFV2OwnerTestConsumer.CallOpts) } +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerCaller) LINKTOKEN(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2OwnerTestConsumer.contract.Call(opts, &out, "LINKTOKEN") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerSession) LINKTOKEN() (common.Address, error) { + return _VRFV2OwnerTestConsumer.Contract.LINKTOKEN(&_VRFV2OwnerTestConsumer.CallOpts) +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerCallerSession) LINKTOKEN() (common.Address, error) { + return _VRFV2OwnerTestConsumer.Contract.LINKTOKEN(&_VRFV2OwnerTestConsumer.CallOpts) +} + func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) { @@ -460,16 +482,16 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactorSession) RawFulfi return _VRFV2OwnerTestConsumer.Contract.RawFulfillRandomWords(&_VRFV2OwnerTestConsumer.TransactOpts, requestId, randomWords) } -func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactor) RequestRandomWords(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { - return _VRFV2OwnerTestConsumer.contract.Transact(opts, "requestRandomWords", _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount) +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactor) RequestRandomWords(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.contract.Transact(opts, "requestRandomWords", _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount) } -func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerSession) RequestRandomWords(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { - return _VRFV2OwnerTestConsumer.Contract.RequestRandomWords(&_VRFV2OwnerTestConsumer.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount) +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerSession) RequestRandomWords(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.Contract.RequestRandomWords(&_VRFV2OwnerTestConsumer.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount) } -func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactorSession) RequestRandomWords(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { - return _VRFV2OwnerTestConsumer.Contract.RequestRandomWords(&_VRFV2OwnerTestConsumer.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount) +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactorSession) RequestRandomWords(_requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.Contract.RequestRandomWords(&_VRFV2OwnerTestConsumer.TransactOpts, _requestConfirmations, _keyHash, _callbackGasLimit, _numWords, _requestCount, _subTopUpAmount) } func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { @@ -484,6 +506,18 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactorSession) Reset() return _VRFV2OwnerTestConsumer.Contract.Reset(&_VRFV2OwnerTestConsumer.TransactOpts) } +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactor) TopUpSubscription(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.contract.Transact(opts, "topUpSubscription", amount) +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerSession) TopUpSubscription(amount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.Contract.TopUpSubscription(&_VRFV2OwnerTestConsumer.TransactOpts, amount) +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactorSession) TopUpSubscription(amount *big.Int) (*types.Transaction, error) { + return _VRFV2OwnerTestConsumer.Contract.TopUpSubscription(&_VRFV2OwnerTestConsumer.TransactOpts, amount) +} + func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { return _VRFV2OwnerTestConsumer.contract.Transact(opts, "transferOwnership", to) } @@ -768,6 +802,125 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerFilterer) ParseOwnershipTra return event, nil } +type VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator struct { + Event *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) + 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(VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) + 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 *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator) Error() error { + return it.fail +} + +func (it *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded struct { + SubId uint64 + Consumer common.Address + Amount *big.Int + Raw types.Log +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerFilterer) FilterSubscriptionCreatedFundedAndConsumerAdded(opts *bind.FilterOpts) (*VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator, error) { + + logs, sub, err := _VRFV2OwnerTestConsumer.contract.FilterLogs(opts, "SubscriptionCreatedFundedAndConsumerAdded") + if err != nil { + return nil, err + } + return &VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator{contract: _VRFV2OwnerTestConsumer.contract, event: "SubscriptionCreatedFundedAndConsumerAdded", logs: logs, sub: sub}, nil +} + +func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerFilterer) WatchSubscriptionCreatedFundedAndConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) (event.Subscription, error) { + + logs, sub, err := _VRFV2OwnerTestConsumer.contract.WatchLogs(opts, "SubscriptionCreatedFundedAndConsumerAdded") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) + if err := _VRFV2OwnerTestConsumer.contract.UnpackLog(event, "SubscriptionCreatedFundedAndConsumerAdded", 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 (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumerFilterer) ParseSubscriptionCreatedFundedAndConsumerAdded(log types.Log) (*VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded, error) { + event := new(VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) + if err := _VRFV2OwnerTestConsumer.contract.UnpackLog(event, "SubscriptionCreatedFundedAndConsumerAdded", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type GetRequestStatus struct { Fulfilled bool RandomWords []*big.Int @@ -790,6 +943,8 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumer) ParseLog(log types.Log) ( return _VRFV2OwnerTestConsumer.ParseOwnershipTransferRequested(log) case _VRFV2OwnerTestConsumer.abi.Events["OwnershipTransferred"].ID: return _VRFV2OwnerTestConsumer.ParseOwnershipTransferred(log) + case _VRFV2OwnerTestConsumer.abi.Events["SubscriptionCreatedFundedAndConsumerAdded"].ID: + return _VRFV2OwnerTestConsumer.ParseSubscriptionCreatedFundedAndConsumerAdded(log) default: return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) @@ -804,6 +959,10 @@ func (VRFV2OwnerTestConsumerOwnershipTransferred) Topic() common.Hash { return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") } +func (VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) Topic() common.Hash { + return common.HexToHash("0x56c142509574e8340ca0190b029c74464b84037d2876278ea0ade3ffb1f0042c") +} + func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumer) Address() common.Address { return _VRFV2OwnerTestConsumer.address } @@ -811,6 +970,8 @@ func (_VRFV2OwnerTestConsumer *VRFV2OwnerTestConsumer) Address() common.Address type VRFV2OwnerTestConsumerInterface interface { COORDINATOR(opts *bind.CallOpts) (common.Address, error) + LINKTOKEN(opts *bind.CallOpts) (common.Address, error) + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, error) @@ -839,10 +1000,12 @@ type VRFV2OwnerTestConsumerInterface interface { RawFulfillRandomWords(opts *bind.TransactOpts, requestId *big.Int, randomWords []*big.Int) (*types.Transaction, error) - RequestRandomWords(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16) (*types.Transaction, error) + RequestRandomWords(opts *bind.TransactOpts, _requestConfirmations uint16, _keyHash [32]byte, _callbackGasLimit uint32, _numWords uint32, _requestCount uint16, _subTopUpAmount *big.Int) (*types.Transaction, error) Reset(opts *bind.TransactOpts) (*types.Transaction, error) + TopUpSubscription(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2OwnerTestConsumerOwnershipTransferRequestedIterator, error) @@ -857,6 +1020,12 @@ type VRFV2OwnerTestConsumerInterface interface { ParseOwnershipTransferred(log types.Log) (*VRFV2OwnerTestConsumerOwnershipTransferred, error) + FilterSubscriptionCreatedFundedAndConsumerAdded(opts *bind.FilterOpts) (*VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAddedIterator, error) + + WatchSubscriptionCreatedFundedAndConsumerAdded(opts *bind.WatchOpts, sink chan<- *VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded) (event.Subscription, error) + + ParseSubscriptionCreatedFundedAndConsumerAdded(log types.Log) (*VRFV2OwnerTestConsumerSubscriptionCreatedFundedAndConsumerAdded, error) + ParseLog(log types.Log) (generated.AbigenLog, error) Address() common.Address 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 7aae3d37770..ae3b764b3ce 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 @@ -66,8 +66,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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"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\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"oracle\",\"type\":\"address\"}],\"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\":\"\",\"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\"}],\"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\":\"\",\"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\":\"owner\",\"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\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"addresspayable\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdrawNative\",\"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\":\"address\",\"name\":\"oracle\",\"type\":\"address\"},{\"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\"}],\"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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"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\"}]", - Bin: "0x60a06040523480156200001157600080fd5b50604051620061a6380380620061a6833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615fcb620001db600039600081816104a601526136530152615fcb6000f3fe6080604052600436106101e05760003560e01c8062012291146101e5578063088070f5146102125780630ae095401461029257806315c48b84146102b457806318e3dd27146102dc5780631b6b6d231461031b5780632949265714610348578063294daa4914610368578063330987b314610384578063405b84fa146103a457806340d6bb82146103c457806341af6c87146103ef5780635d06b4ab1461041f57806364d51a2a1461043f578063659827441461045457806366316d8d14610474578063689c4517146104945780636f64f03f146104c857806372e9d565146104e857806379ba5097146105085780638402595e1461051d57806386fe91c71461053d5780638da5cb5b1461055d57806395b55cfc1461057b5780639b1c385e1461058e5780639d40a6fd146105bc578063a21a23e4146105e9578063a4c0ed36146105fe578063aa433aff1461061e578063aefb212f1461063e578063b08c87951461066b578063b2a7cac51461068b578063bec4c08c146106ab578063caf70c4a146106cb578063cb631797146106eb578063ce3f47191461070b578063d98e620e1461071e578063dac83d291461073e578063dc311dd31461075e578063e72f6e301461078f578063ee9d2d38146107af578063f2fde38b146107dc575b600080fd5b3480156101f157600080fd5b506101fa6107fc565b60405161020993929190615a56565b60405180910390f35b34801561021e57600080fd5b50600d5461025a9061ffff81169063ffffffff62010000820481169160ff600160301b82041691600160381b8204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610209565b34801561029e57600080fd5b506102b26102ad3660046156c9565b610878565b005b3480156102c057600080fd5b506102c960c881565b60405161ffff9091168152602001610209565b3480156102e857600080fd5b50600a5461030390600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610209565b34801561032757600080fd5b5060025461033b906001600160a01b031681565b60405161020991906158fa565b34801561035457600080fd5b506102b261036336600461523b565b610946565b34801561037457600080fd5b5060405160028152602001610209565b34801561039057600080fd5b5061030361039f36600461541e565b610ac3565b3480156103b057600080fd5b506102b26103bf3660046156c9565b610f9e565b3480156103d057600080fd5b506103da6101f481565b60405163ffffffff9091168152602001610209565b3480156103fb57600080fd5b5061040f61040a3660046156b0565b611389565b6040519015158152602001610209565b34801561042b57600080fd5b506102b261043a36600461521e565b61152a565b34801561044b57600080fd5b506102c9606481565b34801561046057600080fd5b506102b261046f366004615270565b6115e1565b34801561048057600080fd5b506102b261048f36600461523b565b611641565b3480156104a057600080fd5b5061033b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d457600080fd5b506102b26104e33660046152a9565b611809565b3480156104f457600080fd5b5060035461033b906001600160a01b031681565b34801561051457600080fd5b506102b2611910565b34801561052957600080fd5b506102b261053836600461521e565b6119ba565b34801561054957600080fd5b50600a54610303906001600160601b031681565b34801561056957600080fd5b506000546001600160a01b031661033b565b6102b26105893660046156b0565b611ac6565b34801561059a57600080fd5b506105ae6105a93660046154fb565b611c0a565b604051908152602001610209565b3480156105c857600080fd5b506007546105dc906001600160401b031681565b6040516102099190615bef565b3480156105f557600080fd5b506105ae611f7a565b34801561060a57600080fd5b506102b26106193660046152e5565b6121c8565b34801561062a57600080fd5b506102b26106393660046156b0565b612365565b34801561064a57600080fd5b5061065e6106593660046156ee565b6123c8565b6040516102099190615971565b34801561067757600080fd5b506102b2610686366004615612565b6124c9565b34801561069757600080fd5b506102b26106a63660046156b0565b61263d565b3480156106b757600080fd5b506102b26106c63660046156c9565b612761565b3480156106d757600080fd5b506105ae6106e6366004615340565b6128f8565b3480156106f757600080fd5b506102b26107063660046156c9565b612928565b6102b2610719366004615392565b612c15565b34801561072a57600080fd5b506105ae6107393660046156b0565b612f26565b34801561074a57600080fd5b506102b26107593660046156c9565b612f47565b34801561076a57600080fd5b5061077e6107793660046156b0565b613057565b604051610209959493929190615c03565b34801561079b57600080fd5b506102b26107aa36600461521e565b613152565b3480156107bb57600080fd5b506105ae6107ca3660046156b0565b60106020526000908152604090205481565b3480156107e857600080fd5b506102b26107f736600461521e565b61332d565b600d54600f805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561086657602002820191906000526020600020905b815481526020019060010190808311610852575b50505050509050925092509250909192565b60008281526005602052604090205482906001600160a01b0316806108b057604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146108e45780604051636c51fda960e11b81526004016108db91906158fa565b60405180910390fd5b600d54600160301b900460ff161561090f5760405163769dd35360e11b815260040160405180910390fd5b61091884611389565b1561093657604051631685ecdd60e31b815260040160405180910390fd5b610940848461333e565b50505050565b600d54600160301b900460ff16156109715760405163769dd35360e11b815260040160405180910390fd5b336000908152600c60205260409020546001600160601b03808316911610156109ad57604051631e9acf1760e31b815260040160405180910390fd5b336000908152600c6020526040812080548392906109d59084906001600160601b0316615e0b565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610a1d9190615e0b565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610a97576040519150601f19603f3d011682016040523d82523d6000602084013e610a9c565b606091505b5050905080610abe5760405163950b247960e01b815260040160405180910390fd5b505050565b600d54600090600160301b900460ff1615610af15760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610b0285856134f9565b90506000846060015163ffffffff166001600160401b03811115610b2857610b28615f3d565b604051908082528060200260200182016040528015610b51578160200160208202803683370190505b50905060005b856060015163ffffffff16811015610bc857826040015181604051602001610b80929190615984565b6040516020818303038152906040528051906020012060001c828281518110610bab57610bab615f27565b602090810291909101015280610bc081615e8f565b915050610b57565b5060208083018051600090815260109092526040808320839055905190518291631fe543e360e01b91610c0091908690602401615ae0565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600d805460ff60301b1916600160301b179055908801516080890151919250600091610c659163ffffffff16908461376c565b600d805460ff60301b19169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b0316610ca5816001615d7d565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a01518051610cf290600190615df4565b81518110610d0257610d02615f27565b602091010151600d5460f89190911c6001149150600090610d33908a90600160581b900463ffffffff163a856137ba565b90508115610e3c576020808c01516000908152600690915260409020546001600160601b03808316600160601b909204161015610d8357604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c90610dba908490600160601b90046001600160601b0316615e0b565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600c909152812080548594509092610e1391859116615d9f565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550610f28565b6020808c01516000908152600690915260409020546001600160601b0380831691161015610e7d57604051631e9acf1760e31b815260040160405180910390fd5b6020808c015160009081526006909152604081208054839290610eaa9084906001600160601b0316615e0b565b82546101009290920a6001600160601b0381810219909316918316021790915589516000908152600e60209081526040808320546001600160a01b03168352600b909152812080548594509092610f0391859116615d9f565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051610f85939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600d54600160301b900460ff1615610fc95760405163769dd35360e11b815260040160405180910390fd5b610fd281613809565b610ff15780604051635428d44960e01b81526004016108db91906158fa565b60008060008061100086613057565b945094505093509350336001600160a01b0316826001600160a01b0316146110635760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b60448201526064016108db565b61106c86611389565b156110b25760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b60448201526064016108db565b60006040518060c001604052806110c7600290565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b0316815250905060008160405160200161111b91906159c3565b604051602081830303815290604052905061113588613873565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b0388169061116e9085906004016159b0565b6000604051808303818588803b15801561118757600080fd5b505af115801561119b573d6000803e3d6000fd5b50506002546001600160a01b0316158015935091506111c4905057506001600160601b03861615155b1561128e5760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906111fb908a908a90600401615941565b602060405180830381600087803b15801561121557600080fd5b505af1158015611229573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124d919061535c565b61128e5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b60448201526064016108db565b600d805460ff60301b1916600160301b17905560005b8351811015611337578381815181106112bf576112bf615f27565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b81526004016112f291906158fa565b600060405180830381600087803b15801561130c57600080fd5b505af1158015611320573d6000803e3d6000fd5b50505050808061132f90615e8f565b9150506112a4565b50600d805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be4187906113779089908b9061590e565b60405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561141357602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113f5575b505050505081525050905060005b8160400151518110156115205760005b600f5481101561150d5760006114d6600f838154811061145357611453615f27565b90600052602060002001548560400151858151811061147457611474615f27565b602002602001015188600460008960400151898151811061149757611497615f27565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208d82529092529020546001600160401b0316613ac1565b50600081815260106020526040902054909150156114fa5750600195945050505050565b508061150581615e8f565b915050611431565b508061151881615e8f565b915050611421565b5060009392505050565b611532613b4a565b61153b81613809565b1561155b578060405163ac8a27ef60e01b81526004016108db91906158fa565b601380546001810182556000919091527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af01625906115d69083906158fa565b60405180910390a150565b6115e9613b4a565b6002546001600160a01b03161561161357604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b600d54600160301b900460ff161561166c5760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b03166116955760405163c1f0c0a160e01b815260040160405180910390fd5b336000908152600b60205260409020546001600160601b03808316911610156116d157604051631e9acf1760e31b815260040160405180910390fd5b336000908152600b6020526040812080548392906116f99084906001600160601b0316615e0b565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b03166117419190615e0b565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906117969085908590600401615941565b602060405180830381600087803b1580156117b057600080fd5b505af11580156117c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e8919061535c565b61180557604051631e9acf1760e31b815260040160405180910390fd5b5050565b611811613b4a565b6040805180820182526000916118409190849060029083908390808284376000920191909152506128f8915050565b6000818152600e60205260409020549091506001600160a01b03161561187c57604051634a0b8fa760e01b8152600481018290526024016108db565b6000818152600e6020908152604080832080546001600160a01b0319166001600160a01b038816908117909155600f805460018101825594527f8d1108e10bcb7c27dddfc02ed9d693a074039d026cf4ea4240b40f7d581ac802909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b8910160405180910390a2505050565b6001546001600160a01b031633146119635760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b60448201526064016108db565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6119c2613b4a565b600a544790600160601b90046001600160601b0316818111156119fc5780826040516354ced18160e11b81526004016108db929190615984565b81811015610abe576000611a108284615df4565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611a5f576040519150601f19603f3d011682016040523d82523d6000602084013e611a64565b606091505b5050905080611a865760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c8583604051611ab792919061590e565b60405180910390a15050505050565b600d54600160301b900460ff1615611af15760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316611b2657604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611b558385615d9f565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611b9d9190615d9f565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e902823484611bf09190615d65565b604051611bfe929190615984565b60405180910390a25050565b600d54600090600160301b900460ff1615611c385760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b0316611c7357604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b031680611cc0578260200135336040516379bfd40160e01b81526004016108db929190615ab5565b600d5461ffff16611cd760608501604086016155f7565b61ffff161080611cfa575060c8611cf460608501604086016155f7565b61ffff16115b15611d3457611d0f60608401604085016155f7565b600d5460405163539c34bb60e11b81526108db929161ffff169060c890600401615a38565b600d5462010000900463ffffffff16611d536080850160608601615710565b63ffffffff161115611d9957611d6f6080840160608501615710565b600d54604051637aebf00f60e11b81526108db929162010000900463ffffffff1690600401615bd8565b6101f4611dac60a0850160808601615710565b63ffffffff161115611de657611dc860a0840160808501615710565b6101f46040516311ce1afb60e21b81526004016108db929190615bd8565b6000611df3826001615d7d565b9050600080611e09863533602089013586613ac1565b90925090506000611e25611e2060a0890189615c58565b613b9f565b90506000611e3282613c1c565b905083611e3d613c8d565b60208a0135611e5260808c0160608d01615710565b611e6260a08d0160808e01615710565b3386604051602001611e7a9796959493929190615b38565b604051602081830303815290604052805190602001206010600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d6040016020810190611ef191906155f7565b8e6060016020810190611f049190615710565b8f6080016020810190611f179190615710565b89604051611f2a96959493929190615af9565b60405180910390a45050336000908152600460209081526040808320898301358452909152902080546001600160401b0319166001600160401b039490941693909317909255925050505b919050565b600d54600090600160301b900460ff1615611fa85760405163769dd35360e11b815260040160405180910390fd5b600033611fb6600143615df4565b600754604051606093841b6001600160601b03199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b0390911690600061203083615eaa565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561206f5761206f615f3d565b604051908082528060200260200182016040528015612098578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b0392831617835592516001830180549094169116179091559251805194955090936121799260028501920190614e8f565b5061218991506008905083613d1d565b50817f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d336040516121ba91906158fa565b60405180910390a250905090565b600d54600160301b900460ff16156121f35760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b0316331461221e576040516344b0e3c360e01b815260040160405180910390fd5b6020811461223f57604051638129bbcd60e01b815260040160405180910390fd5b600061224d828401846156b0565b6000818152600560205260409020549091506001600160a01b031661228557604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b0316918691906122ac8385615d9f565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166122f49190615d9f565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846123479190615d65565b604051612355929190615984565b60405180910390a2505050505050565b61236d613b4a565b6000818152600560205260409020546001600160a01b03166123a257604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020546123c59082906001600160a01b031661333e565b50565b606060006123d66008613d29565b90508084106123f857604051631390f2a160e01b815260040160405180910390fd5b60006124048486615d65565b905081811180612412575083155b61241c578061241e565b815b9050600061242c8683615df4565b6001600160401b0381111561244357612443615f3d565b60405190808252806020026020018201604052801561246c578160200160208202803683370190505b50905060005b81518110156124bf576124906124888883615d65565b600890613d33565b8282815181106124a2576124a2615f27565b6020908102919091010152806124b781615e8f565b915050612472565b5095945050505050565b6124d1613b4a565b60c861ffff871611156124fe57858660c860405163539c34bb60e11b81526004016108db93929190615a38565b60008213612522576040516321ea67b360e11b8152600481018390526024016108db565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600d805465ffffffffffff1916881762010000870217600160301b600160781b031916600160381b850263ffffffff60581b191617600160581b83021790558a51601280548d8701519289166001600160401b031990911617600160201b92891692909202919091179081905560118d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600d54600160301b900460ff16156126685760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b031661269d57604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b031633146126f4576000818152600560205260409081902060010154905163d084e97560e01b81526108db916001600160a01b0316906004016158fa565b6000818152600560205260409081902080546001600160a01b031980821633908117845560019093018054909116905591516001600160a01b039092169183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691611bfe918591615927565b60008281526005602052604090205482906001600160a01b03168061279957604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146127c45780604051636c51fda960e11b81526004016108db91906158fa565b600d54600160301b900460ff16156127ef5760405163769dd35360e11b815260040160405180910390fd5b60008481526005602052604090206002015460641415612822576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b03161561285957610940565b6001600160a01b0383166000818152600460209081526040808320888452825280832080546001600160401b031916600190811790915560058352818420600201805491820181558452919092200180546001600160a01b0319169092179091555184907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e1906128ea9086906158fa565b60405180910390a250505050565b60008160405160200161290b9190615963565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b03168061296057604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461298b5780604051636c51fda960e11b81526004016108db91906158fa565b600d54600160301b900460ff16156129b65760405163769dd35360e11b815260040160405180910390fd5b6129bf84611389565b156129dd57604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b0316612a2b5783836040516379bfd40160e01b81526004016108db929190615ab5565b600084815260056020908152604080832060020180548251818502810185019093528083529192909190830182828015612a8e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a70575b50505050509050600060018251612aa59190615df4565b905060005b8251811015612bb157856001600160a01b0316838281518110612acf57612acf615f27565b60200260200101516001600160a01b03161415612b9f576000838381518110612afa57612afa615f27565b6020026020010151905080600560008a81526020019081526020016000206002018381548110612b2c57612b2c615f27565b600091825260208083209190910180546001600160a01b0319166001600160a01b039490941693909317909255898152600590915260409020600201805480612b7757612b77615f11565b600082815260209020810160001990810180546001600160a01b031916905501905550612bb1565b80612ba981615e8f565b915050612aaa565b506001600160a01b03851660009081526004602090815260408083208984529091529081902080546001600160401b03191690555186907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a7906123559088906158fa565b6000612c2382840184615535565b9050806000015160ff16600114612c5c57805160405163237d181f60e21b815260ff9091166004820152600160248201526044016108db565b8060a001516001600160601b03163414612ca05760a08101516040516306acf13560e41b81523460048201526001600160601b0390911660248201526044016108db565b6020808201516000908152600590915260409020546001600160a01b031615612cdc576040516326afa43560e11b815260040160405180910390fd5b60005b816060015151811015612d7c5760016004600084606001518481518110612d0857612d08615f27565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008460200151815260200190815260200160002060006101000a8154816001600160401b0302191690836001600160401b031602179055508080612d7490615e8f565b915050612cdf565b50604080516060808201835260808401516001600160601b03908116835260a0850151811660208085019182526000858701818152828901805183526006845288832097518854955192516001600160401b0316600160c01b026001600160c01b03938816600160601b026001600160c01b0319909716919097161794909417169390931790945584518084018652868601516001600160a01b03908116825281860184815294880151828801908152925184526005865295909220825181549087166001600160a01b0319918216178255935160018201805491909716941693909317909455925180519192612e7b92600285019290910190614e8f565b5050506080810151600a8054600090612e9e9084906001600160601b0316615d9f565b92506101000a8154816001600160601b0302191690836001600160601b031602179055508060a00151600a600c8282829054906101000a90046001600160601b0316612eea9190615d9f565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555061094081602001516008613d1d90919063ffffffff16565b600f8181548110612f3657600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b031680612f7f57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612faa5780604051636c51fda960e11b81526004016108db91906158fa565b600d54600160301b900460ff1615612fd55760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610940576000848152600560205260409081902060010180546001600160a01b0319166001600160a01b0386161790555184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a1906128ea9033908790615927565b6000818152600560205260408120548190819081906060906001600160a01b031661309557604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b039094169391839183018282801561313857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161311a575b505050505090509450945094509450945091939590929450565b61315a613b4a565b6002546001600160a01b03166131835760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a08231906131b49030906004016158fa565b60206040518083038186803b1580156131cc57600080fd5b505afa1580156131e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132049190615379565b600a549091506001600160601b0316818111156132385780826040516354ced18160e11b81526004016108db929190615984565b81811015610abe57600061324c8284615df4565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb9061327f908790859060040161590e565b602060405180830381600087803b15801561329957600080fd5b505af11580156132ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132d1919061535c565b6132ee57604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600848260405161331f92919061590e565b60405180910390a150505050565b613335613b4a565b6123c581613d3f565b60008061334a84613873565b60025491935091506001600160a01b03161580159061337157506001600160601b03821615155b156134205760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906133b19086906001600160601b0387169060040161590e565b602060405180830381600087803b1580156133cb57600080fd5b505af11580156133df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613403919061535c565b61342057604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613476576040519150601f19603f3d011682016040523d82523d6000602084013e61347b565b606091505b505090508061349d5760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b6040805160608101825260008082526020820181905291810191909152600061352584600001516128f8565b6000818152600e60205260409020549091506001600160a01b03168061356157604051631dfd6e1360e21b8152600481018390526024016108db565b600082866080015160405160200161357a929190615984565b60408051601f19818403018152918152815160209283012060008181526010909352912054909150806135c057604051631b44092560e11b815260040160405180910390fd5b85516020808801516040808a015160608b015160808c015160a08d015193516135ef978a979096959101615b84565b6040516020818303038152906040528051906020012081146136245760405163354a450b60e21b815260040160405180910390fd5b60006136338760000151613de3565b9050806136fa578651604051631d2827a760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163e9413d38916136879190600401615bef565b60206040518083038186803b15801561369f57600080fd5b505afa1580156136b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136d79190615379565b9050806136fa57865160405163175dadad60e01b81526108db9190600401615bef565b600088608001518260405160200161371c929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006137438a83613ec0565b604080516060810182529889526020890196909652948701949094525093979650505050505050565b60005a61138881101561377e57600080fd5b61138881039050846040820482031161379657600080fd5b50823b6137a257600080fd5b60008083516020850160008789f190505b9392505050565b600081156137e7576012546137e09086908690600160201b900463ffffffff1686613f2b565b9050613801565b6012546137fe908690869063ffffffff1686613fcd565b90505b949350505050565b6000805b60135481101561386a57826001600160a01b03166013828154811061383457613834615f27565b6000918252602090912001546001600160a01b031614156138585750600192915050565b8061386281615e8f565b91505061380d565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879687969495948601939192908301828280156138ff57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116138e1575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b8260400151518110156139db57600460008460400151838151811061398b5761398b615f27565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120898252909252902080546001600160401b0319169055806139d381615e8f565b915050613964565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613a136002830182614ef4565b5050600085815260066020526040812055613a2f6008866140f2565b50600a8054859190600090613a4e9084906001600160601b0316615e0b565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613a969190615e0b565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b60408051602081018690526001600160a01b03851691810191909152606081018390526001600160401b03821660808201526000908190819060a00160408051601f198184030181529082905280516020918201209250613b26918991849101615984565b60408051808303601f19018152919052805160209091012097909650945050505050565b6000546001600160a01b03163314613b9d5760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b60448201526064016108db565b565b60408051602081019091526000815281613bc85750604080516020810190915260008152610f98565b63125fa26760e31b613bda8385615e33565b6001600160e01b03191614613c0257604051632923fee760e11b815260040160405180910390fd5b613c0f8260048186615d3b565b8101906137b391906153d3565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613c5591511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b600046613c99816140fe565b15613d165760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613cd857600080fd5b505afa158015613cec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d109190615379565b91505090565b4391505090565b60006137b38383614121565b6000610f98825490565b60006137b38383614170565b6001600160a01b038116331415613d925760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b60448201526064016108db565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613def816140fe565b15613eb157610100836001600160401b0316613e09613c8d565b613e139190615df4565b1180613e2f5750613e22613c8d565b836001600160401b031610155b15613e3d5750600092915050565b6040516315a03d4160e11b8152606490632b407a8290613e61908690600401615bef565b60206040518083038186803b158015613e7957600080fd5b505afa158015613e8d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137b39190615379565b50506001600160401b03164090565b6000613ef48360000151846020015185604001518660600151868860a001518960c001518a60e001518b610100015161419a565b60038360200151604051602001613f0c929190615acc565b60408051601f1981840301815291905280516020909101209392505050565b600080613f6e6000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506143b592505050565b905060005a613f7d8888615d65565b613f879190615df4565b613f919085615dd5565b90506000613faa63ffffffff871664e8d4a51000615dd5565b905082613fb78284615d65565b613fc19190615d65565b98975050505050505050565b600080613fd861447a565b905060008113613ffe576040516321ea67b360e11b8152600481018290526024016108db565b60006140406000368080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506143b592505050565b9050600082825a6140518b8b615d65565b61405b9190615df4565b6140659088615dd5565b61406f9190615d65565b61408190670de0b6b3a7640000615dd5565b61408b9190615dc1565b905060006140a463ffffffff881664e8d4a51000615dd5565b90506140bb81676765c793fa10079d601b1b615df4565b8211156140db5760405163e80fa38160e01b815260040160405180910390fd5b6140e58183615d65565b9998505050505050505050565b60006137b38383614545565b600061a4b1821480614112575062066eed82145b80610f9857505062066eee1490565b600081815260018301602052604081205461416857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610f98565b506000610f98565b600082600001828154811061418757614187615f27565b9060005260206000200154905092915050565b6141a389614638565b6141ec5760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b60448201526064016108db565b6141f588614638565b6142395760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b60448201526064016108db565b61424283614638565b61428e5760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e20637572766500000060448201526064016108db565b61429782614638565b6142e25760405162461bcd60e51b815260206004820152601c60248201527b73486173685769746e657373206973206e6f74206f6e20637572766560201b60448201526064016108db565b6142ee878a88876146fb565b6143365760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b60448201526064016108db565b60006143428a8761480f565b90506000614355898b878b868989614873565b90506000614366838d8d8a86614986565b9050808a146143a75760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b60448201526064016108db565b505050505050505050505050565b6000466143c1816140fe565b1561440057606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b158015613e7957600080fd5b614409816149c6565b1561386a57600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615f776048913960405160200161444f929190615850565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613e6191906159b0565b600d5460035460408051633fabe5a360e21b81529051600093600160381b900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b1580156144d857600080fd5b505afa1580156144ec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614510919061572b565b509450909250849150508015614534575061452b8242615df4565b8463ffffffff16105b156138015750601154949350505050565b6000818152600183016020526040812054801561462e576000614569600183615df4565b855490915060009061457d90600190615df4565b90508181146145e257600086600001828154811061459d5761459d615f27565b90600052602060002001549050808760000184815481106145c0576145c0615f27565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806145f3576145f3615f11565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610f98565b6000915050610f98565b80516000906401000003d019116146865760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b60448201526064016108db565b60208201516401000003d019116146d45760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b60448201526064016108db565b60208201516401000003d0199080096146f48360005b6020020151614a00565b1492915050565b60006001600160a01b0382166147415760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b60448201526064016108db565b60208401516000906001161561475857601c61475b565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe19918203925060009190890987516040805160008082526020909101918290529293506001916147c591869188918790615992565b6020604051602081039080840390855afa1580156147e7573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b614817614f12565b61484460018484604051602001614830939291906158d9565b604051602081830303815290604052614a24565b90505b61485081614638565b610f9857805160408051602081019290925261486c9101614830565b9050614847565b61487b614f12565b825186516401000003d01990819006910614156148da5760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e6374000060448201526064016108db565b6148e5878988614a72565b61492a5760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b60448201526064016108db565b614935848685614a72565b61497b5760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b60448201526064016108db565b613fc1868484614b8d565b6000600286868685876040516020016149a49695949392919061587f565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a8214806149d857506101a482145b806149e5575062aa37dc82145b806149f1575061210582145b80610f9857505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b614a2c614f12565b614a3582614c50565b8152614a4a614a458260006146ea565b614c8b565b602082018190526002900660011415611f75576020810180516401000003d019039052919050565b600082614aaf5760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b60448201526064016108db565b83516020850151600090614ac590600290615ed1565b15614ad157601c614ad4565b601b5b9050600070014551231950b75fc4402da1732fc9bebe19838709604080516000808252602090910191829052919250600190614b17908390869088908790615992565b6020604051602081039080840390855afa158015614b39573d6000803e3d6000fd5b505050602060405103519050600086604051602001614b58919061583e565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614b95614f12565b835160208086015185519186015160009384938493614bb693909190614cab565b919450925090506401000003d019858209600114614c125760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b60448201526064016108db565b60405180604001604052806401000003d01980614c3157614c31615efb565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d0198110611f7557604080516020808201939093528151808203840181529082019091528051910120614c58565b6000610f98826002614ca46401000003d0196001615d65565b901c614d8b565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614ceb83838585614e22565b9098509050614cfc88828e88614e46565b9098509050614d0d88828c87614e46565b90985090506000614d208d878b85614e46565b9098509050614d3188828686614e22565b9098509050614d4288828e89614e46565b9098509050818114614d77576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614d7b565b8196505b5050505050509450945094915050565b600080614d96614f30565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614dc8614f4e565b60208160c0846005600019fa925082614e185760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b60448201526064016108db565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614ee4579160200282015b82811115614ee457825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614eaf565b50614ef0929150614f6c565b5090565b50805460008255906000526020600020908101906123c59190614f6c565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614ef05760008155600101614f6d565b8035611f7581615f53565b600082601f830112614f9d57600080fd5b813560206001600160401b03821115614fb857614fb8615f3d565b8160051b614fc7828201615d0b565b838152828101908684018388018501891015614fe257600080fd5b600093505b8584101561500e578035614ffa81615f53565b835260019390930192918401918401614fe7565b50979650505050505050565b600082601f83011261502b57600080fd5b615033615c9e565b80838560408601111561504557600080fd5b60005b6002811015615067578135845260209384019390910190600101615048565b509095945050505050565b60008083601f84011261508457600080fd5b5081356001600160401b0381111561509b57600080fd5b6020830191508360208285010111156150b357600080fd5b9250929050565b600082601f8301126150cb57600080fd5b81356001600160401b038111156150e4576150e4615f3d565b6150f7601f8201601f1916602001615d0b565b81815284602083860101111561510c57600080fd5b816020850160208301376000918101602001919091529392505050565b600060c0828403121561513b57600080fd5b615143615cc6565b905081356001600160401b03808216821461515d57600080fd5b81835260208401356020840152615176604085016151dc565b6040840152615187606085016151dc565b606084015261519860808501614f81565b608084015260a08401359150808211156151b157600080fd5b506151be848285016150ba565b60a08301525092915050565b803561ffff81168114611f7557600080fd5b803563ffffffff81168114611f7557600080fd5b80516001600160501b0381168114611f7557600080fd5b80356001600160601b0381168114611f7557600080fd5b60006020828403121561523057600080fd5b81356137b381615f53565b6000806040838503121561524e57600080fd5b823561525981615f53565b915061526760208401615207565b90509250929050565b6000806040838503121561528357600080fd5b823561528e81615f53565b9150602083013561529e81615f53565b809150509250929050565b600080606083850312156152bc57600080fd5b82356152c781615f53565b9150606083018410156152d957600080fd5b50926020919091019150565b600080600080606085870312156152fb57600080fd5b843561530681615f53565b93506020850135925060408501356001600160401b0381111561532857600080fd5b61533487828801615072565b95989497509550505050565b60006040828403121561535257600080fd5b6137b3838361501a565b60006020828403121561536e57600080fd5b81516137b381615f68565b60006020828403121561538b57600080fd5b5051919050565b600080602083850312156153a557600080fd5b82356001600160401b038111156153bb57600080fd5b6153c785828601615072565b90969095509350505050565b6000602082840312156153e557600080fd5b604051602081016001600160401b038111828210171561540757615407615f3d565b604052823561541581615f68565b81529392505050565b6000808284036101c081121561543357600080fd5b6101a08082121561544357600080fd5b61544b615ce8565b9150615457868661501a565b8252615466866040870161501a565b60208301526080850135604083015260a0850135606083015260c0850135608083015261549560e08601614f81565b60a08301526101006154a98782880161501a565b60c08401526154bc87610140880161501a565b60e0840152610180860135908301529092508301356001600160401b038111156154e557600080fd5b6154f185828601615129565b9150509250929050565b60006020828403121561550d57600080fd5b81356001600160401b0381111561552357600080fd5b820160c081850312156137b357600080fd5b60006020828403121561554757600080fd5b81356001600160401b038082111561555e57600080fd5b9083019060c0828603121561557257600080fd5b61557a615cc6565b823560ff8116811461558b57600080fd5b8152602083810135908201526155a360408401614f81565b60408201526060830135828111156155ba57600080fd5b6155c687828601614f8c565b6060830152506155d860808401615207565b60808201526155e960a08401615207565b60a082015295945050505050565b60006020828403121561560957600080fd5b6137b3826151ca565b60008060008060008086880360e081121561562c57600080fd5b615635886151ca565b9650615643602089016151dc565b9550615651604089016151dc565b945061565f606089016151dc565b9350608088013592506040609f198201121561567a57600080fd5b50615683615c9e565b61568f60a089016151dc565b815261569d60c089016151dc565b6020820152809150509295509295509295565b6000602082840312156156c257600080fd5b5035919050565b600080604083850312156156dc57600080fd5b82359150602083013561529e81615f53565b6000806040838503121561570157600080fd5b50508035926020909101359150565b60006020828403121561572257600080fd5b6137b3826151dc565b600080600080600060a0868803121561574357600080fd5b61574c866151f0565b945060208601519350604086015192506060860151915061576f608087016151f0565b90509295509295909350565b600081518084526020808501945080840160005b838110156157b45781516001600160a01b03168752958201959082019060010161578f565b509495945050505050565b8060005b60028110156109405781518452602093840193909101906001016157c3565b600081518084526020808501945080840160005b838110156157b4578151875295820195908201906001016157f6565b6000815180845261582a816020860160208601615e63565b601f01601f19169290920160200192915050565b61584881836157bf565b604001919050565b60008351615862818460208801615e63565b835190830190615876818360208801615e63565b01949350505050565b86815261588f60208201876157bf565b61589c60608201866157bf565b6158a960a08201856157bf565b6158b660e08201846157bf565b60609190911b6001600160601b0319166101208201526101340195945050505050565b8381526158e960208201846157bf565b606081019190915260800192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b60408101610f9882846157bf565b6020815260006137b360208301846157e2565b918252602082015260400190565b93845260ff9290921660208401526040830152606082015260800190565b6020815260006137b36020830184615812565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c06080840152615a0860e084018261577b565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b61ffff93841681529183166020830152909116604082015260600190565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615aa757845183529383019391830191600101615a8b565b509098975050505050505050565b9182526001600160a01b0316602082015260400190565b828152606081016137b360208301846157bf565b82815260406020820152600061380160408301846157e2565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a0830152613fc160c0830184615812565b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c082018190526000906140e590830184615812565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c082018190526000906140e590830184615812565b63ffffffff92831681529116602082015260400190565b6001600160401b0391909116815260200190565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a060808201819052600090615c4d9083018461577b565b979650505050505050565b6000808335601e19843603018112615c6f57600080fd5b8301803591506001600160401b03821115615c8957600080fd5b6020019150368190038213156150b357600080fd5b604080519081016001600160401b0381118282101715615cc057615cc0615f3d565b60405290565b60405160c081016001600160401b0381118282101715615cc057615cc0615f3d565b60405161012081016001600160401b0381118282101715615cc057615cc0615f3d565b604051601f8201601f191681016001600160401b0381118282101715615d3357615d33615f3d565b604052919050565b60008085851115615d4b57600080fd5b83861115615d5857600080fd5b5050820193919092039150565b60008219821115615d7857615d78615ee5565b500190565b60006001600160401b0382811684821680830382111561587657615876615ee5565b60006001600160601b0382811684821680830382111561587657615876615ee5565b600082615dd057615dd0615efb565b500490565b6000816000190483118215151615615def57615def615ee5565b500290565b600082821015615e0657615e06615ee5565b500390565b60006001600160601b0383811690831681811015615e2b57615e2b615ee5565b039392505050565b6001600160e01b03198135818116916004851015615e5b5780818660040360031b1b83161692505b505092915050565b60005b83811015615e7e578181015183820152602001615e66565b838111156109405750506000910152565b6000600019821415615ea357615ea3615ee5565b5060010190565b60006001600160401b0382811680821415615ec757615ec7615ee5565b6001019392505050565b600082615ee057615ee0615efb565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146123c557600080fd5b80151581146123c557600080fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", + 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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"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\":\"\",\"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\"}],\"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\":\"\",\"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\":\"owner\",\"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\"}],\"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\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeLinkPPM\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"fulfillmentFlatFeeNativePPM\",\"type\":\"uint32\"}],\"internalType\":\"structVRFCoordinatorV2PlusUpgradedVersion.FeeConfig\",\"name\":\"feeConfig\",\"type\":\"tuple\"}],\"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: "0x60a06040523480156200001157600080fd5b506040516200610538038062006105833981016040819052620000349162000183565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000d7565b50505060601b6001600160601b031916608052620001b5565b6001600160a01b038116331415620001325760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000602082840312156200019657600080fd5b81516001600160a01b0381168114620001ae57600080fd5b9392505050565b60805160601c615f2a620001db600039600081816104a601526136510152615f2a6000f3fe6080604052600436106101e05760003560e01c8062012291146101e5578063088070f5146102125780630ae095401461029257806315c48b84146102b457806318e3dd27146102dc5780631b6b6d231461031b578063294daa49146103485780632f622e6b14610364578063330987b314610384578063405b84fa146103a457806340d6bb82146103c457806341af6c87146103ef57806351cff8d91461041f5780635d06b4ab1461043f57806364d51a2a1461045f5780636598274414610474578063689c45171461049457806372e9d565146104c857806379ba5097146104e85780637bce14d1146104fd5780638402595e1461051d57806386fe91c71461053d5780638da5cb5b1461055d57806395b55cfc1461057b5780639b1c385e1461058e5780639d40a6fd146105bc578063a21a23e4146105e9578063a4c0ed36146105fe578063aa433aff1461061e578063aefb212f1461063e578063b08c87951461066b578063b2a7cac51461068b578063bec4c08c146106ab578063caf70c4a146106cb578063cb631797146106eb578063ce3f47191461070b578063d98e620e1461071e578063dac83d291461073e578063dc311dd31461075e578063e72f6e301461078f578063ee9d2d38146107af578063f2fde38b146107dc575b600080fd5b3480156101f157600080fd5b506101fa6107fc565b604051610209939291906159b5565b60405180910390f35b34801561021e57600080fd5b50600c5461025a9061ffff81169063ffffffff62010000820481169160ff600160301b82041691600160381b8204811691600160581b90041685565b6040805161ffff909616865263ffffffff9485166020870152921515928501929092528216606084015216608082015260a001610209565b34801561029e57600080fd5b506102b26102ad366004615628565b610878565b005b3480156102c057600080fd5b506102c960c881565b60405161ffff9091168152602001610209565b3480156102e857600080fd5b50600a5461030390600160601b90046001600160601b031681565b6040516001600160601b039091168152602001610209565b34801561032757600080fd5b5060025461033b906001600160a01b031681565b6040516102099190615859565b34801561035457600080fd5b5060405160028152602001610209565b34801561037057600080fd5b506102b261037f3660046151c6565b610946565b34801561039057600080fd5b5061030361039f36600461537d565b610aba565b3480156103b057600080fd5b506102b26103bf366004615628565b610f73565b3480156103d057600080fd5b506103da6101f481565b60405163ffffffff9091168152602001610209565b3480156103fb57600080fd5b5061040f61040a36600461560f565b61135e565b6040519015158152602001610209565b34801561042b57600080fd5b506102b261043a3660046151c6565b6114ff565b34801561044b57600080fd5b506102b261045a3660046151c6565b6116b0565b34801561046b57600080fd5b506102c9606481565b34801561048057600080fd5b506102b261048f3660046151e3565b611767565b3480156104a057600080fd5b5061033b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104d457600080fd5b5060035461033b906001600160a01b031681565b3480156104f457600080fd5b506102b26117c7565b34801561050957600080fd5b506102b2610518366004615277565b611871565b34801561052957600080fd5b506102b26105383660046151c6565b61196a565b34801561054957600080fd5b50600a54610303906001600160601b031681565b34801561056957600080fd5b506000546001600160a01b031661033b565b6102b261058936600461560f565b611a76565b34801561059a57600080fd5b506105ae6105a936600461545a565b611bba565b604051908152602001610209565b3480156105c857600080fd5b506007546105dc906001600160401b031681565b6040516102099190615b4e565b3480156105f557600080fd5b506105ae611f2a565b34801561060a57600080fd5b506102b261061936600461521c565b612178565b34801561062a57600080fd5b506102b261063936600461560f565b612315565b34801561064a57600080fd5b5061065e61065936600461564d565b612378565b60405161020991906158d0565b34801561067757600080fd5b506102b2610686366004615571565b612479565b34801561069757600080fd5b506102b26106a636600461560f565b6125ed565b3480156106b757600080fd5b506102b26106c6366004615628565b612711565b3480156106d757600080fd5b506105ae6106e636600461529f565b6128a8565b3480156106f757600080fd5b506102b2610706366004615628565b6128d8565b6102b26107193660046152f1565b612bc5565b34801561072a57600080fd5b506105ae61073936600461560f565b612ed6565b34801561074a57600080fd5b506102b2610759366004615628565b612ef7565b34801561076a57600080fd5b5061077e61077936600461560f565b613007565b604051610209959493929190615b62565b34801561079b57600080fd5b506102b26107aa3660046151c6565b613102565b3480156107bb57600080fd5b506105ae6107ca36600461560f565b600f6020526000908152604090205481565b3480156107e857600080fd5b506102b26107f73660046151c6565b6132dd565b600c54600e805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff1693919283919083018282801561086657602002820191906000526020600020905b815481526020019060010190808311610852575b50505050509050925092509250909192565b60008281526005602052604090205482906001600160a01b0316806108b057604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146108e45780604051636c51fda960e11b81526004016108db9190615859565b60405180910390fd5b600c54600160301b900460ff161561090f5760405163769dd35360e11b815260040160405180910390fd5b6109188461135e565b1561093657604051631685ecdd60e31b815260040160405180910390fd5b61094084846132ee565b50505050565b600c54600160301b900460ff16156109715760405163769dd35360e11b815260040160405180910390fd5b6109796134a9565b600b54600160601b90046001600160601b03166109a957604051631e9acf1760e31b815260040160405180910390fd5b600b8054600160601b90046001600160601b0316908190600c6109cc8380615d6a565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a600c8282829054906101000a90046001600160601b0316610a149190615d6a565b92506101000a8154816001600160601b0302191690836001600160601b031602179055506000826001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114610a8e576040519150601f19603f3d011682016040523d82523d6000602084013e610a93565b606091505b5050905080610ab55760405163950b247960e01b815260040160405180910390fd5b505050565b600c54600090600160301b900460ff1615610ae85760405163769dd35360e11b815260040160405180910390fd5b60005a90506000610af985856134fe565b90506000846060015163ffffffff166001600160401b03811115610b1f57610b1f615e9c565b604051908082528060200260200182016040528015610b48578160200160208202803683370190505b50905060005b856060015163ffffffff16811015610bbf57826040015181604051602001610b779291906158e3565b6040516020818303038152906040528051906020012060001c828281518110610ba257610ba2615e86565b602090810291909101015280610bb781615dee565b915050610b4e565b50602080830180516000908152600f9092526040808320839055905190518291631fe543e360e01b91610bf791908690602401615a3f565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600c805460ff60301b1916600160301b179055908801516080890151919250600091610c5c9163ffffffff169084613769565b600c805460ff60301b19169055602089810151600090815260069091526040902054909150600160c01b90046001600160401b0316610c9c816001615cdc565b6020808b0151600090815260069091526040812080546001600160401b0393909316600160c01b026001600160c01b039093169290921790915560a08a01518051610ce990600190615d53565b81518110610cf957610cf9615e86565b602091010151600c5460f89190911c6001149150600090610d2a908a90600160581b900463ffffffff163a856137b7565b90508115610e22576020808c01516000908152600690915260409020546001600160601b03808316600160601b909204161015610d7a57604051631e9acf1760e31b815260040160405180910390fd5b60208b81015160009081526006909152604090208054829190600c90610db1908490600160601b90046001600160601b0316615d6a565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600b600c8282829054906101000a90046001600160601b0316610df99190615cfe565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550610efd565b6020808c01516000908152600690915260409020546001600160601b0380831691161015610e6357604051631e9acf1760e31b815260040160405180910390fd5b6020808c015160009081526006909152604081208054839290610e909084906001600160601b0316615d6a565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600b60008282829054906101000a90046001600160601b0316610ed89190615cfe565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505b8a6020015188602001517f49580fdfd9497e1ed5c1b1cec0495087ae8e3f1267470ec2fb015db32e3d6aa78a604001518488604051610f5a939291909283526001600160601b039190911660208301521515604082015260600190565b60405180910390a3985050505050505050505b92915050565b600c54600160301b900460ff1615610f9e5760405163769dd35360e11b815260040160405180910390fd5b610fa781613806565b610fc65780604051635428d44960e01b81526004016108db9190615859565b600080600080610fd586613007565b945094505093509350336001600160a01b0316826001600160a01b0316146110385760405162461bcd60e51b81526020600482015260166024820152752737ba1039bab139b1b934b83a34b7b71037bbb732b960511b60448201526064016108db565b6110418661135e565b156110875760405162461bcd60e51b815260206004820152601660248201527550656e64696e6720726571756573742065786973747360501b60448201526064016108db565b60006040518060c0016040528061109c600290565b60ff168152602001888152602001846001600160a01b03168152602001838152602001866001600160601b03168152602001856001600160601b031681525090506000816040516020016110f09190615922565b604051602081830303815290604052905061110a88613870565b505060405163ce3f471960e01b81526001600160a01b0388169063ce3f4719906001600160601b0388169061114390859060040161590f565b6000604051808303818588803b15801561115c57600080fd5b505af1158015611170573d6000803e3d6000fd5b50506002546001600160a01b031615801593509150611199905057506001600160601b03861615155b156112635760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906111d0908a908a906004016158a0565b602060405180830381600087803b1580156111ea57600080fd5b505af11580156111fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122291906152bb565b6112635760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b60448201526064016108db565b600c805460ff60301b1916600160301b17905560005b835181101561130c5783818151811061129457611294615e86565b60200260200101516001600160a01b0316638ea98117896040518263ffffffff1660e01b81526004016112c79190615859565b600060405180830381600087803b1580156112e157600080fd5b505af11580156112f5573d6000803e3d6000fd5b50505050808061130490615dee565b915050611279565b50600c805460ff60301b191690556040517fd63ca8cb945956747ee69bfdc3ea754c24a4caf7418db70e46052f7850be41879061134c9089908b9061586d565b60405180910390a15050505050505050565b6000818152600560209081526040808320815160608101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287969395860193909291908301828280156113e857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116113ca575b505050505081525050905060005b8160400151518110156114f55760005b600e548110156114e25760006114ab600e838154811061142857611428615e86565b90600052602060002001548560400151858151811061144957611449615e86565b602002602001015188600460008960400151898151811061146c5761146c615e86565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208d82529092529020546001600160401b0316613abe565b506000818152600f6020526040902054909150156114cf5750600195945050505050565b50806114da81615dee565b915050611406565b50806114ed81615dee565b9150506113f6565b5060009392505050565b600c54600160301b900460ff161561152a5760405163769dd35360e11b815260040160405180910390fd5b6115326134a9565b6002546001600160a01b031661155b5760405163c1f0c0a160e01b815260040160405180910390fd5b600b546001600160601b031661158457604051631e9acf1760e31b815260040160405180910390fd5b600b80546001600160601b031690819060006115a08380615d6a565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555080600a60008282829054906101000a90046001600160601b03166115e89190615d6a565b82546001600160601b039182166101009390930a92830291909202199091161790555060025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061163d90859085906004016158a0565b602060405180830381600087803b15801561165757600080fd5b505af115801561166b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168f91906152bb565b6116ac57604051631e9acf1760e31b815260040160405180910390fd5b5050565b6116b86134a9565b6116c181613806565b156116e1578060405163ac8a27ef60e01b81526004016108db9190615859565b601280546001810182556000919091527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec34440180546001600160a01b0319166001600160a01b0383161790556040517fb7cabbfc11e66731fc77de0444614282023bcbd41d16781c753a431d0af016259061175c908390615859565b60405180910390a150565b61176f6134a9565b6002546001600160a01b03161561179957604051631688c53760e11b815260040160405180910390fd5b600280546001600160a01b039384166001600160a01b03199182161790915560038054929093169116179055565b6001546001600160a01b0316331461181a5760405162461bcd60e51b815260206004820152601660248201527526bab9ba10313290383937b837b9b2b21037bbb732b960511b60448201526064016108db565b60008054336001600160a01b0319808316821784556001805490911690556040516001600160a01b0390921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b6118796134a9565b6040805180820182526000916118a89190849060029083908390808284376000920191909152506128a8915050565b6000818152600d602052604090205490915060ff16156118de57604051634a0b8fa760e01b8152600481018290526024016108db565b6000818152600d6020526040808220805460ff19166001908117909155600e805491820181559092527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd909101829055517fc9583fd3afa3d7f16eb0b88d0268e7d05c09bafa4b21e092cbd1320e1bc8089d9061195e9083815260200190565b60405180910390a15050565b6119726134a9565b600a544790600160601b90046001600160601b0316818111156119ac5780826040516354ced18160e11b81526004016108db9291906158e3565b81811015610ab55760006119c08284615d53565b90506000846001600160a01b03168260405160006040518083038185875af1925050503d8060008114611a0f576040519150601f19603f3d011682016040523d82523d6000602084013e611a14565b606091505b5050905080611a365760405163950b247960e01b815260040160405180910390fd5b7f4aed7c8eed0496c8c19ea2681fcca25741c1602342e38b045d9f1e8e905d2e9c8583604051611a6792919061586d565b60405180910390a15050505050565b600c54600160301b900460ff1615611aa15760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b0316611ad657604051630fb532db60e11b815260040160405180910390fd5b60008181526006602052604090208054600160601b90046001600160601b0316903490600c611b058385615cfe565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555034600a600c8282829054906101000a90046001600160601b0316611b4d9190615cfe565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f7603b205d03651ee812f803fccde89f1012e545a9c99f0abfea9cedd0fd8e902823484611ba09190615cc4565b604051611bae9291906158e3565b60405180910390a25050565b600c54600090600160301b900460ff1615611be85760405163769dd35360e11b815260040160405180910390fd5b6020808301356000908152600590915260409020546001600160a01b0316611c2357604051630fb532db60e11b815260040160405180910390fd5b3360009081526004602090815260408083208583013584529091529020546001600160401b031680611c70578260200135336040516379bfd40160e01b81526004016108db929190615a14565b600c5461ffff16611c876060850160408601615556565b61ffff161080611caa575060c8611ca46060850160408601615556565b61ffff16115b15611ce457611cbf6060840160408501615556565b600c5460405163539c34bb60e11b81526108db929161ffff169060c890600401615997565b600c5462010000900463ffffffff16611d03608085016060860161566f565b63ffffffff161115611d4957611d1f608084016060850161566f565b600c54604051637aebf00f60e11b81526108db929162010000900463ffffffff1690600401615b37565b6101f4611d5c60a085016080860161566f565b63ffffffff161115611d9657611d7860a084016080850161566f565b6101f46040516311ce1afb60e21b81526004016108db929190615b37565b6000611da3826001615cdc565b9050600080611db9863533602089013586613abe565b90925090506000611dd5611dd060a0890189615bb7565b613b47565b90506000611de282613bc4565b905083611ded613c35565b60208a0135611e0260808c0160608d0161566f565b611e1260a08d0160808e0161566f565b3386604051602001611e2a9796959493929190615a97565b60405160208183030381529060405280519060200120600f600086815260200190815260200160002081905550336001600160a01b0316886020013589600001357feb0e3652e0f44f417695e6e90f2f42c99b65cd7169074c5a654b16b9748c3a4e87878d6040016020810190611ea19190615556565b8e6060016020810190611eb4919061566f565b8f6080016020810190611ec7919061566f565b89604051611eda96959493929190615a58565b60405180910390a45050336000908152600460209081526040808320898301358452909152902080546001600160401b0319166001600160401b039490941693909317909255925050505b919050565b600c54600090600160301b900460ff1615611f585760405163769dd35360e11b815260040160405180910390fd5b600033611f66600143615d53565b600754604051606093841b6001600160601b03199081166020830152924060348201523090931b909116605483015260c01b6001600160c01b031916606882015260700160408051601f198184030181529190528051602090910120600780549192506001600160401b03909116906000611fe083615e09565b91906101000a8154816001600160401b0302191690836001600160401b03160217905550506000806001600160401b0381111561201f5761201f615e9c565b604051908082528060200260200182016040528015612048578160200160208202803683370190505b506040805160608082018352600080835260208084018281528486018381528984526006835286842095518654925191516001600160601b039182166001600160c01b031990941693909317600160601b9190921602176001600160c01b0316600160c01b6001600160401b039092169190910217909355835191820184523382528183018181528285018681528883526005855294909120825181546001600160a01b03199081166001600160a01b0392831617835592516001830180549094169116179091559251805194955090936121299260028501920190614e37565b5061213991506008905083613cc5565b50817f1d3015d7ba850fa198dc7b1a3f5d42779313a681035f77c8c03764c61005518d3360405161216a9190615859565b60405180910390a250905090565b600c54600160301b900460ff16156121a35760405163769dd35360e11b815260040160405180910390fd5b6002546001600160a01b031633146121ce576040516344b0e3c360e01b815260040160405180910390fd5b602081146121ef57604051638129bbcd60e01b815260040160405180910390fd5b60006121fd8284018461560f565b6000818152600560205260409020549091506001600160a01b031661223557604051630fb532db60e11b815260040160405180910390fd5b600081815260066020526040812080546001600160601b03169186919061225c8385615cfe565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555084600a60008282829054906101000a90046001600160601b03166122a49190615cfe565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550817f1ced9348ff549fceab2ac57cd3a9de38edaaab274b725ee82c23e8fc8c4eec7a8287846122f79190615cc4565b6040516123059291906158e3565b60405180910390a2505050505050565b61231d6134a9565b6000818152600560205260409020546001600160a01b031661235257604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020546123759082906001600160a01b03166132ee565b50565b606060006123866008613cd1565b90508084106123a857604051631390f2a160e01b815260040160405180910390fd5b60006123b48486615cc4565b9050818111806123c2575083155b6123cc57806123ce565b815b905060006123dc8683615d53565b6001600160401b038111156123f3576123f3615e9c565b60405190808252806020026020018201604052801561241c578160200160208202803683370190505b50905060005b815181101561246f576124406124388883615cc4565b600890613cdb565b82828151811061245257612452615e86565b60209081029190910101528061246781615dee565b915050612422565b5095945050505050565b6124816134a9565b60c861ffff871611156124ae57858660c860405163539c34bb60e11b81526004016108db93929190615997565b600082136124d2576040516321ea67b360e11b8152600481018390526024016108db565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600c805465ffffffffffff1916881762010000870217600160301b600160781b031916600160381b850263ffffffff60581b191617600160581b83021790558a51601180548d8701519289166001600160401b031990911617600160201b92891692909202919091179081905560108d90558a519788528785019590955298860191909152840196909652938201879052838116928201929092529190921c90911660c08201527f777357bb93f63d088f18112d3dba38457aec633eb8f1341e1d418380ad328e789060e00160405180910390a1505050505050565b600c54600160301b900460ff16156126185760405163769dd35360e11b815260040160405180910390fd5b6000818152600560205260409020546001600160a01b031661264d57604051630fb532db60e11b815260040160405180910390fd5b6000818152600560205260409020600101546001600160a01b031633146126a4576000818152600560205260409081902060010154905163d084e97560e01b81526108db916001600160a01b031690600401615859565b6000818152600560205260409081902080546001600160a01b031980821633908117845560019093018054909116905591516001600160a01b039092169183917fd4114ab6e9af9f597c52041f32d62dc57c5c4e4c0d4427006069635e216c938691611bae918591615886565b60008281526005602052604090205482906001600160a01b03168061274957604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b038216146127745780604051636c51fda960e11b81526004016108db9190615859565b600c54600160301b900460ff161561279f5760405163769dd35360e11b815260040160405180910390fd5b600084815260056020526040902060020154606414156127d2576040516305a48e0f60e01b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b03161561280957610940565b6001600160a01b0383166000818152600460209081526040808320888452825280832080546001600160401b031916600190811790915560058352818420600201805491820181558452919092200180546001600160a01b0319169092179091555184907f1e980d04aa7648e205713e5e8ea3808672ac163d10936d36f91b2c88ac1575e19061289a908690615859565b60405180910390a250505050565b6000816040516020016128bb91906158c2565b604051602081830303815290604052805190602001209050919050565b60008281526005602052604090205482906001600160a01b03168061291057604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b0382161461293b5780604051636c51fda960e11b81526004016108db9190615859565b600c54600160301b900460ff16156129665760405163769dd35360e11b815260040160405180910390fd5b61296f8461135e565b1561298d57604051631685ecdd60e31b815260040160405180910390fd5b6001600160a01b03831660009081526004602090815260408083208784529091529020546001600160401b03166129db5783836040516379bfd40160e01b81526004016108db929190615a14565b600084815260056020908152604080832060020180548251818502810185019093528083529192909190830182828015612a3e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612a20575b50505050509050600060018251612a559190615d53565b905060005b8251811015612b6157856001600160a01b0316838281518110612a7f57612a7f615e86565b60200260200101516001600160a01b03161415612b4f576000838381518110612aaa57612aaa615e86565b6020026020010151905080600560008a81526020019081526020016000206002018381548110612adc57612adc615e86565b600091825260208083209190910180546001600160a01b0319166001600160a01b039490941693909317909255898152600590915260409020600201805480612b2757612b27615e70565b600082815260209020810160001990810180546001600160a01b031916905501905550612b61565b80612b5981615dee565b915050612a5a565b506001600160a01b03851660009081526004602090815260408083208984529091529081902080546001600160401b03191690555186907f32158c6058347c1601b2d12bc696ac6901d8a9a9aa3ba10c27ab0a983e8425a790612305908890615859565b6000612bd382840184615494565b9050806000015160ff16600114612c0c57805160405163237d181f60e21b815260ff9091166004820152600160248201526044016108db565b8060a001516001600160601b03163414612c505760a08101516040516306acf13560e41b81523460048201526001600160601b0390911660248201526044016108db565b6020808201516000908152600590915260409020546001600160a01b031615612c8c576040516326afa43560e11b815260040160405180910390fd5b60005b816060015151811015612d2c5760016004600084606001518481518110612cb857612cb8615e86565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008460200151815260200190815260200160002060006101000a8154816001600160401b0302191690836001600160401b031602179055508080612d2490615dee565b915050612c8f565b50604080516060808201835260808401516001600160601b03908116835260a0850151811660208085019182526000858701818152828901805183526006845288832097518854955192516001600160401b0316600160c01b026001600160c01b03938816600160601b026001600160c01b0319909716919097161794909417169390931790945584518084018652868601516001600160a01b03908116825281860184815294880151828801908152925184526005865295909220825181549087166001600160a01b0319918216178255935160018201805491909716941693909317909455925180519192612e2b92600285019290910190614e37565b5050506080810151600a8054600090612e4e9084906001600160601b0316615cfe565b92506101000a8154816001600160601b0302191690836001600160601b031602179055508060a00151600a600c8282829054906101000a90046001600160601b0316612e9a9190615cfe565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555061094081602001516008613cc590919063ffffffff16565b600e8181548110612ee657600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b031680612f2f57604051630fb532db60e11b815260040160405180910390fd5b336001600160a01b03821614612f5a5780604051636c51fda960e11b81526004016108db9190615859565b600c54600160301b900460ff1615612f855760405163769dd35360e11b815260040160405180910390fd5b6000848152600560205260409020600101546001600160a01b03848116911614610940576000848152600560205260409081902060010180546001600160a01b0319166001600160a01b0386161790555184907f21a4dad170a6bf476c31bbcf4a16628295b0e450672eec25d7c93308e05344a19061289a9033908790615886565b6000818152600560205260408120548190819081906060906001600160a01b031661304557604051630fb532db60e11b815260040160405180910390fd5b60008681526006602090815260408083205460058352928190208054600290910180548351818602810186019094528084526001600160601b0380871696600160601b810490911695600160c01b9091046001600160401b0316946001600160a01b03909416939183918301828280156130e857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116130ca575b505050505090509450945094509450945091939590929450565b61310a6134a9565b6002546001600160a01b03166131335760405163c1f0c0a160e01b815260040160405180910390fd5b6002546040516370a0823160e01b81526000916001600160a01b0316906370a0823190613164903090600401615859565b60206040518083038186803b15801561317c57600080fd5b505afa158015613190573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131b491906152d8565b600a549091506001600160601b0316818111156131e85780826040516354ced18160e11b81526004016108db9291906158e3565b81811015610ab55760006131fc8284615d53565b60025460405163a9059cbb60e01b81529192506001600160a01b03169063a9059cbb9061322f908790859060040161586d565b602060405180830381600087803b15801561324957600080fd5b505af115801561325d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061328191906152bb565b61329e57604051631f01ff1360e21b815260040160405180910390fd5b7f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b43660084826040516132cf92919061586d565b60405180910390a150505050565b6132e56134a9565b61237581613ce7565b6000806132fa84613870565b60025491935091506001600160a01b03161580159061332157506001600160601b03821615155b156133d05760025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906133619086906001600160601b0387169060040161586d565b602060405180830381600087803b15801561337b57600080fd5b505af115801561338f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b391906152bb565b6133d057604051631e9acf1760e31b815260040160405180910390fd5b6000836001600160a01b0316826001600160601b031660405160006040518083038185875af1925050503d8060008114613426576040519150601f19603f3d011682016040523d82523d6000602084013e61342b565b606091505b505090508061344d5760405163950b247960e01b815260040160405180910390fd5b604080516001600160a01b03861681526001600160601b038581166020830152841681830152905186917f8c74ce8b8cf87f5eb001275c8be27eb34ea2b62bfab6814fcc62192bb63e81c4919081900360600190a25050505050565b6000546001600160a01b031633146134fc5760405162461bcd60e51b815260206004820152601660248201527527b7363c9031b0b63630b1363290313c9037bbb732b960511b60448201526064016108db565b565b6040805160608101825260008082526020820181905291810191909152600061352a84600001516128a8565b6000818152600d602052604090205490915060ff1661355f57604051631dfd6e1360e21b8152600481018290526024016108db565b60008185608001516040516020016135789291906158e3565b60408051601f1981840301815291815281516020928301206000818152600f909352912054909150806135be57604051631b44092560e11b815260040160405180910390fd5b845160208087015160408089015160608a015160808b015160a08c015193516135ed978a979096959101615ae3565b6040516020818303038152906040528051906020012081146136225760405163354a450b60e21b815260040160405180910390fd5b60006136318660000151613d8b565b9050806136f8578551604051631d2827a760e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163e9413d38916136859190600401615b4e565b60206040518083038186803b15801561369d57600080fd5b505afa1580156136b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136d591906152d8565b9050806136f857855160405163175dadad60e01b81526108db9190600401615b4e565b600087608001518260405160200161371a929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c905060006137418983613e68565b6040805160608101825297885260208801969096529486019490945250929695505050505050565b60005a61138881101561377b57600080fd5b61138881039050846040820482031161379357600080fd5b50823b61379f57600080fd5b60008083516020850160008789f190505b9392505050565b600081156137e4576011546137dd9086908690600160201b900463ffffffff1686613ed3565b90506137fe565b6011546137fb908690869063ffffffff1686613f75565b90505b949350505050565b6000805b60125481101561386757826001600160a01b03166012828154811061383157613831615e86565b6000918252602090912001546001600160a01b031614156138555750600192915050565b8061385f81615dee565b91505061380a565b50600092915050565b6000818152600560209081526040808320815160608101835281546001600160a01b039081168252600183015416818501526002820180548451818702810187018652818152879687969495948601939192908301828280156138fc57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116138de575b505050919092525050506000858152600660209081526040808320815160608101835290546001600160601b03808216808452600160601b8304909116948301859052600160c01b9091046001600160401b0316928201929092529096509094509192505b8260400151518110156139d857600460008460400151838151811061398857613988615e86565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120898252909252902080546001600160401b0319169055806139d081615dee565b915050613961565b50600085815260056020526040812080546001600160a01b03199081168255600182018054909116905590613a106002830182614e9c565b5050600085815260066020526040812055613a2c60088661409a565b50600a8054859190600090613a4b9084906001600160601b0316615d6a565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555082600a600c8282829054906101000a90046001600160601b0316613a939190615d6a565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050915091565b60408051602081018690526001600160a01b03851691810191909152606081018390526001600160401b03821660808201526000908190819060a00160408051601f198184030181529082905280516020918201209250613b239189918491016158e3565b60408051808303601f19018152919052805160209091012097909650945050505050565b60408051602081019091526000815281613b705750604080516020810190915260008152610f6d565b63125fa26760e31b613b828385615d92565b6001600160e01b03191614613baa57604051632923fee760e11b815260040160405180910390fd5b613bb78260048186615c9a565b8101906137b09190615332565b60607f92fd13387c7fe7befbc38d303d6468778fb9731bc4583f17d92989c6fcfdeaaa82604051602401613bfd91511515815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915292915050565b600046613c41816140a6565b15613cbe5760646001600160a01b031663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015613c8057600080fd5b505afa158015613c94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cb891906152d8565b91505090565b4391505090565b60006137b083836140c9565b6000610f6d825490565b60006137b08383614118565b6001600160a01b038116331415613d3a5760405162461bcd60e51b815260206004820152601760248201527621b0b73737ba103a3930b739b332b9103a379039b2b63360491b60448201526064016108db565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600046613d97816140a6565b15613e5957610100836001600160401b0316613db1613c35565b613dbb9190615d53565b1180613dd75750613dca613c35565b836001600160401b031610155b15613de55750600092915050565b6040516315a03d4160e11b8152606490632b407a8290613e09908690600401615b4e565b60206040518083038186803b158015613e2157600080fd5b505afa158015613e35573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137b091906152d8565b50506001600160401b03164090565b6000613e9c8360000151846020015185604001518660600151868860a001518960c001518a60e001518b6101000151614142565b60038360200151604051602001613eb4929190615a2b565b60408051601f1981840301815291905280516020909101209392505050565b600080613f166000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061435d92505050565b905060005a613f258888615cc4565b613f2f9190615d53565b613f399085615d34565b90506000613f5263ffffffff871664e8d4a51000615d34565b905082613f5f8284615cc4565b613f699190615cc4565b98975050505050505050565b600080613f80614422565b905060008113613fa6576040516321ea67b360e11b8152600481018290526024016108db565b6000613fe86000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061435d92505050565b9050600082825a613ff98b8b615cc4565b6140039190615d53565b61400d9088615d34565b6140179190615cc4565b61402990670de0b6b3a7640000615d34565b6140339190615d20565b9050600061404c63ffffffff881664e8d4a51000615d34565b905061406381676765c793fa10079d601b1b615d53565b8211156140835760405163e80fa38160e01b815260040160405180910390fd5b61408d8183615cc4565b9998505050505050505050565b60006137b083836144ed565b600061a4b18214806140ba575062066eed82145b80610f6d57505062066eee1490565b600081815260018301602052604081205461411057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610f6d565b506000610f6d565b600082600001828154811061412f5761412f615e86565b9060005260206000200154905092915050565b61414b896145e0565b6141945760405162461bcd60e51b815260206004820152601a6024820152797075626c6963206b6579206973206e6f74206f6e20637572766560301b60448201526064016108db565b61419d886145e0565b6141e15760405162461bcd60e51b815260206004820152601560248201527467616d6d61206973206e6f74206f6e20637572766560581b60448201526064016108db565b6141ea836145e0565b6142365760405162461bcd60e51b815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e20637572766500000060448201526064016108db565b61423f826145e0565b61428a5760405162461bcd60e51b815260206004820152601c60248201527b73486173685769746e657373206973206e6f74206f6e20637572766560201b60448201526064016108db565b614296878a88876146a3565b6142de5760405162461bcd60e51b81526020600482015260196024820152786164647228632a706b2b732a6729213d5f755769746e65737360381b60448201526064016108db565b60006142ea8a876147b7565b905060006142fd898b878b86898961481b565b9050600061430e838d8d8a8661492e565b9050808a1461434f5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b210383937b7b360991b60448201526064016108db565b505050505050505050505050565b600046614369816140a6565b156143a857606c6001600160a01b031663c6f7de0e6040518163ffffffff1660e01b815260040160206040518083038186803b158015613e2157600080fd5b6143b18161496e565b1561386757600f602160991b016001600160a01b03166349948e0e84604051806080016040528060488152602001615ed6604891396040516020016143f79291906157af565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401613e09919061590f565b600c5460035460408051633fabe5a360e21b81529051600093600160381b900463ffffffff169283151592859283926001600160a01b03169163feaf968c9160048083019260a0929190829003018186803b15801561448057600080fd5b505afa158015614494573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144b8919061568a565b5094509092508491505080156144dc57506144d38242615d53565b8463ffffffff16105b156137fe5750601054949350505050565b600081815260018301602052604081205480156145d6576000614511600183615d53565b855490915060009061452590600190615d53565b905081811461458a57600086600001828154811061454557614545615e86565b906000526020600020015490508087600001848154811061456857614568615e86565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061459b5761459b615e70565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610f6d565b6000915050610f6d565b80516000906401000003d0191161462e5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420782d6f7264696e61746560701b60448201526064016108db565b60208201516401000003d0191161467c5760405162461bcd60e51b8152602060048201526012602482015271696e76616c696420792d6f7264696e61746560701b60448201526064016108db565b60208201516401000003d01990800961469c8360005b60200201516149a8565b1492915050565b60006001600160a01b0382166146e95760405162461bcd60e51b815260206004820152600b60248201526a626164207769746e65737360a81b60448201526064016108db565b60208401516000906001161561470057601c614703565b601b5b9050600070014551231950b75fc4402da1732fc9bebe1985876000602002015109865170014551231950b75fc4402da1732fc9bebe199182039250600091908909875160408051600080825260209091019182905292935060019161476d918691889187906158f1565b6020604051602081039080840390855afa15801561478f573d6000803e3d6000fd5b5050604051601f1901516001600160a01b039081169088161495505050505050949350505050565b6147bf614eba565b6147ec600184846040516020016147d893929190615838565b6040516020818303038152906040526149cc565b90505b6147f8816145e0565b610f6d57805160408051602081019290925261481491016147d8565b90506147ef565b614823614eba565b825186516401000003d01990819006910614156148825760405162461bcd60e51b815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e6374000060448201526064016108db565b61488d878988614a1a565b6148d25760405162461bcd60e51b8152602060048201526016602482015275119a5c9cdd081b5d5b0818da1958dac819985a5b195960521b60448201526064016108db565b6148dd848685614a1a565b6149235760405162461bcd60e51b815260206004820152601760248201527614d958dbdb99081b5d5b0818da1958dac819985a5b1959604a1b60448201526064016108db565b613f69868484614b35565b60006002868686858760405160200161494c969594939291906157de565b60408051601f1981840301815291905280516020909101209695505050505050565b6000600a82148061498057506101a482145b8061498d575062aa37dc82145b80614999575061210582145b80610f6d57505062014a331490565b6000806401000003d01980848509840990506401000003d019600782089392505050565b6149d4614eba565b6149dd82614bf8565b81526149f26149ed826000614692565b614c33565b602082018190526002900660011415611f25576020810180516401000003d019039052919050565b600082614a575760405162461bcd60e51b815260206004820152600b60248201526a3d32b9379039b1b0b630b960a91b60448201526064016108db565b83516020850151600090614a6d90600290615e30565b15614a7957601c614a7c565b601b5b9050600070014551231950b75fc4402da1732fc9bebe19838709604080516000808252602090910191829052919250600190614abf9083908690889087906158f1565b6020604051602081039080840390855afa158015614ae1573d6000803e3d6000fd5b505050602060405103519050600086604051602001614b00919061579d565b60408051601f1981840301815291905280516020909101206001600160a01b0392831692169190911498975050505050505050565b614b3d614eba565b835160208086015185519186015160009384938493614b5e93909190614c53565b919450925090506401000003d019858209600114614bba5760405162461bcd60e51b815260206004820152601960248201527834b73b2d1036bab9ba1031329034b73b32b939b29037b3103d60391b60448201526064016108db565b60405180604001604052806401000003d01980614bd957614bd9615e5a565b87860981526020016401000003d0198785099052979650505050505050565b805160208201205b6401000003d0198110611f2557604080516020808201939093528151808203840181529082019091528051910120614c00565b6000610f6d826002614c4c6401000003d0196001615cc4565b901c614d33565b60008080600180826401000003d019896401000003d019038808905060006401000003d0198b6401000003d019038a0890506000614c9383838585614dca565b9098509050614ca488828e88614dee565b9098509050614cb588828c87614dee565b90985090506000614cc88d878b85614dee565b9098509050614cd988828686614dca565b9098509050614cea88828e89614dee565b9098509050818114614d1f576401000003d019818a0998506401000003d01982890997506401000003d0198183099650614d23565b8196505b5050505050509450945094915050565b600080614d3e614ed8565b6020808252818101819052604082015260608101859052608081018490526401000003d01960a0820152614d70614ef6565b60208160c0846005600019fa925082614dc05760405162461bcd60e51b81526020600482015260126024820152716269674d6f64457870206661696c7572652160701b60448201526064016108db565b5195945050505050565b6000806401000003d0198487096401000003d0198487099097909650945050505050565b600080806401000003d019878509905060006401000003d01987876401000003d019030990506401000003d0198183086401000003d01986890990999098509650505050505050565b828054828255906000526020600020908101928215614e8c579160200282015b82811115614e8c57825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190614e57565b50614e98929150614f14565b5090565b50805460008255906000526020600020908101906123759190614f14565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614e985760008155600101614f15565b8035611f2581615eb2565b600082601f830112614f4557600080fd5b813560206001600160401b03821115614f6057614f60615e9c565b8160051b614f6f828201615c6a565b838152828101908684018388018501891015614f8a57600080fd5b600093505b85841015614fb6578035614fa281615eb2565b835260019390930192918401918401614f8f565b50979650505050505050565b600082601f830112614fd357600080fd5b614fdb615bfd565b808385604086011115614fed57600080fd5b60005b600281101561500f578135845260209384019390910190600101614ff0565b509095945050505050565b60008083601f84011261502c57600080fd5b5081356001600160401b0381111561504357600080fd5b60208301915083602082850101111561505b57600080fd5b9250929050565b600082601f83011261507357600080fd5b81356001600160401b0381111561508c5761508c615e9c565b61509f601f8201601f1916602001615c6a565b8181528460208386010111156150b457600080fd5b816020850160208301376000918101602001919091529392505050565b600060c082840312156150e357600080fd5b6150eb615c25565b905081356001600160401b03808216821461510557600080fd5b8183526020840135602084015261511e60408501615184565b604084015261512f60608501615184565b606084015261514060808501614f29565b608084015260a084013591508082111561515957600080fd5b5061516684828501615062565b60a08301525092915050565b803561ffff81168114611f2557600080fd5b803563ffffffff81168114611f2557600080fd5b80516001600160501b0381168114611f2557600080fd5b80356001600160601b0381168114611f2557600080fd5b6000602082840312156151d857600080fd5b81356137b081615eb2565b600080604083850312156151f657600080fd5b823561520181615eb2565b9150602083013561521181615eb2565b809150509250929050565b6000806000806060858703121561523257600080fd5b843561523d81615eb2565b93506020850135925060408501356001600160401b0381111561525f57600080fd5b61526b8782880161501a565b95989497509550505050565b60006040828403121561528957600080fd5b8260408301111561529957600080fd5b50919050565b6000604082840312156152b157600080fd5b6137b08383614fc2565b6000602082840312156152cd57600080fd5b81516137b081615ec7565b6000602082840312156152ea57600080fd5b5051919050565b6000806020838503121561530457600080fd5b82356001600160401b0381111561531a57600080fd5b6153268582860161501a565b90969095509350505050565b60006020828403121561534457600080fd5b604051602081016001600160401b038111828210171561536657615366615e9c565b604052823561537481615ec7565b81529392505050565b6000808284036101c081121561539257600080fd5b6101a0808212156153a257600080fd5b6153aa615c47565b91506153b68686614fc2565b82526153c58660408701614fc2565b60208301526080850135604083015260a0850135606083015260c085013560808301526153f460e08601614f29565b60a083015261010061540887828801614fc2565b60c084015261541b876101408801614fc2565b60e0840152610180860135908301529092508301356001600160401b0381111561544457600080fd5b615450858286016150d1565b9150509250929050565b60006020828403121561546c57600080fd5b81356001600160401b0381111561548257600080fd5b820160c081850312156137b057600080fd5b6000602082840312156154a657600080fd5b81356001600160401b03808211156154bd57600080fd5b9083019060c082860312156154d157600080fd5b6154d9615c25565b823560ff811681146154ea57600080fd5b81526020838101359082015261550260408401614f29565b604082015260608301358281111561551957600080fd5b61552587828601614f34565b606083015250615537608084016151af565b608082015261554860a084016151af565b60a082015295945050505050565b60006020828403121561556857600080fd5b6137b082615172565b60008060008060008086880360e081121561558b57600080fd5b61559488615172565b96506155a260208901615184565b95506155b060408901615184565b94506155be60608901615184565b9350608088013592506040609f19820112156155d957600080fd5b506155e2615bfd565b6155ee60a08901615184565b81526155fc60c08901615184565b6020820152809150509295509295509295565b60006020828403121561562157600080fd5b5035919050565b6000806040838503121561563b57600080fd5b82359150602083013561521181615eb2565b6000806040838503121561566057600080fd5b50508035926020909101359150565b60006020828403121561568157600080fd5b6137b082615184565b600080600080600060a086880312156156a257600080fd5b6156ab86615198565b94506020860151935060408601519250606086015191506156ce60808701615198565b90509295509295909350565b600081518084526020808501945080840160005b838110156157135781516001600160a01b0316875295820195908201906001016156ee565b509495945050505050565b8060005b6002811015610940578151845260209384019390910190600101615722565b600081518084526020808501945080840160005b8381101561571357815187529582019590820190600101615755565b60008151808452615789816020860160208601615dc2565b601f01601f19169290920160200192915050565b6157a7818361571e565b604001919050565b600083516157c1818460208801615dc2565b8351908301906157d5818360208801615dc2565b01949350505050565b8681526157ee602082018761571e565b6157fb606082018661571e565b61580860a082018561571e565b61581560e082018461571e565b60609190911b6001600160601b0319166101208201526101340195945050505050565b838152615848602082018461571e565b606081019190915260800192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039290921682526001600160601b0316602082015260400190565b60408101610f6d828461571e565b6020815260006137b06020830184615741565b918252602082015260400190565b93845260ff9290921660208401526040830152606082015260800190565b6020815260006137b06020830184615771565b6020815260ff82511660208201526020820151604082015260018060a01b0360408301511660608201526000606083015160c0608084015261596760e08401826156da565b60808501516001600160601b0390811660a0868101919091529095015190941660c0909301929092525090919050565b61ffff93841681529183166020830152909116604082015260600190565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b81811015615a06578451835293830193918301916001016159ea565b509098975050505050505050565b9182526001600160a01b0316602082015260400190565b828152606081016137b0602083018461571e565b8281526040602082015260006137fe6040830184615741565b86815285602082015261ffff85166040820152600063ffffffff808616606084015280851660808401525060c060a0830152613f6960c0830184615771565b878152602081018790526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c0820181905260009061408d90830184615771565b8781526001600160401b03871660208201526040810186905263ffffffff8581166060830152841660808201526001600160a01b03831660a082015260e060c0820181905260009061408d90830184615771565b63ffffffff92831681529116602082015260400190565b6001600160401b0391909116815260200190565b6001600160601b038681168252851660208201526001600160401b03841660408201526001600160a01b038316606082015260a060808201819052600090615bac908301846156da565b979650505050505050565b6000808335601e19843603018112615bce57600080fd5b8301803591506001600160401b03821115615be857600080fd5b60200191503681900382131561505b57600080fd5b604080519081016001600160401b0381118282101715615c1f57615c1f615e9c565b60405290565b60405160c081016001600160401b0381118282101715615c1f57615c1f615e9c565b60405161012081016001600160401b0381118282101715615c1f57615c1f615e9c565b604051601f8201601f191681016001600160401b0381118282101715615c9257615c92615e9c565b604052919050565b60008085851115615caa57600080fd5b83861115615cb757600080fd5b5050820193919092039150565b60008219821115615cd757615cd7615e44565b500190565b60006001600160401b038281168482168083038211156157d5576157d5615e44565b60006001600160601b038281168482168083038211156157d5576157d5615e44565b600082615d2f57615d2f615e5a565b500490565b6000816000190483118215151615615d4e57615d4e615e44565b500290565b600082821015615d6557615d65615e44565b500390565b60006001600160601b0383811690831681811015615d8a57615d8a615e44565b039392505050565b6001600160e01b03198135818116916004851015615dba5780818660040360031b1b83161692505b505092915050565b60005b83811015615ddd578181015183820152602001615dc5565b838111156109405750506000910152565b6000600019821415615e0257615e02615e44565b5060010190565b60006001600160401b0382811680821415615e2657615e26615e44565b6001019392505050565b600082615e3f57615e3f615e5a565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461237557600080fd5b801515811461237557600080fdfe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000806000a", } var VRFCoordinatorV2PlusUpgradedVersionABI = VRFCoordinatorV2PlusUpgradedVersionMetaData.ABI @@ -768,30 +768,6 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionT return _VRFCoordinatorV2PlusUpgradedVersion.Contract.OnTokenTransfer(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, arg0, amount, data) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "oracleWithdraw", recipient, amount) -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) OracleWithdraw(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.OracleWithdraw(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, recipient, amount) -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactorSession) OracleWithdraw(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.OracleWithdraw(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, recipient, amount) -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) OracleWithdrawNative(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "oracleWithdrawNative", recipient, amount) -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) OracleWithdrawNative(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.OracleWithdrawNative(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, recipient, amount) -} - -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactorSession) OracleWithdrawNative(recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.OracleWithdrawNative(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, recipient, amount) -} - func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) OwnerCancelSubscription(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) { return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "ownerCancelSubscription", subId) } @@ -840,16 +816,16 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionT return _VRFCoordinatorV2PlusUpgradedVersion.Contract.RegisterMigratableCoordinator(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, target) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "registerProvingKey", oracle, publicProvingKey) +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) RegisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "registerProvingKey", publicProvingKey) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) RegisterProvingKey(oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.RegisterProvingKey(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, oracle, publicProvingKey) +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) RegisterProvingKey(publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.RegisterProvingKey(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, publicProvingKey) } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactorSession) RegisterProvingKey(oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return _VRFCoordinatorV2PlusUpgradedVersion.Contract.RegisterProvingKey(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, oracle, publicProvingKey) +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactorSession) RegisterProvingKey(publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.RegisterProvingKey(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, publicProvingKey) } func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { @@ -924,6 +900,30 @@ func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionT return _VRFCoordinatorV2PlusUpgradedVersion.Contract.TransferOwnership(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, to) } +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) Withdraw(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "withdraw", recipient) +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) Withdraw(recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.Withdraw(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, recipient) +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactorSession) Withdraw(recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.Withdraw(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, recipient) +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactor) WithdrawNative(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.contract.Transact(opts, "withdrawNative", recipient) +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionSession) WithdrawNative(recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.WithdrawNative(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, recipient) +} + +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionTransactorSession) WithdrawNative(recipient common.Address) (*types.Transaction, error) { + return _VRFCoordinatorV2PlusUpgradedVersion.Contract.WithdrawNative(&_VRFCoordinatorV2PlusUpgradedVersion.TransactOpts, recipient) +} + type VRFCoordinatorV2PlusUpgradedVersionConfigSetIterator struct { Event *VRFCoordinatorV2PlusUpgradedVersionConfigSet @@ -1851,32 +1851,21 @@ func (it *VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegisteredIterator) Close type VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegistered struct { KeyHash [32]byte - Oracle common.Address Raw types.Log } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) FilterProvingKeyRegistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegisteredIterator, error) { +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) FilterProvingKeyRegistered(opts *bind.FilterOpts) (*VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegisteredIterator, error) { - var oracleRule []interface{} - for _, oracleItem := range oracle { - oracleRule = append(oracleRule, oracleItem) - } - - logs, sub, err := _VRFCoordinatorV2PlusUpgradedVersion.contract.FilterLogs(opts, "ProvingKeyRegistered", oracleRule) + logs, sub, err := _VRFCoordinatorV2PlusUpgradedVersion.contract.FilterLogs(opts, "ProvingKeyRegistered") if err != nil { return nil, err } return &VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegisteredIterator{contract: _VRFCoordinatorV2PlusUpgradedVersion.contract, event: "ProvingKeyRegistered", logs: logs, sub: sub}, nil } -func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegistered, oracle []common.Address) (event.Subscription, error) { - - var oracleRule []interface{} - for _, oracleItem := range oracle { - oracleRule = append(oracleRule, oracleItem) - } +func (_VRFCoordinatorV2PlusUpgradedVersion *VRFCoordinatorV2PlusUpgradedVersionFilterer) WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegistered) (event.Subscription, error) { - logs, sub, err := _VRFCoordinatorV2PlusUpgradedVersion.contract.WatchLogs(opts, "ProvingKeyRegistered", oracleRule) + logs, sub, err := _VRFCoordinatorV2PlusUpgradedVersion.contract.WatchLogs(opts, "ProvingKeyRegistered") if err != nil { return nil, err } @@ -3331,7 +3320,7 @@ func (VRFCoordinatorV2PlusUpgradedVersionOwnershipTransferred) Topic() common.Ha } func (VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegistered) Topic() common.Hash { - return common.HexToHash("0xe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b8") + return common.HexToHash("0xc9583fd3afa3d7f16eb0b88d0268e7d05c09bafa4b21e092cbd1320e1bc8089d") } func (VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled) Topic() common.Hash { @@ -3441,10 +3430,6 @@ type VRFCoordinatorV2PlusUpgradedVersionInterface interface { OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) - OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) - - OracleWithdrawNative(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) - OwnerCancelSubscription(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) RecoverFunds(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) @@ -3453,7 +3438,7 @@ type VRFCoordinatorV2PlusUpgradedVersionInterface interface { RegisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) - RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) + RegisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) @@ -3467,6 +3452,10 @@ type VRFCoordinatorV2PlusUpgradedVersionInterface interface { TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + Withdraw(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) + + WithdrawNative(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) + FilterConfigSet(opts *bind.FilterOpts) (*VRFCoordinatorV2PlusUpgradedVersionConfigSetIterator, error) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionConfigSet) (event.Subscription, error) @@ -3509,9 +3498,9 @@ type VRFCoordinatorV2PlusUpgradedVersionInterface interface { ParseOwnershipTransferred(log types.Log) (*VRFCoordinatorV2PlusUpgradedVersionOwnershipTransferred, error) - FilterProvingKeyRegistered(opts *bind.FilterOpts, oracle []common.Address) (*VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegisteredIterator, error) + FilterProvingKeyRegistered(opts *bind.FilterOpts) (*VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegisteredIterator, error) - WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegistered, oracle []common.Address) (event.Subscription, error) + WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegistered) (event.Subscription, error) ParseProvingKeyRegistered(log types.Log) (*VRFCoordinatorV2PlusUpgradedVersionProvingKeyRegistered, error) diff --git a/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer/vrfv2_wrapper_load_test_consumer.go b/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer/vrfv2_wrapper_load_test_consumer.go new file mode 100644 index 00000000000..9f59d32f0a5 --- /dev/null +++ b/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer/vrfv2_wrapper_load_test_consumer.go @@ -0,0 +1,1142 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package vrfv2_wrapper_load_test_consumer + +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 +) + +var VRFV2WrapperLoadTestConsumerMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_link\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_vrfV2Wrapper\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"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\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"payment\",\"type\":\"uint256\"}],\"name\":\"WrappedRequestFulfilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"requestId\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"}],\"name\":\"WrapperRequestMade\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_requestId\",\"type\":\"uint256\"}],\"name\":\"getRequestStatus\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256[]\",\"name\":\"randomWords\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"i_vrfV2Wrapper\",\"outputs\":[{\"internalType\":\"contractVRFV2WrapperInterface\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"_callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestConfirmations\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"_numWords\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"_requestCount\",\"type\":\"uint16\"}],\"name\":\"makeRequests\",\"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\":[],\"name\":\"reset\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_averageFulfillmentInMillions\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_fastestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_lastRequestId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_requestCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"s_requests\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"paid\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"fulfilled\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"requestTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentTimestamp\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"requestBlockNumber\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"fulfilmentBlockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_responseCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"s_slowestFulfillment\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"withdrawLink\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}]", + Bin: "0x60e0604052600060045560006005556103e76006553480156200002157600080fd5b50604051620017d6380380620017d68339810160408190526200004491620001cb565b6001600160601b0319606083811b821660805282901b1660a0523380600081620000b55760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000e857620000e88162000102565b50505060601b6001600160601b03191660c0525062000203565b6001600160a01b0381163314156200015d5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401620000ac565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001c657600080fd5b919050565b60008060408385031215620001df57600080fd5b620001ea83620001ae565b9150620001fa60208401620001ae565b90509250929050565b60805160601c60a05160601c60c05160601c61157e6200025860003960006101600152600081816103ad015281816106d401528181610cea0152610e1101526000818161054e0152610cc0015261157e6000f3fe6080604052600436106100f75760003560e01c80638da5cb5b1161008a578063d826f88f11610059578063d826f88f14610300578063d8a4676f1461032c578063dc1670db1461035f578063f2fde38b1461037557600080fd5b80638da5cb5b1461021e578063a168fa8914610249578063afacbf9c146102ca578063b1e21749146102ea57600080fd5b8063737144bc116100c6578063737144bc146101bd57806374dba124146101d357806379ba5097146101e95780637a8042bd146101fe57600080fd5b80631757f11c146101035780631fe543e31461012c5780632353f2381461014e578063557d2e92146101a757600080fd5b366100fe57005b600080fd5b34801561010f57600080fd5b5061011960055481565b6040519081526020015b60405180910390f35b34801561013857600080fd5b5061014c61014736600461118b565b610395565b005b34801561015a57600080fd5b506101827f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610123565b3480156101b357600080fd5b5061011960035481565b3480156101c957600080fd5b5061011960045481565b3480156101df57600080fd5b5061011960065481565b3480156101f557600080fd5b5061014c610447565b34801561020a57600080fd5b5061014c610219366004611159565b610544565b34801561022a57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610182565b34801561025557600080fd5b5061029d610264366004611159565b600960205260009081526040902080546001820154600383015460048401546005850154600690950154939460ff909316939192909186565b604080519687529415156020870152938501929092526060840152608083015260a082015260c001610123565b3480156102d657600080fd5b5061014c6102e536600461127a565b61064c565b3480156102f657600080fd5b5061011960075481565b34801561030c57600080fd5b5061014c6000600481905560058190556103e76006556003819055600255565b34801561033857600080fd5b5061034c610347366004611159565b61089a565b60405161012397969594939291906113ca565b34801561036b57600080fd5b5061011960025481565b34801561038157600080fd5b5061014c6103903660046110fa565b610a01565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610439576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6f6e6c792056524620563220777261707065722063616e2066756c66696c6c0060448201526064015b60405180910390fd5b6104438282610a15565b5050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146104c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610430565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61054c610bf1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb6105a760005473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff909116600482015260248101849052604401602060405180830381600087803b15801561061457600080fd5b505af1158015610628573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104439190611137565b610654610bf1565b60005b8161ffff168161ffff161015610893576000610674868686610c74565b600781905590506000610685610eb5565b6040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff8916600482015290915060009073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634306d3549060240160206040518083038186803b15801561071657600080fd5b505afa15801561072a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061074e9190611172565b6040805160e08101825282815260006020808301828152845183815280830186528486019081524260608601526080850184905260a0850189905260c0850184905289845260098352949092208351815591516001830180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001691151591909117905592518051949550919390926107ee92600285019291019061106f565b5060608201516003808301919091556080830151600483015560a0830151600583015560c090920151600690910155805490600061082b836114da565b9091555050600083815260086020526040908190208390555183907f5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec4906108759084815260200190565b60405180910390a2505050808061088b906114b8565b915050610657565b5050505050565b6000818152600960205260408120548190606090829081908190819061091c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610430565b6000888152600960209081526040808320815160e08101835281548152600182015460ff1615158185015260028201805484518187028101870186528181529295939486019383018282801561099157602002820191906000526020600020905b81548152602001906001019080831161097d575b505050505081526020016003820154815260200160048201548152602001600582015481526020016006820154815250509050806000015181602001518260400151836060015184608001518560a001518660c00151975097509750975097509750975050919395979092949650565b610a09610bf1565b610a1281610f52565b50565b600082815260096020526040902054610a8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f72657175657374206e6f7420666f756e640000000000000000000000000000006044820152606401610430565b6000610a94610eb5565b60008481526008602052604081205491925090610ab190836114a1565b90506000610ac282620f4240611464565b9050600554821115610ad45760058290555b600654821015610ae45760068290555b600060025411610af45780610b27565b600254610b02906001611411565b81600254600454610b139190611464565b610b1d9190611411565b610b279190611429565b60045560028054906000610b3a836114da565b90915550506000858152600960209081526040909120600181810180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690911790558551610b929260029092019187019061106f565b5060008581526009602052604090819020426004820155600681018590555490517f6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b91610be291889188916113a1565b60405180910390a15050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c72576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610430565b565b6040517f4306d35400000000000000000000000000000000000000000000000000000000815263ffffffff8416600482015260009073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811691634000aea0917f00000000000000000000000000000000000000000000000000000000000000009190821690634306d3549060240160206040518083038186803b158015610d2f57600080fd5b505afa158015610d43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d679190611172565b6040805163ffffffff808b16602083015261ffff8a169282019290925290871660608201526080016040516020818303038152906040526040518463ffffffff1660e01b8152600401610dbc93929190611309565b602060405180830381600087803b158015610dd657600080fd5b505af1158015610dea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e0e9190611137565b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663fc2a88c36040518163ffffffff1660e01b815260040160206040518083038186803b158015610e7557600080fd5b505afa158015610e89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ead9190611172565b949350505050565b600046610ec181611048565b15610f4b57606473ffffffffffffffffffffffffffffffffffffffff1663a3b1b31d6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f0d57600080fd5b505afa158015610f21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f459190611172565b91505090565b4391505090565b73ffffffffffffffffffffffffffffffffffffffff8116331415610fd2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610430565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061a4b182148061105c575062066eed82145b80611069575062066eee82145b92915050565b8280548282559060005260206000209081019282156110aa579160200282015b828111156110aa57825182559160200191906001019061108f565b506110b69291506110ba565b5090565b5b808211156110b657600081556001016110bb565b803561ffff811681146110e157600080fd5b919050565b803563ffffffff811681146110e157600080fd5b60006020828403121561110c57600080fd5b813573ffffffffffffffffffffffffffffffffffffffff8116811461113057600080fd5b9392505050565b60006020828403121561114957600080fd5b8151801515811461113057600080fd5b60006020828403121561116b57600080fd5b5035919050565b60006020828403121561118457600080fd5b5051919050565b6000806040838503121561119e57600080fd5b8235915060208084013567ffffffffffffffff808211156111be57600080fd5b818601915086601f8301126111d257600080fd5b8135818111156111e4576111e4611542565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110858211171561122757611227611542565b604052828152858101935084860182860187018b101561124657600080fd5b600095505b8386101561126957803585526001959095019493860193860161124b565b508096505050505050509250929050565b6000806000806080858703121561129057600080fd5b611299856110e6565b93506112a7602086016110cf565b92506112b5604086016110e6565b91506112c3606086016110cf565b905092959194509250565b600081518084526020808501945080840160005b838110156112fe578151875295820195908201906001016112e2565b509495945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416815260006020848184015260606040840152835180606085015260005b818110156113595785810183015185820160800152820161133d565b8181111561136b576000608083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160800195945050505050565b8381526060602082015260006113ba60608301856112ce565b9050826040830152949350505050565b878152861515602082015260e0604082015260006113eb60e08301886112ce565b90508560608301528460808301528360a08301528260c083015298975050505050505050565b6000821982111561142457611424611513565b500190565b60008261145f577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561149c5761149c611513565b500290565b6000828210156114b3576114b3611513565b500390565b600061ffff808316818114156114d0576114d0611513565b6001019392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561150c5761150c611513565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a", +} + +var VRFV2WrapperLoadTestConsumerABI = VRFV2WrapperLoadTestConsumerMetaData.ABI + +var VRFV2WrapperLoadTestConsumerBin = VRFV2WrapperLoadTestConsumerMetaData.Bin + +func DeployVRFV2WrapperLoadTestConsumer(auth *bind.TransactOpts, backend bind.ContractBackend, _link common.Address, _vrfV2Wrapper common.Address) (common.Address, *types.Transaction, *VRFV2WrapperLoadTestConsumer, error) { + parsed, err := VRFV2WrapperLoadTestConsumerMetaData.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(VRFV2WrapperLoadTestConsumerBin), backend, _link, _vrfV2Wrapper) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &VRFV2WrapperLoadTestConsumer{address: address, abi: *parsed, VRFV2WrapperLoadTestConsumerCaller: VRFV2WrapperLoadTestConsumerCaller{contract: contract}, VRFV2WrapperLoadTestConsumerTransactor: VRFV2WrapperLoadTestConsumerTransactor{contract: contract}, VRFV2WrapperLoadTestConsumerFilterer: VRFV2WrapperLoadTestConsumerFilterer{contract: contract}}, nil +} + +type VRFV2WrapperLoadTestConsumer struct { + address common.Address + abi abi.ABI + VRFV2WrapperLoadTestConsumerCaller + VRFV2WrapperLoadTestConsumerTransactor + VRFV2WrapperLoadTestConsumerFilterer +} + +type VRFV2WrapperLoadTestConsumerCaller struct { + contract *bind.BoundContract +} + +type VRFV2WrapperLoadTestConsumerTransactor struct { + contract *bind.BoundContract +} + +type VRFV2WrapperLoadTestConsumerFilterer struct { + contract *bind.BoundContract +} + +type VRFV2WrapperLoadTestConsumerSession struct { + Contract *VRFV2WrapperLoadTestConsumer + CallOpts bind.CallOpts + TransactOpts bind.TransactOpts +} + +type VRFV2WrapperLoadTestConsumerCallerSession struct { + Contract *VRFV2WrapperLoadTestConsumerCaller + CallOpts bind.CallOpts +} + +type VRFV2WrapperLoadTestConsumerTransactorSession struct { + Contract *VRFV2WrapperLoadTestConsumerTransactor + TransactOpts bind.TransactOpts +} + +type VRFV2WrapperLoadTestConsumerRaw struct { + Contract *VRFV2WrapperLoadTestConsumer +} + +type VRFV2WrapperLoadTestConsumerCallerRaw struct { + Contract *VRFV2WrapperLoadTestConsumerCaller +} + +type VRFV2WrapperLoadTestConsumerTransactorRaw struct { + Contract *VRFV2WrapperLoadTestConsumerTransactor +} + +func NewVRFV2WrapperLoadTestConsumer(address common.Address, backend bind.ContractBackend) (*VRFV2WrapperLoadTestConsumer, error) { + abi, err := abi.JSON(strings.NewReader(VRFV2WrapperLoadTestConsumerABI)) + if err != nil { + return nil, err + } + contract, err := bindVRFV2WrapperLoadTestConsumer(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumer{address: address, abi: abi, VRFV2WrapperLoadTestConsumerCaller: VRFV2WrapperLoadTestConsumerCaller{contract: contract}, VRFV2WrapperLoadTestConsumerTransactor: VRFV2WrapperLoadTestConsumerTransactor{contract: contract}, VRFV2WrapperLoadTestConsumerFilterer: VRFV2WrapperLoadTestConsumerFilterer{contract: contract}}, nil +} + +func NewVRFV2WrapperLoadTestConsumerCaller(address common.Address, caller bind.ContractCaller) (*VRFV2WrapperLoadTestConsumerCaller, error) { + contract, err := bindVRFV2WrapperLoadTestConsumer(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerCaller{contract: contract}, nil +} + +func NewVRFV2WrapperLoadTestConsumerTransactor(address common.Address, transactor bind.ContractTransactor) (*VRFV2WrapperLoadTestConsumerTransactor, error) { + contract, err := bindVRFV2WrapperLoadTestConsumer(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerTransactor{contract: contract}, nil +} + +func NewVRFV2WrapperLoadTestConsumerFilterer(address common.Address, filterer bind.ContractFilterer) (*VRFV2WrapperLoadTestConsumerFilterer, error) { + contract, err := bindVRFV2WrapperLoadTestConsumer(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerFilterer{contract: contract}, nil +} + +func bindVRFV2WrapperLoadTestConsumer(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := VRFV2WrapperLoadTestConsumerMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFV2WrapperLoadTestConsumer.Contract.VRFV2WrapperLoadTestConsumerCaller.contract.Call(opts, result, method, params...) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.VRFV2WrapperLoadTestConsumerTransactor.contract.Transfer(opts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.VRFV2WrapperLoadTestConsumerTransactor.contract.Transact(opts, method, params...) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _VRFV2WrapperLoadTestConsumer.Contract.contract.Call(opts, result, method, params...) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.contract.Transfer(opts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.contract.Transact(opts, method, params...) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, + + error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "getRequestStatus", _requestId) + + outstruct := new(GetRequestStatus) + if err != nil { + return *outstruct, err + } + + outstruct.Paid = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Fulfilled = *abi.ConvertType(out[1], new(bool)).(*bool) + outstruct.RandomWords = *abi.ConvertType(out[2], new([]*big.Int)).(*[]*big.Int) + outstruct.RequestTimestamp = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.FulfilmentTimestamp = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + outstruct.RequestBlockNumber = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + outstruct.FulfilmentBlockNumber = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) GetRequestStatus(_requestId *big.Int) (GetRequestStatus, + + error) { + return _VRFV2WrapperLoadTestConsumer.Contract.GetRequestStatus(&_VRFV2WrapperLoadTestConsumer.CallOpts, _requestId) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) GetRequestStatus(_requestId *big.Int) (GetRequestStatus, + + error) { + return _VRFV2WrapperLoadTestConsumer.Contract.GetRequestStatus(&_VRFV2WrapperLoadTestConsumer.CallOpts, _requestId) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) IVrfV2Wrapper(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "i_vrfV2Wrapper") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) IVrfV2Wrapper() (common.Address, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.IVrfV2Wrapper(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) IVrfV2Wrapper() (common.Address, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.IVrfV2Wrapper(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) Owner(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.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 (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) Owner() (common.Address, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Owner(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) Owner() (common.Address, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Owner(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SAverageFulfillmentInMillions(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_averageFulfillmentInMillions") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SAverageFulfillmentInMillions() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SAverageFulfillmentInMillions(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SAverageFulfillmentInMillions() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SAverageFulfillmentInMillions(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SFastestFulfillment(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_fastestFulfillment") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SFastestFulfillment() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SFastestFulfillment(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SFastestFulfillment() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SFastestFulfillment(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SLastRequestId(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_lastRequestId") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SLastRequestId() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SLastRequestId(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SLastRequestId() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SLastRequestId(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SRequestCount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_requestCount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SRequestCount() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SRequestCount(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SRequestCount() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SRequestCount(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SRequests(opts *bind.CallOpts, arg0 *big.Int) (SRequests, + + error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_requests", arg0) + + outstruct := new(SRequests) + if err != nil { + return *outstruct, err + } + + outstruct.Paid = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + outstruct.Fulfilled = *abi.ConvertType(out[1], new(bool)).(*bool) + outstruct.RequestTimestamp = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.FulfilmentTimestamp = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.RequestBlockNumber = *abi.ConvertType(out[4], new(*big.Int)).(**big.Int) + outstruct.FulfilmentBlockNumber = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SRequests(arg0 *big.Int) (SRequests, + + error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SRequests(&_VRFV2WrapperLoadTestConsumer.CallOpts, arg0) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SRequests(arg0 *big.Int) (SRequests, + + error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SRequests(&_VRFV2WrapperLoadTestConsumer.CallOpts, arg0) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SResponseCount(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_responseCount") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SResponseCount() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SResponseCount(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SResponseCount() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SResponseCount(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCaller) SSlowestFulfillment(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _VRFV2WrapperLoadTestConsumer.contract.Call(opts, &out, "s_slowestFulfillment") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) SSlowestFulfillment() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SSlowestFulfillment(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerCallerSession) SSlowestFulfillment() (*big.Int, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.SSlowestFulfillment(&_VRFV2WrapperLoadTestConsumer.CallOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "acceptOwnership") +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) AcceptOwnership() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.AcceptOwnership(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) AcceptOwnership() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.AcceptOwnership(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) MakeRequests(opts *bind.TransactOpts, _callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "makeRequests", _callbackGasLimit, _requestConfirmations, _numWords, _requestCount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) MakeRequests(_callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.MakeRequests(&_VRFV2WrapperLoadTestConsumer.TransactOpts, _callbackGasLimit, _requestConfirmations, _numWords, _requestCount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) MakeRequests(_callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, _requestCount uint16) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.MakeRequests(&_VRFV2WrapperLoadTestConsumer.TransactOpts, _callbackGasLimit, _requestConfirmations, _numWords, _requestCount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) RawFulfillRandomWords(opts *bind.TransactOpts, _requestId *big.Int, _randomWords []*big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "rawFulfillRandomWords", _requestId, _randomWords) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) RawFulfillRandomWords(_requestId *big.Int, _randomWords []*big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.RawFulfillRandomWords(&_VRFV2WrapperLoadTestConsumer.TransactOpts, _requestId, _randomWords) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) RawFulfillRandomWords(_requestId *big.Int, _randomWords []*big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.RawFulfillRandomWords(&_VRFV2WrapperLoadTestConsumer.TransactOpts, _requestId, _randomWords) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) Reset(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "reset") +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) Reset() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Reset(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) Reset() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Reset(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "transferOwnership", to) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.TransferOwnership(&_VRFV2WrapperLoadTestConsumer.TransactOpts, to) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) TransferOwnership(to common.Address) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.TransferOwnership(&_VRFV2WrapperLoadTestConsumer.TransactOpts, to) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) WithdrawLink(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.Transact(opts, "withdrawLink", amount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) WithdrawLink(amount *big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.WithdrawLink(&_VRFV2WrapperLoadTestConsumer.TransactOpts, amount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) WithdrawLink(amount *big.Int) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.WithdrawLink(&_VRFV2WrapperLoadTestConsumer.TransactOpts, amount) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.contract.RawTransact(opts, nil) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerSession) Receive() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Receive(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerTransactorSession) Receive() (*types.Transaction, error) { + return _VRFV2WrapperLoadTestConsumer.Contract.Receive(&_VRFV2WrapperLoadTestConsumer.TransactOpts) +} + +type VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator struct { + Event *VRFV2WrapperLoadTestConsumerOwnershipTransferRequested + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerOwnershipTransferRequested) + 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(VRFV2WrapperLoadTestConsumerOwnershipTransferRequested) + 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 *VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator) Error() error { + return it.fail +} + +func (it *VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFV2WrapperLoadTestConsumerOwnershipTransferRequested struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator, 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 := _VRFV2WrapperLoadTestConsumer.contract.FilterLogs(opts, "OwnershipTransferRequested", fromRule, toRule) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator{contract: _VRFV2WrapperLoadTestConsumer.contract, event: "OwnershipTransferRequested", logs: logs, sub: sub}, nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerOwnershipTransferRequested, 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 := _VRFV2WrapperLoadTestConsumer.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(VRFV2WrapperLoadTestConsumerOwnershipTransferRequested) + if err := _VRFV2WrapperLoadTestConsumer.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 (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) ParseOwnershipTransferRequested(log types.Log) (*VRFV2WrapperLoadTestConsumerOwnershipTransferRequested, error) { + event := new(VRFV2WrapperLoadTestConsumerOwnershipTransferRequested) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "OwnershipTransferRequested", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator struct { + Event *VRFV2WrapperLoadTestConsumerOwnershipTransferred + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerOwnershipTransferred) + 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(VRFV2WrapperLoadTestConsumerOwnershipTransferred) + 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 *VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator) Error() error { + return it.fail +} + +func (it *VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFV2WrapperLoadTestConsumerOwnershipTransferred struct { + From common.Address + To common.Address + Raw types.Log +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator, 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 := _VRFV2WrapperLoadTestConsumer.contract.FilterLogs(opts, "OwnershipTransferred", fromRule, toRule) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator{contract: _VRFV2WrapperLoadTestConsumer.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerOwnershipTransferred, 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 := _VRFV2WrapperLoadTestConsumer.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(VRFV2WrapperLoadTestConsumerOwnershipTransferred) + if err := _VRFV2WrapperLoadTestConsumer.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 (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) ParseOwnershipTransferred(log types.Log) (*VRFV2WrapperLoadTestConsumerOwnershipTransferred, error) { + event := new(VRFV2WrapperLoadTestConsumerOwnershipTransferred) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator struct { + Event *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) + 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(VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) + 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 *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator) Error() error { + return it.fail +} + +func (it *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled struct { + RequestId *big.Int + RandomWords []*big.Int + Payment *big.Int + Raw types.Log +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) FilterWrappedRequestFulfilled(opts *bind.FilterOpts) (*VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator, error) { + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.FilterLogs(opts, "WrappedRequestFulfilled") + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator{contract: _VRFV2WrapperLoadTestConsumer.contract, event: "WrappedRequestFulfilled", logs: logs, sub: sub}, nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) WatchWrappedRequestFulfilled(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) (event.Subscription, error) { + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.WatchLogs(opts, "WrappedRequestFulfilled") + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "WrappedRequestFulfilled", 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 (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) ParseWrappedRequestFulfilled(log types.Log) (*VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled, error) { + event := new(VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "WrappedRequestFulfilled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator struct { + Event *VRFV2WrapperLoadTestConsumerWrapperRequestMade + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(VRFV2WrapperLoadTestConsumerWrapperRequestMade) + 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(VRFV2WrapperLoadTestConsumerWrapperRequestMade) + 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 *VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator) Error() error { + return it.fail +} + +func (it *VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type VRFV2WrapperLoadTestConsumerWrapperRequestMade struct { + RequestId *big.Int + Paid *big.Int + Raw types.Log +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) FilterWrapperRequestMade(opts *bind.FilterOpts, requestId []*big.Int) (*VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.FilterLogs(opts, "WrapperRequestMade", requestIdRule) + if err != nil { + return nil, err + } + return &VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator{contract: _VRFV2WrapperLoadTestConsumer.contract, event: "WrapperRequestMade", logs: logs, sub: sub}, nil +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) WatchWrapperRequestMade(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerWrapperRequestMade, requestId []*big.Int) (event.Subscription, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _VRFV2WrapperLoadTestConsumer.contract.WatchLogs(opts, "WrapperRequestMade", requestIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(VRFV2WrapperLoadTestConsumerWrapperRequestMade) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "WrapperRequestMade", 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 (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumerFilterer) ParseWrapperRequestMade(log types.Log) (*VRFV2WrapperLoadTestConsumerWrapperRequestMade, error) { + event := new(VRFV2WrapperLoadTestConsumerWrapperRequestMade) + if err := _VRFV2WrapperLoadTestConsumer.contract.UnpackLog(event, "WrapperRequestMade", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +type GetRequestStatus struct { + Paid *big.Int + Fulfilled bool + RandomWords []*big.Int + RequestTimestamp *big.Int + FulfilmentTimestamp *big.Int + RequestBlockNumber *big.Int + FulfilmentBlockNumber *big.Int +} +type SRequests struct { + Paid *big.Int + Fulfilled bool + RequestTimestamp *big.Int + FulfilmentTimestamp *big.Int + RequestBlockNumber *big.Int + FulfilmentBlockNumber *big.Int +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumer) ParseLog(log types.Log) (generated.AbigenLog, error) { + switch log.Topics[0] { + case _VRFV2WrapperLoadTestConsumer.abi.Events["OwnershipTransferRequested"].ID: + return _VRFV2WrapperLoadTestConsumer.ParseOwnershipTransferRequested(log) + case _VRFV2WrapperLoadTestConsumer.abi.Events["OwnershipTransferred"].ID: + return _VRFV2WrapperLoadTestConsumer.ParseOwnershipTransferred(log) + case _VRFV2WrapperLoadTestConsumer.abi.Events["WrappedRequestFulfilled"].ID: + return _VRFV2WrapperLoadTestConsumer.ParseWrappedRequestFulfilled(log) + case _VRFV2WrapperLoadTestConsumer.abi.Events["WrapperRequestMade"].ID: + return _VRFV2WrapperLoadTestConsumer.ParseWrapperRequestMade(log) + + default: + return nil, fmt.Errorf("abigen wrapper received unknown log topic: %v", log.Topics[0]) + } +} + +func (VRFV2WrapperLoadTestConsumerOwnershipTransferRequested) Topic() common.Hash { + return common.HexToHash("0xed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278") +} + +func (VRFV2WrapperLoadTestConsumerOwnershipTransferred) Topic() common.Hash { + return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") +} + +func (VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) Topic() common.Hash { + return common.HexToHash("0x6c84e12b4c188e61f1b4727024a5cf05c025fa58467e5eedf763c0744c89da7b") +} + +func (VRFV2WrapperLoadTestConsumerWrapperRequestMade) Topic() common.Hash { + return common.HexToHash("0x5f56b4c20db9f5b294cbf6f681368de4a992a27e2de2ee702dcf2cbbfa791ec4") +} + +func (_VRFV2WrapperLoadTestConsumer *VRFV2WrapperLoadTestConsumer) Address() common.Address { + return _VRFV2WrapperLoadTestConsumer.address +} + +type VRFV2WrapperLoadTestConsumerInterface interface { + GetRequestStatus(opts *bind.CallOpts, _requestId *big.Int) (GetRequestStatus, + + error) + + IVrfV2Wrapper(opts *bind.CallOpts) (common.Address, error) + + Owner(opts *bind.CallOpts) (common.Address, error) + + SAverageFulfillmentInMillions(opts *bind.CallOpts) (*big.Int, error) + + SFastestFulfillment(opts *bind.CallOpts) (*big.Int, error) + + SLastRequestId(opts *bind.CallOpts) (*big.Int, error) + + SRequestCount(opts *bind.CallOpts) (*big.Int, error) + + SRequests(opts *bind.CallOpts, arg0 *big.Int) (SRequests, + + error) + + SResponseCount(opts *bind.CallOpts) (*big.Int, error) + + SSlowestFulfillment(opts *bind.CallOpts) (*big.Int, error) + + AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) + + MakeRequests(opts *bind.TransactOpts, _callbackGasLimit uint32, _requestConfirmations uint16, _numWords uint32, _requestCount uint16) (*types.Transaction, error) + + RawFulfillRandomWords(opts *bind.TransactOpts, _requestId *big.Int, _randomWords []*big.Int) (*types.Transaction, error) + + Reset(opts *bind.TransactOpts) (*types.Transaction, error) + + TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) + + WithdrawLink(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) + + Receive(opts *bind.TransactOpts) (*types.Transaction, error) + + FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2WrapperLoadTestConsumerOwnershipTransferRequestedIterator, error) + + WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferRequested(log types.Log) (*VRFV2WrapperLoadTestConsumerOwnershipTransferRequested, error) + + FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*VRFV2WrapperLoadTestConsumerOwnershipTransferredIterator, error) + + WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) + + ParseOwnershipTransferred(log types.Log) (*VRFV2WrapperLoadTestConsumerOwnershipTransferred, error) + + FilterWrappedRequestFulfilled(opts *bind.FilterOpts) (*VRFV2WrapperLoadTestConsumerWrappedRequestFulfilledIterator, error) + + WatchWrappedRequestFulfilled(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled) (event.Subscription, error) + + ParseWrappedRequestFulfilled(log types.Log) (*VRFV2WrapperLoadTestConsumerWrappedRequestFulfilled, error) + + FilterWrapperRequestMade(opts *bind.FilterOpts, requestId []*big.Int) (*VRFV2WrapperLoadTestConsumerWrapperRequestMadeIterator, error) + + WatchWrapperRequestMade(opts *bind.WatchOpts, sink chan<- *VRFV2WrapperLoadTestConsumerWrapperRequestMade, requestId []*big.Int) (event.Subscription, error) + + ParseWrapperRequestMade(log types.Log) (*VRFV2WrapperLoadTestConsumerWrapperRequestMade, error) + + ParseLog(log types.Log) (generated.AbigenLog, error) + + Address() common.Address +} 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 6efc75fce98..46be4857d75 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 @@ -1,4 +1,4 @@ -GETH_VERSION: 1.12.0 +GETH_VERSION: 1.13.8 aggregator_v2v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV2V3Interface.bin 95e8814b408bb05bf21742ef580d98698b7db6a9bac6a35c3de12b23aec4ee28 aggregator_v3_interface: ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.abi ../../contracts/solc/v0.8.6/AggregatorV2V3Interface/AggregatorV3Interface.bin 351b55d3b0f04af67db6dfb5c92f1c64479400ca1fec77afc20bc0ce65cb49ab authorized_forwarder: ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.abi ../../contracts/solc/v0.8.19/AuthorizedForwarder/AuthorizedForwarder.bin 8ea76c883d460f8353a45a493f2aebeb5a2d9a7b4619d1bc4fff5fb590bb3e10 @@ -6,11 +6,14 @@ authorized_receiver: ../../contracts/solc/v0.8.19/AuthorizedReceiver/AuthorizedR 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_2: ../../contracts/solc/v0.8.16/AutomationRegistrar2_2/AutomationRegistrar2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_2/AutomationRegistrar2_2.bin 1da3ede9459c097482de224a47025ef7d578c7a73bafdbe4d471989ca4ecb608 automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin 331bfa79685aee6ddf63b64c0747abee556c454cae3fb8175edff425b615d8aa +automation_utils_2_2: ../../contracts/solc/v0.8.16/AutomationUtils2_2/AutomationUtils2_2.abi ../../contracts/solc/v0.8.16/AutomationUtils2_2/AutomationUtils2_2.bin 30aee16011a019108133e9ae153cc3feeece9c8bd957ee2789b3b32243a4c7a2 batch_blockhash_store: ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.abi ../../contracts/solc/v0.8.6/BatchBlockhashStore/BatchBlockhashStore.bin 14356c48ef70f66ef74f22f644450dbf3b2a147c1b68deaa7e7d1eb8ffab15db batch_vrf_coordinator_v2: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2/BatchVRFCoordinatorV2.bin d0a54963260d8c1f1bbd984b758285e6027cfb5a7e42701bcb562ab123219332 batch_vrf_coordinator_v2plus: ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.abi ../../contracts/solc/v0.8.6/BatchVRFCoordinatorV2Plus/BatchVRFCoordinatorV2Plus.bin 7bb76ae241cf1b37b41920830b836cb99f1ad33efd7435ca2398ff6cd2fe5d48 blockhash_store: ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.abi ../../contracts/solc/v0.8.6/BlockhashStore/BlockhashStore.bin 12b0662f1636a341c8863bdec7a20f2ddd97c3a4fd1a7ae353fe316609face4e +chain_reader_example: ../../contracts/solc/v0.8.19/ChainReaderTestContract/LatestValueHolder.abi ../../contracts/solc/v0.8.19/ChainReaderTestContract/LatestValueHolder.bin de88c7e68de36b96aa2bec844bdc96fcd7c9017b38e25062b3b9f9cec42c814f chain_specific_util_helper: ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.bin 5f10664e31abc768f4a37901cae7a3bef90146180f97303e5a1bde5a08d84595 consumer_wrapper: ../../contracts/solc/v0.7/Consumer/Consumer.abi ../../contracts/solc/v0.7/Consumer/Consumer.bin 894d1cbd920dccbd36d92918c1037c6ded34f66f417ccb18ec3f33c64ef83ec5 cron_upkeep_factory_wrapper: ../../contracts/solc/v0.8.6/CronUpkeepFactory/CronUpkeepFactory.abi - dacb0f8cdf54ae9d2781c5e720fc314b32ed5e58eddccff512c75d6067292cd7 @@ -21,6 +24,7 @@ flux_aggregator_wrapper: ../../contracts/solc/v0.6/FluxAggregator/FluxAggregator 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_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin 6501bb9bcf5048bab2737b00685c6984a24867e234ddf5b60a65904eee9a4ebc +i_keeper_registry_master_wrapper_2_2: ../../contracts/solc/v0.8.16/IAutomationRegistryMaster/IAutomationRegistryMaster.abi ../../contracts/solc/v0.8.16/IAutomationRegistryMaster/IAutomationRegistryMaster.bin 37aabed3df4c1ab6ac63def4aa8e251da975bbbb15a8bcf1c22ff7467d70f70f i_log_automation: ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin 296beccb6af655d6fc3a6e676b244831cce2da6688d3afc4f21f8738ae59e03e keeper_consumer_performance_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.abi ../../contracts/solc/v0.8.16/KeeperConsumerPerformance/KeeperConsumerPerformance.bin eeda39f5d3e1c8ffa0fb6cd1803731b98a4bc262d41833458e3fe8b40933ae90 keeper_consumer_wrapper: ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.abi ../../contracts/solc/v0.8.16/KeeperConsumer/KeeperConsumer.bin 2c6163b145082fbab74b7343577a9cec8fda8b0da9daccf2a82581b1f5a84b83 @@ -30,15 +34,18 @@ keeper_registrar_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistrar2_0/Keep keeper_registry_logic1_3: ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3/KeeperRegistryLogic1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic1_3/KeeperRegistryLogic1_3.bin 903f8b9c8e25425ca6d0b81b89e339d695a83630bfbfa24a6f3b38869676bc5a keeper_registry_logic2_0: ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0/KeeperRegistryLogic2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistryLogic2_0/KeeperRegistryLogic2_0.bin d69d2bc8e4844293dbc2d45abcddc50b84c88554ecccfa4fa77c0ca45ec80871 keeper_registry_logic_a_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.bin 77481ab75c9aa86a62a7b2a708599b5ea1a6346ed1c0def6d4826e7ae523f1ee +keeper_registry_logic_a_wrapper_2_2: ../../contracts/solc/v0.8.16/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.bin 0d7847916491adac72568227177427daa9f47841ae6b4750c02d5e0ba14f8d4d keeper_registry_logic_b_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.bin 467d10741a04601b136553a2b1c6ab37f2a65d809366faf03180a22ff26be215 +keeper_registry_logic_b_wrapper_2_2: ../../contracts/solc/v0.8.16/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.bin 73d0822f2ecef6388f2b46f587795cdaa23316b96704e93467e947e1e3c5fe5f keeper_registry_wrapper1_1: ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.abi ../../contracts/solc/v0.7/KeeperRegistry1_1/KeeperRegistry1_1.bin 6ce079f2738f015f7374673a2816e8e9787143d00b780ea7652c8aa9ad9e1e20 keeper_registry_wrapper1_1_mock: ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.abi ../../contracts/solc/v0.7/KeeperRegistry1_1Mock/KeeperRegistry1_1Mock.bin 98ddb3680e86359de3b5d17e648253ba29a84703f087a1b52237824003a8c6df keeper_registry_wrapper1_2: ../../contracts/solc/v0.8.6/KeeperRegistry1_2/KeeperRegistry1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_2/KeeperRegistry1_2.bin a40ff877dd7c280f984cbbb2b428e160662b0c295e881d5f778f941c0088ca22 keeper_registry_wrapper1_3: ../../contracts/solc/v0.8.6/KeeperRegistry1_3/KeeperRegistry1_3.abi ../../contracts/solc/v0.8.6/KeeperRegistry1_3/KeeperRegistry1_3.bin d4dc760b767ae274ee25c4a604ea371e1fa603a7b6421b69efb2088ad9e8abb3 keeper_registry_wrapper2_0: ../../contracts/solc/v0.8.6/KeeperRegistry2_0/KeeperRegistry2_0.abi ../../contracts/solc/v0.8.6/KeeperRegistry2_0/KeeperRegistry2_0.bin c32dea7d5ef66b7c58ddc84ddf69aa44df1b3ae8601fbc271c95be4ff5853056 keeper_registry_wrapper_2_1: ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistry2_1/KeeperRegistry2_1.bin 604e4a0cd980c713929b523b999462a3aa0ed06f96ff563a4c8566cf59c8445b +keeper_registry_wrapper_2_2: ../../contracts/solc/v0.8.16/AutomationRegistry2_2/AutomationRegistry2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistry2_2/AutomationRegistry2_2.bin 8f1c6d3eddf36201a556a101350abd6eb733d4c3177da2ddb5eca0d24d9a88ef keepers_vrf_consumer: ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.bin fa75572e689c9e84705c63e8dbe1b7b8aa1a8fe82d66356c4873d024bb9166e8 -log_emitter: ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.bin 244ba13730c036de0b02beef4e3d9c9a96946ce353c27f366baecc7f5be5a6fd +log_emitter: ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.bin 4b129ab93432c95ff9143f0631323e189887668889e0b36ccccf18a571e41ccf log_triggered_streams_lookup_wrapper: ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.abi ../../contracts/solc/v0.8.16/LogTriggeredStreamsLookup/LogTriggeredStreamsLookup.bin f8da43a927c1a66238a9f4fd5d5dd7e280e361daa0444da1f7f79498ace901e1 log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.abi ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.bin 42426bbb83f96dfbe55fc576d6c65020eaeed690e2289cf99b0c4aa810a5f4ec mock_aggregator_proxy: ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.abi ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.bin b16c108f3dd384c342ddff5e94da7c0a8d39d1be5e3d8f2cf61ecc7f0e50ff42 @@ -46,11 +53,11 @@ mock_ethlink_aggregator_wrapper: ../../contracts/solc/v0.6/MockETHLINKAggregator mock_gas_aggregator_wrapper: ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.abi ../../contracts/solc/v0.6/MockGASAggregator/MockGASAggregator.bin bacbb1ea4dc6beac0db8a13ca5c75e2fd61b903d70feea9b3b1c8b10fe8df4f3 multiwordconsumer_wrapper: ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.abi ../../contracts/solc/v0.7/MultiWordConsumer/MultiWordConsumer.bin 6e68abdf614e3ed0f5066c1b5f9d7c1199f1e7c5c5251fe8a471344a59afc6ba offchain_aggregator_wrapper: OffchainAggregator/OffchainAggregator.abi - 5c8d6562e94166d4790f1ee6e4321d359d9f7262e6c5452a712b1f1c896f45cf -operator_factory: ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.bin 0fdfacf8879537b854875608dfca41c6221c342174417112acaa67dfcadafddc -operator_wrapper: ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin d7abd0e67f30a3a4c9c04c896124391306fa364fcf579fa6df04dbf912b48568 +operator_factory: ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.abi ../../contracts/solc/v0.8.19/OperatorFactory/OperatorFactory.bin 357203fabe3df436eb015e2d5094374c6967a9fc922ac8edc265b27aac4d67cf +operator_wrapper: ../../contracts/solc/v0.8.19/Operator/Operator.abi ../../contracts/solc/v0.8.19/Operator/Operator.bin c5e1db81070d940a82ef100b0bce38e055593cbeebbc73abf9d45c30d6020cd2 oracle_wrapper: ../../contracts/solc/v0.6/Oracle/Oracle.abi ../../contracts/solc/v0.6/Oracle/Oracle.bin 7af2fbac22a6e8c2847e8e685a5400cac5101d72ddf5365213beb79e4dede43a perform_data_checker_wrapper: ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.abi ../../contracts/solc/v0.8.16/PerformDataChecker/PerformDataChecker.bin 48d8309c2117c29a24e1155917ab0b780956b2cd6a8a39ef06ae66a7f6d94f73 -simple_log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.abi ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.bin 0a7a0cc4da7dc2a3d0a0c36c746b1adc044af5cad1838367356a0604f3255a01 +simple_log_upkeep_counter_wrapper: ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.abi ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.bin a2532ca73e227f846be39b52fa63cfa9d088116c3cfc311d972fe8db886fa915 solidity_vrf_consumer_interface: ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.6/VRFConsumer/VRFConsumer.bin ecc99378aa798014de9db42b2eb81320778b0663dbe208008dad75ccdc1d4366 solidity_vrf_consumer_interface_v08: ../../contracts/solc/v0.8.6/VRFConsumer/VRFConsumer.abi ../../contracts/solc/v0.8.6/VRFConsumer/VRFConsumer.bin b14f9136b15e3dc9d6154d5700f3ed4cf88ddc4f70f20c3bb57fc46050904c8f solidity_vrf_coordinator_interface: ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.abi ../../contracts/solc/v0.6/VRFCoordinator/VRFCoordinator.bin a23d3c395156804788c7f6fbda2994e8f7184304c0f0c9f2c4ddeaf073d346d2 @@ -74,31 +81,35 @@ vrf_consumer_v2: ../../contracts/solc/v0.8.6/VRFConsumerV2/VRFConsumerV2.abi ../ vrf_consumer_v2_plus_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2PlusUpgradeableExample/VRFConsumerV2PlusUpgradeableExample.bin 3155c611e4d6882e9324b6e975033b31356776ea8b031ca63d63da37589d583b vrf_consumer_v2_upgradeable_example: ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample/VRFConsumerV2UpgradeableExample.abi ../../contracts/solc/v0.8.6/VRFConsumerV2UpgradeableExample/VRFConsumerV2UpgradeableExample.bin f1790a9a2f2a04c730593e483459709cb89e897f8a19d7a3ac0cfe6a97265e6e vrf_coordinator_mock: ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordinatorMock.abi ../../contracts/solc/v0.8.6/VRFCoordinatorMock/VRFCoordinatorMock.bin 5c495cf8df1f46d8736b9150cdf174cce358cb8352f60f0d5bb9581e23920501 +vrf_coordinator_test_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorTestV2/VRFCoordinatorTestV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorTestV2/VRFCoordinatorTestV2.bin eaefd785c38bac67fb11a7fc2737ab2da68c988ca170e7db8ff235c80893e01c vrf_coordinator_v2: ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2/VRFCoordinatorV2.bin 295f35ce282060317dfd01f45959f5a2b05ba26913e422fbd4fb6bf90b107006 -vrf_coordinator_v2_5: ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin b0e7c42a30b36d9d31fa9a3f26bad7937152e3dddee5bd8dd3d121390c879ab6 +vrf_coordinator_v2_5: ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2_5/VRFCoordinatorV2_5.bin bcad64e1b41278998c94867370fd9c4809b1376ccc004955bc7ed33fe716408c vrf_coordinator_v2_plus_v2_example: ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2Plus_V2Example/VRFCoordinatorV2Plus_V2Example.bin 4a5b86701983b1b65f0a8dfa116b3f6d75f8f706fa274004b57bdf5992e4cec3 vrf_coordinator_v2plus_interface: ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.abi ../../contracts/solc/v0.8.6/IVRFCoordinatorV2PlusInternal/IVRFCoordinatorV2PlusInternal.bin 834a2ce0e83276372a0e1446593fd89798f4cf6dc95d4be0113e99fadf61558b vrf_external_sub_owner_example: ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFExternalSubOwnerExample/VRFExternalSubOwnerExample.bin 14f888eb313930b50233a6f01ea31eba0206b7f41a41f6311670da8bb8a26963 vrf_load_test_external_sub_owner: ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.abi ../../contracts/solc/v0.8.6/VRFLoadTestExternalSubOwner/VRFLoadTestExternalSubOwner.bin 2097faa70265e420036cc8a3efb1f1e0836ad2d7323b295b9a26a125dbbe6c7d vrf_load_test_ownerless_consumer: ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.abi ../../contracts/solc/v0.8.6/VRFLoadTestOwnerlessConsumer/VRFLoadTestOwnerlessConsumer.bin 74f914843cbc70b9c3079c3e1c709382ce415225e8bb40113e7ac018bfcb0f5c -vrf_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.bin 8ab9de5816fbdf93a2865e2711b85a39a6fc9c413a4b336578c485be1158d430 +vrf_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2LoadTestWithMetrics/VRFV2LoadTestWithMetrics.bin c9621c52d216a090ff6bbe942f1b75d2bce8658a27323c3789e5e14b523277ee +vrf_log_emitter: ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.abi ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.bin 15f491d445ac4d0c712d1cbe4e5054c759b080bf20de7d54bfe2a82cde4dcf06 vrf_malicious_consumer_v2: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2/VRFMaliciousConsumerV2.bin 9755fa8ffc7f5f0b337d5d413d77b0c9f6cd6f68c31727d49acdf9d4a51bc522 vrf_malicious_consumer_v2_plus: ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.abi ../../contracts/solc/v0.8.6/VRFMaliciousConsumerV2Plus/VRFMaliciousConsumerV2Plus.bin e2a72638e11da807b6533d037e7e5aaeed695efd5035777b8e20d2f8973a574c +vrf_mock_ethlink_aggregator: ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.abi ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.bin a6e753984eeec8107e205ae517f74d4616bf23cffda50a25538ffc16ac4b036f vrf_owner: ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.abi ../../contracts/solc/v0.8.6/VRFOwner/VRFOwner.bin eccfae5ee295b5850e22f61240c469f79752b8d9a3bac5d64aec7ac8def2f6cb -vrf_owner_test_consumer: ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.bin 0537bbe96c5a8bbd44d0a65fbb7e51f6a9f9e75f4673225845ac1ba33f4e7974 +vrf_owner_test_consumer: ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2OwnerTestConsumer/VRFV2OwnerTestConsumer.bin 6969de242efe8f366ae4097fc279d9375c8e2d0307aaa322e31f2ce6b8c1909a vrf_ownerless_consumer_example: ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample/VRFOwnerlessConsumerExample.abi ../../contracts/solc/v0.8.6/VRFOwnerlessConsumerExample/VRFOwnerlessConsumerExample.bin 9893b3805863273917fb282eed32274e32aa3d5c2a67a911510133e1218132be vrf_single_consumer_example: ../../contracts/solc/v0.8.6/VRFSingleConsumerExample/VRFSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFSingleConsumerExample/VRFSingleConsumerExample.bin 892a5ed35da2e933f7fd7835cd6f7f70ef3aa63a9c03a22c5b1fd026711b0ece vrf_v2_consumer_wrapper: ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.abi ../../contracts/solc/v0.8.6/VRFv2Consumer/VRFv2Consumer.bin 12368b3b5e06392440143a13b94c0ea2f79c4c897becc3b060982559e10ace40 vrf_v2plus_load_test_with_metrics: ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.abi ../../contracts/solc/v0.8.6/VRFV2PlusLoadTestWithMetrics/VRFV2PlusLoadTestWithMetrics.bin 0a89cb7ed9dfb42f91e559b03dc351ccdbe14d281a7ab71c63bd3f47eeed7711 vrf_v2plus_single_consumer: ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusSingleConsumerExample/VRFV2PlusSingleConsumerExample.bin 6226d05afa1664033b182bfbdde11d5dfb1d4c8e3eb0bd0448c8bfb76f5b96e4 vrf_v2plus_sub_owner: ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusExternalSubOwnerExample/VRFV2PlusExternalSubOwnerExample.bin 7541f986571b8a5671a256edc27ae9b8df9bcdff45ac3b96e5609bbfcc320e4e -vrf_v2plus_upgraded_version: ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin c0793d86fb6e45342c4424184fe241c16da960c0b4de76816364b933344d0756 +vrf_v2plus_upgraded_version: ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.abi ../../contracts/solc/v0.8.6/VRFCoordinatorV2PlusUpgradedVersion/VRFCoordinatorV2PlusUpgradedVersion.bin 3bcd359eddf2bc861dda86f9bb10b78bac1e0370badd15f67ae17b35c5d228d4 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 vrfv2_wrapper: ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.bin d5e9a982325d2d4f517c4f2bc818795f61555408ef4b38fb59b923d144970e38 vrfv2_wrapper_consumer_example: ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.bin 3c5c9f1c501e697a7e77e959b48767e2a0bb1372393fd7686f7aaef3eb794231 vrfv2_wrapper_interface: ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.abi ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.bin ff8560169de171a68b360b7438d13863682d07040d984fd0fb096b2379421003 +vrfv2_wrapper_load_test_consumer: ../../contracts/solc/v0.8.6/VRFV2WrapperLoadTestConsumer/VRFV2WrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2WrapperLoadTestConsumer/VRFV2WrapperLoadTestConsumer.bin 664ca7fdf4dd65cc183bc25f20708c4b369c3401bba3ee12797a93bcd70138b6 vrfv2plus_client: ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.abi ../../contracts/solc/v0.8.6/VRFV2PlusClient/VRFV2PlusClient.bin 3ffbfa4971a7e5f46051a26b1722613f265d89ea1867547ecec58500953a9501 vrfv2plus_consumer_example: ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2PlusConsumerExample/VRFV2PlusConsumerExample.bin 2c480a6d7955d33a00690fdd943486d95802e48a03f3cc243df314448e4ddb2c vrfv2plus_malicious_migrator: ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.abi ../../contracts/solc/v0.8.6/VRFV2PlusMaliciousMigrator/VRFV2PlusMaliciousMigrator.bin 80dbc98be5e42246960c889d29488f978d3db0127e95e9b295352c481d8c9b07 diff --git a/core/gethwrappers/go_generate.go b/core/gethwrappers/go_generate.go index 07e4fa9b8f3..b854d69970a 100644 --- a/core/gethwrappers/go_generate.go +++ b/core/gethwrappers/go_generate.go @@ -55,8 +55,14 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicA2_1/KeeperRegistryLogicA2_1.bin KeeperRegistryLogicA keeper_registry_logic_a_wrapper_2_1 //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.abi ../../contracts/solc/v0.8.16/KeeperRegistryLogicB2_1/KeeperRegistryLogicB2_1.bin KeeperRegistryLogicB keeper_registry_logic_b_wrapper_2_1 //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin IKeeperRegistryMaster i_keeper_registry_master_wrapper_2_1 -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin ILogAutomation i_log_automation //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin AutomationUtils automation_utils_2_1 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationRegistrar2_2/AutomationRegistrar2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_2/AutomationRegistrar2_2.bin AutomationRegistrar automation_registrar_wrapper2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationRegistry2_2/AutomationRegistry2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistry2_2/AutomationRegistry2_2.bin AutomationRegistry keeper_registry_wrapper_2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.bin AutomationRegistryLogicA keeper_registry_logic_a_wrapper_2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.abi ../../contracts/solc/v0.8.16/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.bin AutomationRegistryLogicB keeper_registry_logic_b_wrapper_2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/IAutomationRegistryMaster/IAutomationRegistryMaster.abi ../../contracts/solc/v0.8.16/IAutomationRegistryMaster/IAutomationRegistryMaster.bin IAutomationRegistryMaster i_keeper_registry_master_wrapper_2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationUtils2_2/AutomationUtils2_2.abi ../../contracts/solc/v0.8.16/AutomationUtils2_2/AutomationUtils2_2.bin AutomationUtils automation_utils_2_2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.abi ../../contracts/solc/v0.8.16/ILogAutomation/ILogAutomation.bin ILogAutomation i_log_automation //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.abi ../../contracts/solc/v0.8.16/AutomationForwarderLogic/AutomationForwarderLogic.bin AutomationForwarderLogic automation_forwarder_logic //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.abi ../../contracts/solc/v0.8.6/LogUpkeepCounter/LogUpkeepCounter.bin LogUpkeepCounter log_upkeep_counter_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.abi ../../contracts/solc/v0.8.6/SimpleLogUpkeepCounter/SimpleLogUpkeepCounter.bin SimpleLogUpkeepCounter simple_log_upkeep_counter_wrapper @@ -103,11 +109,14 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.abi ../../contracts/solc/v0.8.6/VRFV2TransparentUpgradeableProxy/VRFV2TransparentUpgradeableProxy.bin VRFV2TransparentUpgradeableProxy vrfv2_transparent_upgradeable_proxy //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.abi ../../contracts/solc/v0.8.6/VRFV2ProxyAdmin/VRFV2ProxyAdmin.bin VRFV2ProxyAdmin vrfv2_proxy_admin //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.abi ../../contracts/solc/v0.8.6/ChainSpecificUtilHelper/ChainSpecificUtilHelper.bin ChainSpecificUtilHelper chain_specific_util_helper +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFCoordinatorTestV2/VRFCoordinatorTestV2.abi ../../contracts/solc/v0.8.6/VRFCoordinatorTestV2/VRFCoordinatorTestV2.bin VRFCoordinatorTestV2 vrf_coordinator_test_v2 +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.abi ../../contracts/solc/v0.8.6/VRFMockETHLINKAggregator/VRFMockETHLINKAggregator.bin VRFMockETHLINKAggregator vrf_mock_ethlink_aggregator // VRF V2 Wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.abi ../../contracts/solc/v0.8.6/VRFV2Wrapper/VRFV2Wrapper.bin VRFV2Wrapper vrfv2_wrapper //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.abi ../../contracts/solc/v0.8.6/VRFV2WrapperInterface/VRFV2WrapperInterface.bin VRFV2WrapperInterface vrfv2_wrapper_interface //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.abi ../../contracts/solc/v0.8.6/VRFV2WrapperConsumerExample/VRFV2WrapperConsumerExample.bin VRFV2WrapperConsumerExample vrfv2_wrapper_consumer_example +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/VRFV2WrapperLoadTestConsumer/VRFV2WrapperLoadTestConsumer.abi ../../contracts/solc/v0.8.6/VRFV2WrapperLoadTestConsumer/VRFV2WrapperLoadTestConsumer.bin VRFV2WrapperLoadTestConsumer vrfv2_wrapper_load_test_consumer // Keepers X VRF v2 //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.abi ../../contracts/solc/v0.8.6/KeepersVRFConsumer/KeepersVRFConsumer.bin KeepersVRFConsumer keepers_vrf_consumer @@ -138,7 +147,9 @@ package gethwrappers //go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.abi ../../contracts/solc/v0.8.6/MockAggregatorProxy/MockAggregatorProxy.bin MockAggregatorProxy mock_aggregator_proxy // Log tester -//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.bin LogEmitter log_emitter + +// ChainReader test contract +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/ChainReaderTestContract/LatestValueHolder.abi ../../contracts/solc/v0.8.19/ChainReaderTestContract/LatestValueHolder.bin LatestValueHolder chain_reader_example // Chainlink Functions //go:generate go generate ./functions diff --git a/core/gethwrappers/go_generate_logpoller.go b/core/gethwrappers/go_generate_logpoller.go new file mode 100644 index 00000000000..b28b8205830 --- /dev/null +++ b/core/gethwrappers/go_generate_logpoller.go @@ -0,0 +1,7 @@ +// Package gethwrappers provides tools for wrapping solidity contracts with +// golang packages, using abigen. +package gethwrappers + +// Log tester +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.abi ../../contracts/solc/v0.8.19/LogEmitter/LogEmitter.bin LogEmitter log_emitter +//go:generate go run ./generation/generate/wrap.go ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.abi ../../contracts/solc/v0.8.19/VRFLogEmitter/VRFLogEmitter.bin VRFLogEmitter vrf_log_emitter diff --git a/core/gethwrappers/go_generate_test.go b/core/gethwrappers/go_generate_test.go index 9ded44c0785..e0779c306c4 100644 --- a/core/gethwrappers/go_generate_test.go +++ b/core/gethwrappers/go_generate_test.go @@ -14,6 +14,7 @@ import ( gethParams "github.com/ethereum/go-ethereum/params" "github.com/fatih/color" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/assert" @@ -112,7 +113,7 @@ func init() { for db.Scan() { line := strings.Fields(db.Text()) if stripTrailingColon(line[0], "") != "GETH_VERSION" { - if os.IsNotExist(utils.JustError(os.Stat(line[1]))) { + if os.IsNotExist(cutils.JustError(os.Stat(line[1]))) { solidityArtifactsMissing = append(solidityArtifactsMissing, line[1]) } } diff --git a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 293defcfbe0..d54d3fb8cdf 100644 --- a/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/llo-feeds/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,4 +1,4 @@ -GETH_VERSION: 1.12.0 +GETH_VERSION: 1.13.8 errored_verifier: ../../../contracts/solc/v0.8.16/ErroredVerifier/ErroredVerifier.abi ../../../contracts/solc/v0.8.16/ErroredVerifier/ErroredVerifier.bin 510d18a58bfda646be35e46491baf73041eb333a349615465b20e2b5b41c5f73 exposed_verifier: ../../../contracts/solc/v0.8.16/ExposedVerifier/ExposedVerifier.abi ../../../contracts/solc/v0.8.16/ExposedVerifier/ExposedVerifier.bin 6932cea8f2738e874d3ec9e1a4231d2421704030c071d9e15dd2f7f08482c246 fee_manager: ../../../contracts/solc/v0.8.16/FeeManager/FeeManager.abi ../../../contracts/solc/v0.8.16/FeeManager/FeeManager.bin 1b852df75bfabcc2b57539e84309cd57f9e693a2bb6b25a50e4a6101ccf32c49 diff --git a/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt index af907ce85eb..3268bb55bd7 100644 --- a/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/shared/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,4 +1,4 @@ -GETH_VERSION: 1.12.0 +GETH_VERSION: 1.13.8 burn_mint_erc677: ../../../contracts/solc/v0.8.19/BurnMintERC677/BurnMintERC677.abi ../../../contracts/solc/v0.8.19/BurnMintERC677/BurnMintERC677.bin 405c9016171e614b17e10588653ef8d33dcea21dd569c3fddc596a46fcff68a3 erc20: ../../../contracts/solc/v0.8.19/ERC20/ERC20.abi ../../../contracts/solc/v0.8.19/ERC20/ERC20.bin 5b1a93d9b24f250e49a730c96335a8113c3f7010365cba578f313b483001d4fc link_token: ../../../contracts/solc/v0.8.19/LinkToken/LinkToken.abi ../../../contracts/solc/v0.8.19/LinkToken/LinkToken.bin c0ef9b507103aae541ebc31d87d051c2764ba9d843076b30ec505d37cdfffaba diff --git a/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt index a6d32bf0a85..6d5b5c22c58 100644 --- a/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/transmission/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -1,4 +1,4 @@ -GETH_VERSION: 1.12.0 +GETH_VERSION: 1.13.8 entry_point: ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.abi ../../../contracts/solc/v0.8.15/EntryPoint/EntryPoint.bin 2cb4bb2ba3efa8df3dfb0a57eb3727d17b68fe202682024fa7cfb4faf026833e greeter: ../../../contracts/solc/v0.8.15/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter.bin 653dcba5c33a46292073939ce1e639372cf521c0ec2814d4c9f20c72f796f18c greeter_wrapper: ../../../contracts/solc/v0.8.15/Greeter/Greeter.abi ../../../contracts/solc/v0.8.15/Greeter/Greeter.bin 653dcba5c33a46292073939ce1e639372cf521c0ec2814d4c9f20c72f796f18c diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 8802d9c4b0d..c7abfb31a2a 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -26,7 +26,6 @@ import ( "github.com/google/uuid" "github.com/gorilla/securecookie" "github.com/gorilla/sessions" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/manyminds/api2go/jsonapi" "github.com/onsi/gomega" "github.com/stretchr/testify/assert" @@ -39,6 +38,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/client" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" @@ -51,6 +51,8 @@ import ( httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "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" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -141,11 +143,10 @@ func init() { fmt.Printf("[gin] %-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers) } - defaultP2PPeerID, err := p2ppeer.Decode(configtest.DefaultPeerID) + err := DefaultP2PPeerID.UnmarshalString(configtest.DefaultPeerID) if err != nil { panic(err) } - DefaultP2PPeerID = p2pkey.PeerID(defaultP2PPeerID) } func NewRandomPositiveInt64() int64 { @@ -233,10 +234,10 @@ func NewApplicationWithKey(t *testing.T, flagsAndDeps ...interface{}) *TestAppli func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, flagsAndDeps ...interface{}) *TestApplication { app := NewApplicationWithConfig(t, c, flagsAndDeps...) - chainID := *utils.NewBig(&FixtureChainID) + chainID := *ubig.New(&FixtureChainID) for _, dep := range flagsAndDeps { switch v := dep.(type) { - case *utils.Big: + case *ubig.Big: chainID = *v } } @@ -256,7 +257,7 @@ func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, fla return app } -func setKeys(t testing.TB, app *TestApplication, flagsAndDeps ...interface{}) (chainID utils.Big) { +func setKeys(t testing.TB, app *TestApplication, flagsAndDeps ...interface{}) (chainID ubig.Big) { require.NoError(t, app.KeyStore.Unlock(Password)) for _, dep := range flagsAndDeps { @@ -310,8 +311,6 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn auditLogger = audit.NoopLogger } - var eventBroadcaster pg.EventBroadcaster = pg.NewNullEventBroadcaster() - url := cfg.Database().URL() db, err := pg.NewConnection(url.String(), cfg.Database().Dialect(), cfg.Database()) require.NoError(t, err) @@ -328,8 +327,6 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn ethClient = dep case webhook.ExternalInitiatorManager: externalInitiatorManager = dep - case pg.EventBroadcaster: - eventBroadcaster = dep default: switch flag { case UseRealExternalInitiatorManager: @@ -341,7 +338,7 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn keyStore := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg.Database()) - mailMon := utils.NewMailboxMonitor(cfg.AppID().String()) + mailMon := mailbox.NewMonitor(cfg.AppID().String(), lggr.Named("Mailbox")) loopRegistry := plugins.NewLoopRegistry(lggr, nil) mercuryPool := wsrpc.NewPool(lggr, cache.Config{ @@ -359,10 +356,9 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn evmOpts := chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, - EventBroadcaster: eventBroadcaster, - MailMon: mailMon, - DB: db, + AppConfig: cfg, + MailMon: mailMon, + DB: db, }, CSAETHKeystore: keyStore, } @@ -415,7 +411,6 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn c := clhttptest.NewTestLocalOnlyHTTPClient() appInstance, err := chainlink.NewApplication(chainlink.ApplicationOpts{ Config: cfg, - EventBroadcaster: eventBroadcaster, MailMon: mailMon, SqlxDB: db, KeyStore: keyStore, @@ -504,14 +499,14 @@ func NewEthMocksWithTransactionsOnBlocksAssertions(t testing.TB) *evmclimocks.Cl if len(elems) > 0 { elems[0].Result = &evmtypes.Block{ Number: 42, - Hash: utils.NewHash(), + Hash: evmutils.NewHash(), Transactions: LegacyTransactionsFromGasPrices(9001, 9002), } } if len(elems) > 1 { elems[1].Result = &evmtypes.Block{ Number: 41, - Hash: utils.NewHash(), + Hash: evmutils.NewHash(), Transactions: LegacyTransactionsFromGasPrices(9003, 9004), } } @@ -697,27 +692,27 @@ type HTTPClientCleaner struct { } func (r *HTTPClientCleaner) Get(path string, headers ...map[string]string) (*http.Response, func()) { - resp, err := r.HTTPClient.Get(path, headers...) + resp, err := r.HTTPClient.Get(testutils.Context(r.t), path, headers...) return bodyCleaner(r.t, resp, err) } func (r *HTTPClientCleaner) Post(path string, body io.Reader) (*http.Response, func()) { - resp, err := r.HTTPClient.Post(path, body) + resp, err := r.HTTPClient.Post(testutils.Context(r.t), path, body) return bodyCleaner(r.t, resp, err) } func (r *HTTPClientCleaner) Put(path string, body io.Reader) (*http.Response, func()) { - resp, err := r.HTTPClient.Put(path, body) + resp, err := r.HTTPClient.Put(testutils.Context(r.t), path, body) return bodyCleaner(r.t, resp, err) } func (r *HTTPClientCleaner) Patch(path string, body io.Reader, headers ...map[string]string) (*http.Response, func()) { - resp, err := r.HTTPClient.Patch(path, body, headers...) + resp, err := r.HTTPClient.Patch(testutils.Context(r.t), path, body, headers...) return bodyCleaner(r.t, resp, err) } func (r *HTTPClientCleaner) Delete(path string) (*http.Response, func()) { - resp, err := r.HTTPClient.Delete(path) + resp, err := r.HTTPClient.Delete(testutils.Context(r.t), path) return bodyCleaner(r.t, resp, err) } @@ -877,10 +872,7 @@ func CreateExternalInitiatorViaWeb( t.Helper() client := app.NewHTTPClient(nil) - resp, cleanup := client.Post( - "/v2/external_initiators", - bytes.NewBufferString(payload), - ) + resp, cleanup := client.Post("/v2/external_initiators", bytes.NewBufferString(payload)) defer cleanup() AssertServerResponse(t, resp, http.StatusCreated) ei := &webpresenters.ExternalInitiatorAuthentication{} @@ -974,16 +966,14 @@ func AssertPipelineRunsStays(t testing.TB, pipelineSpecID int32, db *sqlx.DB, wa } // AssertEthTxAttemptCountStays asserts that the number of tx attempts remains at the provided value -func AssertEthTxAttemptCountStays(t testing.TB, db *sqlx.DB, want int) []int64 { +func AssertEthTxAttemptCountStays(t testing.TB, txStore txmgr.TestEvmTxStore, want int) []int64 { g := gomega.NewWithT(t) var txaIds []int64 - var err error - g.Consistently(func() []int64 { - txaIds = make([]int64, 0) - err = db.Select(&txaIds, `SELECT ID FROM evm.tx_attempts ORDER BY id ASC`) + g.Consistently(func() []txmgr.TxAttempt { + attempts, err := txStore.GetAllTxAttempts(testutils.Context(t)) assert.NoError(t, err) - return txaIds + return attempts }, AssertNoActionTimeout, DBPollingInterval).Should(gomega.HaveLen(want)) return txaIds } @@ -994,13 +984,13 @@ func Head(val interface{}) *evmtypes.Head { time := uint64(0) switch t := val.(type) { case int: - h = evmtypes.NewHead(big.NewInt(int64(t)), utils.NewHash(), utils.NewHash(), time, utils.NewBig(&FixtureChainID)) + h = evmtypes.NewHead(big.NewInt(int64(t)), evmutils.NewHash(), evmutils.NewHash(), time, ubig.New(&FixtureChainID)) case uint64: - h = evmtypes.NewHead(big.NewInt(int64(t)), utils.NewHash(), utils.NewHash(), time, utils.NewBig(&FixtureChainID)) + h = evmtypes.NewHead(big.NewInt(int64(t)), evmutils.NewHash(), evmutils.NewHash(), time, ubig.New(&FixtureChainID)) case int64: - h = evmtypes.NewHead(big.NewInt(t), utils.NewHash(), utils.NewHash(), time, utils.NewBig(&FixtureChainID)) + h = evmtypes.NewHead(big.NewInt(t), evmutils.NewHash(), evmutils.NewHash(), time, ubig.New(&FixtureChainID)) case *big.Int: - h = evmtypes.NewHead(t, utils.NewHash(), utils.NewHash(), time, utils.NewBig(&FixtureChainID)) + h = evmtypes.NewHead(t, evmutils.NewHash(), evmutils.NewHash(), time, ubig.New(&FixtureChainID)) default: panic(fmt.Sprintf("Could not convert %v of type %T to Head", val, val)) } @@ -1010,7 +1000,7 @@ func Head(val interface{}) *evmtypes.Head { func HeadWithHash(n int64, hash common.Hash) *evmtypes.Head { var h evmtypes.Head time := uint64(0) - h = evmtypes.NewHead(big.NewInt(n), hash, utils.NewHash(), time, utils.NewBig(&FixtureChainID)) + h = evmtypes.NewHead(big.NewInt(n), hash, evmutils.NewHash(), time, ubig.New(&FixtureChainID)) return &h } @@ -1132,7 +1122,7 @@ func unauthenticatedHTTP(t testing.TB, method string, url string, body io.Reader t.Helper() client := clhttptest.NewTestLocalOnlyHTTPClient() - request, err := http.NewRequest(method, url, body) + request, err := http.NewRequestWithContext(testutils.Context(t), method, url, body) require.NoError(t, err) request.Header.Set("Content-Type", "application/json") for key, value := range headers { @@ -1387,11 +1377,11 @@ func (b *Blocks) NewHead(number uint64) *evmtypes.Head { } head := &evmtypes.Head{ Number: parent.Number + 1, - Hash: utils.NewHash(), + Hash: evmutils.NewHash(), ParentHash: parent.Hash, Parent: parent, Timestamp: time.Unix(parent.Number+1, 0), - EVMChainID: utils.NewBig(&FixtureChainID), + EVMChainID: ubig.New(&FixtureChainID), } return head } @@ -1427,10 +1417,10 @@ func NewBlocks(t *testing.T, numHashes int) *Blocks { hashes := make([]common.Hash, 0) heads := make(map[int64]*evmtypes.Head) for i := int64(0); i < int64(numHashes); i++ { - hash := utils.NewHash() + hash := evmutils.NewHash() hashes = append(hashes, hash) - heads[i] = &evmtypes.Head{Hash: hash, Number: i, Timestamp: time.Unix(i, 0), EVMChainID: utils.NewBig(&FixtureChainID)} + heads[i] = &evmtypes.Head{Hash: hash, Number: i, Timestamp: time.Unix(i, 0), EVMChainID: ubig.New(&FixtureChainID)} if i > 0 { parent := heads[i-1] heads[i].Parent = parent diff --git a/core/internal/cltest/factories.go b/core/internal/cltest/factories.go index f0ce8c4ff66..804dbe2d088 100644 --- a/core/internal/cltest/factories.go +++ b/core/internal/cltest/factories.go @@ -16,7 +16,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/google/uuid" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/require" "github.com/urfave/cli" "gopkg.in/guregu/null.v4" @@ -32,6 +32,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" "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" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" @@ -55,8 +57,8 @@ func NewEIP55Address() ethkey.EIP55Address { return e } -func NewPeerID() p2ppeer.ID { - id, err := p2ppeer.Decode("12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw") +func NewPeerID() (id ragep2ptypes.PeerID) { + err := id.UnmarshalText([]byte("12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw")) if err != nil { panic(err) } @@ -145,6 +147,18 @@ func NewEthTx(fromAddress common.Address) txmgr.Tx { } } +func NewLegacyTransaction(nonce uint64, to common.Address, value *big.Int, gasLimit uint32, gasPrice *big.Int, data []byte) *types.Transaction { + tx := types.LegacyTx{ + Nonce: nonce, + To: &to, + Value: value, + Gas: uint64(gasLimit), + GasPrice: gasPrice, + Data: data, + } + return types.NewTx(&tx) +} + func MustInsertUnconfirmedEthTx(t *testing.T, txStore txmgr.TestEvmTxStore, nonce int64, fromAddress common.Address, opts ...interface{}) txmgr.Tx { broadcastAt := time.Now() chainID := &FixtureChainID @@ -172,7 +186,7 @@ func MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t *testing.T, txStore etx := MustInsertUnconfirmedEthTx(t, txStore, nonce, fromAddress, opts...) attempt := NewLegacyEthTxAttempt(t, etx.ID) - tx := types.NewTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) + tx := NewLegacyTransaction(uint64(nonce), testutils.NewAddress(), big.NewInt(142), 242, big.NewInt(342), []byte{1, 2, 3}) rlp := new(bytes.Buffer) require.NoError(t, tx.EncodeRLP(rlp)) attempt.SignedRawTx = rlp.Bytes() @@ -212,7 +226,7 @@ func NewLegacyEthTxAttempt(t *testing.T, etxID int64) txmgr.TxAttempt { // Just a random signed raw tx that decodes correctly // Ignore all actual values SignedRawTx: hexutil.MustDecode("0xf889808504a817c8008307a12094000000000000000000000000000000000000000080a400000000000000000000000000000000000000000000000000000000000000000000000025a0838fe165906e2547b9a052c099df08ec891813fea4fcdb3c555362285eb399c5a070db99322490eb8a0f2270be6eca6e3aedbc49ff57ef939cf2774f12d08aa85e"), - Hash: utils.NewHash(), + Hash: evmutils.NewHash(), State: txmgrtypes.TxAttemptInProgress, } } @@ -230,7 +244,7 @@ func NewDynamicFeeEthTxAttempt(t *testing.T, etxID int64) txmgr.TxAttempt { // Just a random signed raw tx that decodes correctly // Ignore all actual values SignedRawTx: hexutil.MustDecode("0xf889808504a817c8008307a12094000000000000000000000000000000000000000080a400000000000000000000000000000000000000000000000000000000000000000000000025a0838fe165906e2547b9a052c099df08ec891813fea4fcdb3c555362285eb399c5a070db99322490eb8a0f2270be6eca6e3aedbc49ff57ef939cf2774f12d08aa85e"), - Hash: utils.NewHash(), + Hash: evmutils.NewHash(), State: txmgrtypes.TxAttemptInProgress, ChainSpecificFeeLimit: 42, } @@ -240,12 +254,12 @@ type RandomKey struct { Nonce int64 Disabled bool - chainIDs []utils.Big // nil: Fixture, set empty for none + chainIDs []ubig.Big // nil: Fixture, set empty for none } func (r RandomKey) MustInsert(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2, common.Address) { if r.chainIDs == nil { - r.chainIDs = []utils.Big{*utils.NewBig(&FixtureChainID)} + r.chainIDs = []ubig.Big{*ubig.New(&FixtureChainID)} } key := MustGenerateRandomKey(t) @@ -272,7 +286,7 @@ func (r RandomKey) MustInsertWithState(t testing.TB, keystore keystore.Eth) (eth // MustInsertRandomKey inserts a randomly generated (not cryptographically secure) key for testing. // By default, it is enabled for the fixture chain. Pass chainIDs to override. // Use MustInsertRandomKeyNoChains for a key associate with no chains. -func MustInsertRandomKey(t testing.TB, keystore keystore.Eth, chainIDs ...utils.Big) (ethkey.KeyV2, common.Address) { +func MustInsertRandomKey(t testing.TB, keystore keystore.Eth, chainIDs ...ubig.Big) (ethkey.KeyV2, common.Address) { r := RandomKey{} if len(chainIDs) > 0 { r.chainIDs = chainIDs @@ -281,7 +295,7 @@ func MustInsertRandomKey(t testing.TB, keystore keystore.Eth, chainIDs ...utils. } func MustInsertRandomKeyNoChains(t testing.TB, keystore keystore.Eth) (ethkey.KeyV2, common.Address) { - return RandomKey{chainIDs: []utils.Big{}}.MustInsert(t, keystore) + return RandomKey{chainIDs: []ubig.Big{}}.MustInsert(t, keystore) } func MustInsertRandomKeyReturningState(t testing.TB, keystore keystore.Eth) (ethkey.State, common.Address) { @@ -299,7 +313,7 @@ func MustGenerateRandomKeyState(_ testing.TB) ethkey.State { } func MustInsertHead(t *testing.T, db *sqlx.DB, cfg pg.QConfig, number int64) evmtypes.Head { - h := evmtypes.NewHead(big.NewInt(number), utils.NewHash(), utils.NewHash(), 0, utils.NewBig(&FixtureChainID)) + h := evmtypes.NewHead(big.NewInt(number), evmutils.NewHash(), evmutils.NewHash(), 0, ubig.New(&FixtureChainID)) horm := headtracker.NewORM(db, logger.TestLogger(t), cfg, FixtureChainID) err := horm.IdempotentInsertHead(testutils.Context(t), &h) @@ -339,7 +353,7 @@ func MustInsertOffchainreportingOracleSpec(t *testing.T, db *sqlx.DB, transmitte ocrKeyID := models.MustSha256HashFromHex(DefaultOCRKeyBundleID) spec := job.OCROracleSpec{} - require.NoError(t, db.Get(&spec, `INSERT INTO ocr_oracle_specs (created_at, updated_at, contract_address, p2p_bootstrap_peers, is_bootstrap_peer, encrypted_ocr_key_bundle_id, transmitter_address, observation_timeout, blockchain_timeout, contract_config_tracker_subscribe_interval, contract_config_tracker_poll_interval, contract_config_confirmations, database_timeout, observation_grace_period, contract_transmitter_transmit_timeout, evm_chain_id) VALUES ( + require.NoError(t, db.Get(&spec, `INSERT INTO ocr_oracle_specs (created_at, updated_at, contract_address, p2pv2_bootstrappers, is_bootstrap_peer, encrypted_ocr_key_bundle_id, transmitter_address, observation_timeout, blockchain_timeout, contract_config_tracker_subscribe_interval, contract_config_tracker_poll_interval, contract_config_confirmations, database_timeout, observation_grace_period, contract_transmitter_transmit_timeout, evm_chain_id) VALUES ( NOW(),NOW(),$1,'{}',false,$2,$3,0,0,0,0,0,0,0,0,0 ) RETURNING *`, NewEIP55Address(), &ocrKeyID, &transmitterAddress)) return spec @@ -347,7 +361,7 @@ NOW(),NOW(),$1,'{}',false,$2,$3,0,0,0,0,0,0,0,0,0 func MakeDirectRequestJobSpec(t *testing.T) *job.Job { t.Helper() - drs := &job.DirectRequestSpec{EVMChainID: (*utils.Big)(testutils.FixtureChainID)} + drs := &job.DirectRequestSpec{EVMChainID: (*ubig.Big)(testutils.FixtureChainID)} spec := &job.Job{ Type: job.DirectRequest, SchemaVersion: 1, @@ -391,7 +405,7 @@ func MustInsertKeeperJob(t *testing.T, db *sqlx.DB, korm keeper.ORM, from ethkey } func MustInsertKeeperRegistry(t *testing.T, db *sqlx.DB, korm keeper.ORM, ethKeyStore keystore.Eth, keeperIndex, numKeepers, blockCountPerTurn int32) (keeper.Registry, job.Job) { - key, _ := MustInsertRandomKey(t, ethKeyStore, *utils.NewBig(testutils.SimulatedChainID)) + key, _ := MustInsertRandomKey(t, ethKeyStore, *ubig.New(testutils.SimulatedChainID)) from := key.EIP55Address t.Helper() contractAddress := NewEIP55Address() @@ -415,7 +429,7 @@ func MustInsertKeeperRegistry(t *testing.T, db *sqlx.DB, korm keeper.ORM, ethKey func MustInsertUpkeepForRegistry(t *testing.T, db *sqlx.DB, cfg pg.QConfig, registry keeper.Registry) keeper.UpkeepRegistration { korm := keeper.NewORM(db, logger.TestLogger(t), cfg) - upkeepID := utils.NewBigI(int64(mathrand.Uint32())) + upkeepID := ubig.NewI(int64(mathrand.Uint32())) upkeep := keeper.UpkeepRegistration{ UpkeepID: upkeepID, ExecuteGas: uint32(150_000), @@ -479,23 +493,23 @@ func RandomLog(t *testing.T) types.Log { topics := make([]common.Hash, 4) for i := range topics { - topics[i] = utils.NewHash() + topics[i] = evmutils.NewHash() } return types.Log{ Address: testutils.NewAddress(), - BlockHash: utils.NewHash(), + BlockHash: evmutils.NewHash(), BlockNumber: uint64(mathrand.Intn(9999999)), Index: uint(mathrand.Intn(9999999)), Data: MustRandomBytes(t, 512), - Topics: []common.Hash{utils.NewHash(), utils.NewHash(), utils.NewHash(), utils.NewHash()}, + Topics: []common.Hash{evmutils.NewHash(), evmutils.NewHash(), evmutils.NewHash(), evmutils.NewHash()}, } } func RawNewRoundLog(t *testing.T, contractAddr common.Address, blockHash common.Hash, blockNumber uint64, logIndex uint, removed bool) types.Log { t.Helper() topic := (flux_aggregator_wrapper.FluxAggregatorNewRound{}).Topic() - topics := []common.Hash{topic, utils.NewHash(), utils.NewHash()} + topics := []common.Hash{topic, evmutils.NewHash(), evmutils.NewHash()} return RawNewRoundLogWithTopics(t, contractAddr, blockHash, blockNumber, logIndex, removed, topics) } diff --git a/core/internal/cltest/heavyweight/orm.go b/core/internal/cltest/heavyweight/orm.go index 5df28a49778..f49a94be05b 100644 --- a/core/internal/cltest/heavyweight/orm.go +++ b/core/internal/cltest/heavyweight/orm.go @@ -1,13 +1,8 @@ -package heavyweight - -// The heavyweight package contains cltest items that are costly and you should +// Package heavyweight contains test helpers that are costly and you should // think **real carefully** before using in your tests. +package heavyweight import ( - "database/sql" - "errors" - "fmt" - "net/url" "os" "path" "runtime" @@ -20,41 +15,45 @@ import ( "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/chainlink/v2/core/cmd" "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/pg" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/v2/internal/testdb" ) // FullTestDBV2 creates a pristine DB which runs in a separate database than the normal // unit tests, so you can do things like use other Postgres connection types with it. func FullTestDBV2(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { - return prepareFullTestDBV2(t, false, true, overrideFn) + return KindFixtures.PrepareDB(t, overrideFn) } // FullTestDBNoFixturesV2 is the same as FullTestDB, but it does not load fixtures. func FullTestDBNoFixturesV2(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { - return prepareFullTestDBV2(t, false, false, overrideFn) + return KindTemplate.PrepareDB(t, overrideFn) } // FullTestDBEmptyV2 creates an empty DB (without migrations). func FullTestDBEmptyV2(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { - return prepareFullTestDBV2(t, true, false, overrideFn) + return KindEmpty.PrepareDB(t, overrideFn) } func generateName() string { return strings.ReplaceAll(uuid.New().String(), "-", "") } -func prepareFullTestDBV2(t testing.TB, empty bool, loadFixtures bool, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { - testutils.SkipShort(t, "FullTestDB") +type Kind int - if empty && loadFixtures { - t.Fatal("could not load fixtures into an empty DB") - } +const ( + KindEmpty Kind = iota + KindTemplate + KindFixtures +) + +func (c Kind) PrepareDB(t testing.TB, overrideFn func(c *chainlink.Config, s *chainlink.Secrets)) (chainlink.GeneralConfig, *sqlx.DB) { + testutils.SkipShort(t, "FullTestDB") gcfg := configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Database.Dialect = dialects.Postgres @@ -64,7 +63,7 @@ func prepareFullTestDBV2(t testing.TB, empty bool, loadFixtures bool, overrideFn }) require.NoError(t, os.MkdirAll(gcfg.RootDir(), 0700)) - migrationTestDBURL, err := dropAndCreateThrowawayTestDB(gcfg.Database().URL(), generateName(), empty) + migrationTestDBURL, err := testdb.CreateOrReplace(gcfg.Database().URL(), generateName(), c != KindEmpty) require.NoError(t, err) db, err := pg.NewConnection(migrationTestDBURL, dialects.Postgres, gcfg.Database()) require.NoError(t, err) @@ -81,7 +80,7 @@ func prepareFullTestDBV2(t testing.TB, empty bool, loadFixtures bool, overrideFn } }) - if loadFixtures { + if c == KindFixtures { _, filename, _, ok := runtime.Caller(1) if !ok { t.Fatal("could not get runtime.Caller(1)") @@ -95,39 +94,3 @@ func prepareFullTestDBV2(t testing.TB, empty bool, loadFixtures bool, overrideFn return gcfg, db } - -func dropAndCreateThrowawayTestDB(parsed url.URL, postfix string, empty bool) (string, error) { - if parsed.Path == "" { - return "", errors.New("path missing from database URL") - } - - // Match the naming schema that our dangling DB cleanup methods expect - dbname := cmd.TestDBNamePrefix + postfix - if l := len(dbname); l > 63 { - return "", fmt.Errorf("dbname %v too long (%d), max is 63 bytes. Try a shorter postfix", dbname, l) - } - // Cannot drop test database if we are connected to it, so we must connect - // to a different one. 'postgres' should be present on all postgres installations - parsed.Path = "/postgres" - db, err := sql.Open(string(dialects.Postgres), parsed.String()) - if err != nil { - return "", fmt.Errorf("In order to drop the test database, we need to connect to a separate database"+ - " called 'postgres'. But we are unable to open 'postgres' database: %+v\n", err) - } - defer db.Close() - - _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", dbname)) - if err != nil { - return "", fmt.Errorf("unable to drop postgres migrations test database: %v", err) - } - if empty { - _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", dbname)) - } else { - _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s WITH TEMPLATE %s", dbname, cmd.PristineDBName)) - } - if err != nil { - return "", fmt.Errorf("unable to create postgres test database with name '%s': %v", dbname, err) - } - parsed.Path = fmt.Sprintf("/%s", dbname) - return parsed.String(), nil -} diff --git a/core/internal/cltest/job_factories.go b/core/internal/cltest/job_factories.go index a9e403fb608..399e71ff216 100644 --- a/core/internal/cltest/job_factories.go +++ b/core/internal/cltest/job_factories.go @@ -25,7 +25,7 @@ const ( contractAddress = "%s" evmChainID = "0" p2pPeerID = "%s" - p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] + p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false transmitterAddress = "%s" keyBundleID = "%s" diff --git a/core/internal/cltest/mocks.go b/core/internal/cltest/mocks.go index 073b3ba246c..fbfd820309a 100644 --- a/core/internal/cltest/mocks.go +++ b/core/internal/cltest/mocks.go @@ -355,7 +355,7 @@ func (m MockCookieAuthenticator) Cookie() (*http.Cookie, error) { return MustGenerateSessionCookie(m.t, m.SessionID), m.Error } -func (m MockCookieAuthenticator) Authenticate(sessions.SessionRequest) (*http.Cookie, error) { +func (m MockCookieAuthenticator) Authenticate(context.Context, sessions.SessionRequest) (*http.Cookie, error) { return MustGenerateSessionCookie(m.t, m.SessionID), m.Error } diff --git a/core/internal/cltest/simulated_backend.go b/core/internal/cltest/simulated_backend.go index 010478837da..cde060d7f4a 100644 --- a/core/internal/cltest/simulated_backend.go +++ b/core/internal/cltest/simulated_backend.go @@ -7,16 +7,14 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/core" - "github.com/google/uuid" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func NewSimulatedBackend(t *testing.T, alloc core.GenesisAlloc, gasLimit uint32) *backends.SimulatedBackend { @@ -39,11 +37,10 @@ func NewApplicationWithConfigV2OnSimulatedBlockchain( } require.Zero(t, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()).Cmp(testutils.SimulatedChainID)) - chainID := utils.NewBig(testutils.SimulatedChainID) + chainID := big.New(testutils.SimulatedChainID) client := client.NewSimulatedBackendClient(t, backend, testutils.SimulatedChainID) - eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) - flagsAndDeps = append(flagsAndDeps, client, eventBroadcaster, chainID) + flagsAndDeps = append(flagsAndDeps, client, chainID) // app.Stop() will call client.Close on the simulated backend app := NewApplicationWithConfig(t, cfg, flagsAndDeps...) @@ -64,11 +61,10 @@ func NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain( } require.Zero(t, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()).Cmp(testutils.SimulatedChainID)) - chainID := utils.NewBig(testutils.SimulatedChainID) + chainID := big.New(testutils.SimulatedChainID) client := client.NewSimulatedBackendClient(t, backend, testutils.SimulatedChainID) - eventBroadcaster := pg.NewEventBroadcaster(cfg.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) - flagsAndDeps = append(flagsAndDeps, client, eventBroadcaster, chainID) + flagsAndDeps = append(flagsAndDeps, client, chainID) // app.Stop() will call client.Close on the simulated backend return NewApplicationWithConfigAndKey(t, cfg, flagsAndDeps...) diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 35fd3a31ff8..1c4d097d633 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -21,7 +21,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/rpc" "github.com/google/uuid" @@ -37,16 +36,19 @@ import ( ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" "github.com/smartcontractkit/libocr/gethwrappers/testoffchainaggregator" - ocrnetworking "github.com/smartcontractkit/libocr/networking" "github.com/smartcontractkit/libocr/offchainreporting/confighelper" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" evmtypes "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/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/consumer_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flags_wrapper" @@ -85,7 +87,7 @@ func TestIntegration_ExternalInitiatorV2(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.JobPipeline.ExternalInitiatorsEnabled = ptr(true) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(10 * time.Millisecond) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient, cltest.UseRealExternalInitiatorManager) @@ -362,7 +364,7 @@ func TestIntegration_DirectRequest(t *testing.T) { // Simulate a consumer contract calling to obtain ETH quotes in 3 different currencies // in a single callback. config := configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(100 * time.Millisecond) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) }) operatorContracts := setupOperatorContracts(t) @@ -380,7 +382,7 @@ func TestIntegration_DirectRequest(t *testing.T) { // Fund node account with ETH. n, err := b.NonceAt(testutils.Context(t), operatorContracts.user.From, nil) require.NoError(t, err) - tx = types.NewTransaction(n, sendingKeys[0].Address, assets.Ether(100).ToInt(), 21000, big.NewInt(1000000000), nil) + tx = cltest.NewLegacyTransaction(n, sendingKeys[0].Address, assets.Ether(100).ToInt(), 21000, big.NewInt(1000000000), nil) signedTx, err := operatorContracts.user.Signer(operatorContracts.user.From, tx) require.NoError(t, err) err = b.SendTransaction(testutils.Context(t), signedTx) @@ -467,7 +469,7 @@ func setupAppForEthTx(t *testing.T, operatorContracts OperatorContracts) (app *c lggr, o := logger.TestLoggerObserved(t, zapcore.DebugLevel) cfg := configtest.NewGeneralConfigSimulated(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(100 * time.Millisecond) }) app = cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, b, lggr) b.Commit() @@ -479,7 +481,7 @@ func setupAppForEthTx(t *testing.T, operatorContracts OperatorContracts) (app *c // Fund node account with ETH. n, err := b.NonceAt(testutils.Context(t), operatorContracts.user.From, nil) require.NoError(t, err) - tx := types.NewTransaction(n, sendingKeys[0].Address, assets.Ether(100).ToInt(), 21000, big.NewInt(1000000000), nil) + tx := cltest.NewLegacyTransaction(n, sendingKeys[0].Address, assets.Ether(100).ToInt(), 21000, big.NewInt(1000000000), nil) signedTx, err := operatorContracts.user.Signer(operatorContracts.user.From, tx) require.NoError(t, err) err = b.SendTransaction(testutils.Context(t), signedTx) @@ -522,8 +524,8 @@ observationSource = """ cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, testutils.WaitTimeout(t)) run := cltest.CreateJobRunViaUser(t, app, j.ExternalJobID, "") - assert.Equal(t, []*string([]*string(nil)), run.Outputs) - assert.Equal(t, []*string([]*string(nil)), run.Errors) + assert.Equal(t, []*string(nil), run.Outputs) + assert.Equal(t, []*string(nil), run.Errors) testutils.WaitForLogMessage(t, o, "Sending transaction") b.Commit() // Needs at least two confirmations @@ -568,8 +570,8 @@ observationSource = """ cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, testutils.WaitTimeout(t)) run := cltest.CreateJobRunViaUser(t, app, j.ExternalJobID, "") - assert.Equal(t, []*string([]*string(nil)), run.Outputs) - assert.Equal(t, []*string([]*string(nil)), run.Errors) + assert.Equal(t, []*string(nil), run.Outputs) + assert.Equal(t, []*string(nil), run.Errors) testutils.WaitForLogMessage(t, o, "Sending transaction") b.Commit() // Needs at least two confirmations @@ -606,8 +608,8 @@ observationSource = """ cltest.AwaitJobActive(t, app.JobSpawner(), j.ID, testutils.WaitTimeout(t)) run := cltest.CreateJobRunViaUser(t, app, j.ExternalJobID, "") - assert.Equal(t, []*string([]*string(nil)), run.Outputs) - assert.Equal(t, []*string([]*string(nil)), run.Errors) + assert.Equal(t, []*string(nil), run.Outputs) + assert.Equal(t, []*string(nil), run.Errors) testutils.WaitForLogMessage(t, o, "Sending transaction") b.Commit() // Needs at least two confirmations @@ -675,8 +677,8 @@ func setupOCRContracts(t *testing.T) (*bind.TransactOpts, *backends.SimulatedBac return owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress } -func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, - b *backends.SimulatedBackend, ns ocrnetworking.NetworkingStack, overrides func(c *chainlink.Config, s *chainlink.Secrets), +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) { p2pKey := keystest.NewP2PKeyV2(t) config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -686,35 +688,13 @@ func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, c.OCR2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - switch ns { - case ocrnetworking.NetworkingStackV1: - c.P2P.V1.Enabled = ptr(true) - c.P2P.V2.Enabled = ptr(false) - // We want to quickly poll for the bootstrap node to come up, but if we poll too quickly - // we'll flood it with messages and slow things down. 5s is about how long it takes the - // bootstrap node to come up. - c.P2P.V1.BootstrapCheckInterval = models.MustNewDuration(5 * time.Second) - c.P2P.V1.ListenPort = ptr(uint16(portV1)) - - case ocrnetworking.NetworkingStackV2: - c.P2P.V1.Enabled = ptr(false) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) - - case ocrnetworking.NetworkingStackV1V2: - c.P2P.V1.Enabled = ptr(true) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V1.BootstrapCheckInterval = models.MustNewDuration(5 * time.Second) - // Note v1 and v2 ports must be distinct, - // v1v2 mode will listen on both. - c.P2P.V1.ListenPort = ptr(uint16(portV1)) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) - } + + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) // GracePeriod < ObservationTimeout - c.EVM[0].OCR.ObservationGracePeriod = models.MustNewDuration(100 * time.Millisecond) + c.EVM[0].OCR.ObservationGracePeriod = commonconfig.MustNewDuration(100 * time.Millisecond) if overrides != nil { overrides(c, s) @@ -731,7 +711,7 @@ func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, n, err := b.NonceAt(testutils.Context(t), owner.From, nil) require.NoError(t, err) - tx := types.NewTransaction(n, transmitter, assets.Ether(100).ToInt(), 21000, big.NewInt(1000000000), nil) + tx := cltest.NewLegacyTransaction(n, transmitter, assets.Ether(100).ToInt(), 21000, big.NewInt(1000000000), nil) signedTx, err := owner.Signer(owner.From, tx) require.NoError(t, err) err = b.SendTransaction(testutils.Context(t), signedTx) @@ -743,21 +723,7 @@ func setupNode(t *testing.T, owner *bind.TransactOpts, portV1, portV2 int, return app, p2pKey.PeerID().Raw(), transmitter, key } -func setupForwarderEnabledNode( - t *testing.T, - owner *bind.TransactOpts, - portV1, - portV2 int, - b *backends.SimulatedBackend, - ns ocrnetworking.NetworkingStack, - overrides func(c *chainlink.Config, s *chainlink.Secrets), -) ( - *cltest.TestApplication, - string, - common.Address, - common.Address, - ocrkey.KeyV2, -) { +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) { 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. @@ -766,32 +732,9 @@ func setupForwarderEnabledNode( c.OCR2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - switch ns { - case ocrnetworking.NetworkingStackV1: - c.P2P.V1.Enabled = ptr(true) - c.P2P.V2.Enabled = ptr(false) - // We want to quickly poll for the bootstrap node to come up, but if we poll too quickly - // we'll flood it with messages and slow things down. 5s is about how long it takes the - // bootstrap node to come up. - c.P2P.V1.BootstrapCheckInterval = models.MustNewDuration(5 * time.Second) - c.P2P.V1.ListenPort = ptr(uint16(portV1)) - - case ocrnetworking.NetworkingStackV2: - c.P2P.V1.Enabled = ptr(false) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) - - case ocrnetworking.NetworkingStackV1V2: - c.P2P.V1.Enabled = ptr(true) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V1.BootstrapCheckInterval = models.MustNewDuration(5 * time.Second) - // Note v1 and v2 ports must be distinct, - // v1v2 mode will listen on both. - c.P2P.V1.ListenPort = ptr(uint16(portV1)) - c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) - } + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", portV2)} + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) c.EVM[0].Transactions.ForwardersEnabled = ptr(true) @@ -810,7 +753,7 @@ func setupForwarderEnabledNode( n, err := b.NonceAt(testutils.Context(t), owner.From, nil) require.NoError(t, err) - tx := types.NewTransaction(n, transmitter, assets.Ether(100).ToInt(), 21000, big.NewInt(1000000000), nil) + tx := cltest.NewLegacyTransaction(n, transmitter, assets.Ether(100).ToInt(), 21000, big.NewInt(1000000000), nil) signedTx, err := owner.Signer(owner.From, tx) require.NoError(t, err) err = b.SendTransaction(testutils.Context(t), signedTx) @@ -831,7 +774,7 @@ func setupForwarderEnabledNode( // add forwarder address to be tracked in db forwarderORM := forwarders.NewORM(app.GetSqlxDB(), logger.TestLogger(t), config.Database()) - chainID := utils.Big(*b.Blockchain().Config().ChainID) + chainID := ubig.Big(*b.Blockchain().Config().ChainID) _, err = forwarderORM.CreateForwarder(forwarder, chainID) require.NoError(t, err) @@ -842,16 +785,12 @@ func TestIntegration_OCR(t *testing.T) { testutils.SkipShort(t, "long test") t.Parallel() tests := []struct { - id int - portStart int // Test need to run in parallel, all need distinct port ranges. - name string - eip1559 bool - ns ocrnetworking.NetworkingStack + id int + name string + eip1559 bool }{ - {1, 20000, "legacy mode", false, ocrnetworking.NetworkingStackV1}, - {2, 20010, "eip1559 mode", true, ocrnetworking.NetworkingStackV1}, - {3, 20020, "legacy mode V1V2", false, ocrnetworking.NetworkingStackV1V2}, - {4, 20030, "legacy mode V2", false, ocrnetworking.NetworkingStackV2}, + {1, "legacy mode", false}, + {2, "eip1559 mode", true}, } numOracles := 4 @@ -859,31 +798,27 @@ func TestIntegration_OCR(t *testing.T) { test := tt t.Run(test.name, func(t *testing.T) { t.Parallel() - bootstrapNodePortV1 := freeport.GetOne(t) bootstrapNodePortV2 := freeport.GetOne(t) g := gomega.NewWithT(t) owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress := setupOCRContracts(t) // Note it's plausible these ports could be occupied on a CI machine. // May need a port randomize + retry approach if we observe collisions. - appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV1, bootstrapNodePortV2, b, test.ns, nil) + appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV2, b, nil) var ( oracles []confighelper.OracleIdentityExtra transmitters []common.Address keys []ocrkey.KeyV2 apps []*cltest.TestApplication ) - ports := freeport.GetN(t, 2*numOracles) + ports := freeport.GetN(t, numOracles) for i := 0; i < numOracles; i++ { - portV1 := ports[2*i] - portV2 := ports[2*i+1] - app, peerID, transmitter, key := setupNode(t, owner, portV1, portV2, b, test.ns, func(c *chainlink.Config, s *chainlink.Secrets) { + app, peerID, transmitter, key := setupNode(t, owner, ports[i], b, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(test.eip1559) - if test.ns != ocrnetworking.NetworkingStackV1 { - c.P2P.V2.DefaultBootstrappers = &[]ocrcommontypes.BootstrapperLocator{ - {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePortV2)}}, - } + + c.P2P.V2.DefaultBootstrappers = &[]ocrcommontypes.BootstrapperLocator{ + {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePortV2)}}, } }) @@ -947,7 +882,7 @@ isBootstrapPeer = true // Raising flags to initiate hibernation _, err = flagsContract.RaiseFlag(owner, ocrContractAddress) require.NoError(t, err, "failed to raise flag for ocrContractAddress") - _, err = flagsContract.RaiseFlag(owner, utils.ZeroAddress) + _, err = flagsContract.RaiseFlag(owner, evmutils.ZeroAddress) require.NoError(t, err, "failed to raise flag for ZeroAddress") b.Commit() @@ -1007,9 +942,6 @@ name = "web oracle spec" contractAddress = "%s" evmChainID = "%s" isBootstrapPeer = false -p2pBootstrapPeers = [ - "/ip4/127.0.0.1/tcp/%d/p2p/%s" -] keyBundleID = "%s" transmitterAddress = "%s" observationTimeout = "100ms" @@ -1031,7 +963,7 @@ observationSource = """ answer1 [type=median index=0]; """ -`, ocrContractAddress, testutils.SimulatedChainID.String(), bootstrapNodePortV1, bootstrapPeerID, keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) +`, ocrContractAddress, testutils.SimulatedChainID.String(), keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) require.NoError(t, err) jb.Name = null.NewString("testocr", true) err = apps[i].AddJobV2(testutils.Context(t), &jb) @@ -1084,14 +1016,13 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { t.Parallel() numOracles := 4 t.Run("ocr_forwarder_flow", func(t *testing.T) { - bootstrapNodePortV1 := freeport.GetOne(t) bootstrapNodePortV2 := freeport.GetOne(t) g := gomega.NewWithT(t) owner, b, ocrContractAddress, ocrContract, flagsContract, flagsContractAddress := setupOCRContracts(t) // Note it's plausible these ports could be occupied on a CI machine. // May need a port randomize + retry approach if we observe collisions. - appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV1, bootstrapNodePortV2, b, ocrnetworking.NetworkingStackV2, nil) + appBootstrap, bootstrapPeerID, _, _ := setupNode(t, owner, bootstrapNodePortV2, b, nil) var ( oracles []confighelper.OracleIdentityExtra @@ -1100,11 +1031,9 @@ func TestIntegration_OCR_ForwarderFlow(t *testing.T) { keys []ocrkey.KeyV2 apps []*cltest.TestApplication ) - ports := freeport.GetN(t, 2*numOracles) + ports := freeport.GetN(t, numOracles) for i := 0; i < numOracles; i++ { - portV1 := ports[2*i] - portV2 := ports[2*i+1] - app, peerID, transmitter, forwarder, key := setupForwarderEnabledNode(t, owner, portV1, portV2, b, ocrnetworking.NetworkingStackV2, func(c *chainlink.Config, s *chainlink.Secrets) { + app, peerID, transmitter, forwarder, key := setupForwarderEnabledNode(t, owner, ports[i], b, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.EVM[0].FlagsContractAddress = ptr(ethkey.EIP55AddressFromAddress(flagsContractAddress)) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) @@ -1179,7 +1108,7 @@ isBootstrapPeer = true // Raising flags to initiate hibernation _, err = flagsContract.RaiseFlag(owner, ocrContractAddress) require.NoError(t, err, "failed to raise flag for ocrContractAddress") - _, err = flagsContract.RaiseFlag(owner, utils.ZeroAddress) + _, err = flagsContract.RaiseFlag(owner, evmutils.ZeroAddress) require.NoError(t, err, "failed to raise flag for ZeroAddress") b.Commit() @@ -1241,9 +1170,6 @@ contractAddress = "%s" evmChainID = "%s" forwardingAllowed = true isBootstrapPeer = false -p2pBootstrapPeers = [ - "/ip4/127.0.0.1/tcp/%d/p2p/%s" -] keyBundleID = "%s" transmitterAddress = "%s" observationTimeout = "100ms" @@ -1265,7 +1191,7 @@ observationSource = """ answer1 [type=median index=0]; """ -`, ocrContractAddress, testutils.SimulatedChainID.String(), bootstrapNodePortV1, bootstrapPeerID, keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) +`, ocrContractAddress, testutils.SimulatedChainID.String(), keys[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) require.NoError(t, err) jb.Name = null.NewString("testocr", true) err = apps[i].AddJobV2(testutils.Context(t), &jb) @@ -1340,22 +1266,22 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { b41 := evmtypes.Block{ Number: 41, - Hash: utils.NewHash(), + Hash: evmutils.NewHash(), Transactions: cltest.LegacyTransactionsFromGasPrices(41_000_000_000, 41_500_000_000), } b42 := evmtypes.Block{ Number: 42, - Hash: utils.NewHash(), + Hash: evmutils.NewHash(), Transactions: cltest.LegacyTransactionsFromGasPrices(44_000_000_000, 45_000_000_000), } b43 := evmtypes.Block{ Number: 43, - Hash: utils.NewHash(), + Hash: evmutils.NewHash(), Transactions: cltest.LegacyTransactionsFromGasPrices(48_000_000_000, 49_000_000_000, 31_000_000_000), } - evmChainID := utils.NewBig(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) - h40 := evmtypes.Head{Hash: utils.NewHash(), Number: 40, EVMChainID: evmChainID} + evmChainID := ubig.New(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) + h40 := evmtypes.Head{Hash: evmutils.NewHash(), Number: 40, EVMChainID: evmChainID} h41 := evmtypes.Head{Hash: b41.Hash, ParentHash: h40.Hash, Number: 41, EVMChainID: evmChainID} h42 := evmtypes.Head{Hash: b42.Hash, ParentHash: h41.Hash, Number: 42, EVMChainID: evmChainID} @@ -1394,7 +1320,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(cc) for _, re := range cc.Slice() { - require.NoError(t, re.Start(testutils.Context(t))) + servicetest.Run(t, re) } var newHeads evmtest.RawSub[*evmtypes.Head] select { @@ -1418,6 +1344,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { elems := args.Get(1).([]rpc.BatchElem) elems[0].Result = &b43 }) + ethClient.On("Close").Return().Once() // Simulate one new head and check the gas price got updated h43 := cltest.Head(43) diff --git a/core/internal/features/ocr2/features_ocr2_plugin_test.go b/core/internal/features/ocr2/features_ocr2_plugin_test.go new file mode 100644 index 00000000000..96a9f32e957 --- /dev/null +++ b/core/internal/features/ocr2/features_ocr2_plugin_test.go @@ -0,0 +1,14 @@ +//go:build integration + +package ocr2_test + +import ( + "testing" + + "github.com/smartcontractkit/chainlink/v2/core/config/env" +) + +func TestIntegration_OCR2_plugins(t *testing.T) { + t.Setenv(string(env.MedianPlugin.Cmd), "chainlink-feeds") + testIntegration_OCR2(t) +} diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 387b15f76c8..938b7aa2a66 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -34,9 +34,12 @@ import ( confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -51,7 +54,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ocr2Node struct { @@ -119,16 +121,15 @@ func setupNodeOCR2( c.OCR2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - c.P2P.V1.Enabled = ptr(false) c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", port)} if len(p2pV2Bootstrappers) > 0 { c.P2P.V2.DefaultBootstrappers = &p2pV2Bootstrappers } - c.EVM[0].LogPollInterval = models.MustNewDuration(5 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(5 * time.Second) c.EVM[0].Transactions.ForwardersEnabled = &useForwarder }) @@ -144,7 +145,7 @@ func setupNodeOCR2( n, err := b.NonceAt(testutils.Context(t), owner.From, nil) require.NoError(t, err) - tx := types.NewTransaction( + tx := cltest.NewLegacyTransaction( n, transmitter, assets.Ether(1).ToInt(), 21000, @@ -171,7 +172,7 @@ func setupNodeOCR2( // add forwarder address to be tracked in db forwarderORM := forwarders.NewORM(app.GetSqlxDB(), logger.TestLogger(t), config.Database()) - chainID := utils.Big(*b.Blockchain().Config().ChainID) + chainID := ubig.Big(*b.Blockchain().Config().ChainID) _, err2 = forwarderORM.CreateForwarder(faddr, chainID) require.NoError(t, err2) @@ -188,50 +189,63 @@ func setupNodeOCR2( func TestIntegration_OCR2(t *testing.T) { t.Parallel() - owner, b, ocrContractAddress, ocrContract := setupOCR2Contracts(t) - - lggr := logger.TestLogger(t) - bootstrapNodePort := freeport.GetOne(t) - bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, false /* useForwarders */, b, nil) - - var ( - oracles []confighelper2.OracleIdentityExtra - transmitters []common.Address - kbs []ocr2key.KeyBundle - apps []*cltest.TestApplication - ) - ports := freeport.GetN(t, 4) - for i := 0; i < 4; i++ { - node := setupNodeOCR2(t, owner, ports[i], false /* useForwarders */, b, []commontypes.BootstrapperLocator{ - // Supply the bootstrap IP and port as a V2 peer address - {PeerID: bootstrapNode.peerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }) - - kbs = append(kbs, node.keybundle) - apps = append(apps, node.app) - transmitters = append(transmitters, node.transmitter) + testIntegration_OCR2(t) +} - oracles = append(oracles, confighelper2.OracleIdentityExtra{ - OracleIdentity: confighelper2.OracleIdentity{ - OnchainPublicKey: node.keybundle.PublicKey(), - TransmitAccount: ocrtypes2.Account(node.transmitter.String()), - OffchainPublicKey: node.keybundle.OffchainPublicKey(), - PeerID: node.peerID, - }, - ConfigEncryptionPublicKey: node.keybundle.ConfigEncryptionPublicKey(), - }) - } +func testIntegration_OCR2(t *testing.T) { + for _, test := range []struct { + name string + chainReaderAndCodec bool + }{ + {"legacy", false}, + {"chain-reader", true}, + } { + test := test + t.Run(test.name, func(t *testing.T) { + owner, b, ocrContractAddress, ocrContract := setupOCR2Contracts(t) + + lggr := logger.TestLogger(t) + bootstrapNodePort := freeport.GetOne(t) + bootstrapNode := setupNodeOCR2(t, owner, bootstrapNodePort, false /* useForwarders */, b, nil) + + var ( + oracles []confighelper2.OracleIdentityExtra + transmitters []common.Address + kbs []ocr2key.KeyBundle + apps []*cltest.TestApplication + ) + ports := freeport.GetN(t, 4) + for i := 0; i < 4; i++ { + node := setupNodeOCR2(t, owner, ports[i], false /* useForwarders */, b, []commontypes.BootstrapperLocator{ + // Supply the bootstrap IP and port as a V2 peer address + {PeerID: bootstrapNode.peerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, + }) + + kbs = append(kbs, node.keybundle) + apps = append(apps, node.app) + transmitters = append(transmitters, node.transmitter) + + oracles = append(oracles, confighelper2.OracleIdentityExtra{ + OracleIdentity: confighelper2.OracleIdentity{ + OnchainPublicKey: node.keybundle.PublicKey(), + TransmitAccount: ocrtypes2.Account(node.transmitter.String()), + OffchainPublicKey: node.keybundle.OffchainPublicKey(), + PeerID: node.peerID, + }, + ConfigEncryptionPublicKey: node.keybundle.ConfigEncryptionPublicKey(), + }) + } - tick := time.NewTicker(1 * time.Second) - defer tick.Stop() - go func() { - for range tick.C { - b.Commit() - } - }() + tick := time.NewTicker(1 * time.Second) + defer tick.Stop() + go func() { + for range tick.C { + b.Commit() + } + }() - blockBeforeConfig := initOCR2(t, lggr, b, ocrContract, owner, bootstrapNode, oracles, transmitters, transmitters, func(blockNum int64) string { - return fmt.Sprintf(` + blockBeforeConfig := initOCR2(t, lggr, b, ocrContract, owner, bootstrapNode, oracles, transmitters, transmitters, func(blockNum int64) string { + return fmt.Sprintf(` type = "bootstrap" name = "bootstrap" relay = "evm" @@ -241,54 +255,189 @@ contractID = "%s" chainID = 1337 fromBlock = %d `, ocrContractAddress, blockNum) - }) - - var jids []int32 - var servers, slowServers = make([]*httptest.Server, 4), make([]*httptest.Server, 4) - // We expect metadata of: - // latestAnswer:nil // First call - // latestAnswer:0 - // latestAnswer:10 - // latestAnswer:20 - // latestAnswer:30 - var metaLock sync.Mutex - expectedMeta := map[string]struct{}{ - "0": {}, "10": {}, "20": {}, "30": {}, - } - for i := 0; i < 4; i++ { - s := i - require.NoError(t, apps[i].Start(testutils.Context(t))) - - // API speed is > observation timeout set in ContractSetConfigArgsForIntegrationTest - slowServers[i] = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { - time.Sleep(5 * time.Second) - res.WriteHeader(http.StatusOK) - _, err := res.Write([]byte(`{"data":10}`)) - require.NoError(t, err) - })) - t.Cleanup(slowServers[s].Close) - servers[i] = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { - b, err := io.ReadAll(req.Body) - require.NoError(t, err) - var m bridges.BridgeMetaDataJSON - require.NoError(t, json.Unmarshal(b, &m)) - if m.Meta.LatestAnswer != nil && m.Meta.UpdatedAt != nil { - metaLock.Lock() - delete(expectedMeta, m.Meta.LatestAnswer.String()) - metaLock.Unlock() + }) + + var jids []int32 + var servers, slowServers = make([]*httptest.Server, 4), make([]*httptest.Server, 4) + // We expect metadata of: + // latestAnswer:nil // First call + // latestAnswer:0 + // latestAnswer:10 + // latestAnswer:20 + // latestAnswer:30 + var metaLock sync.Mutex + expectedMeta := map[string]struct{}{ + "0": {}, "10": {}, "20": {}, "30": {}, } - res.WriteHeader(http.StatusOK) - _, err = res.Write([]byte(`{"data":10}`)) - require.NoError(t, err) - })) - t.Cleanup(servers[s].Close) - u, _ := url.Parse(servers[i].URL) - require.NoError(t, apps[i].BridgeORM().CreateBridgeType(&bridges.BridgeType{ - Name: bridges.BridgeName(fmt.Sprintf("bridge%d", i)), - URL: models.WebURL(*u), - })) - - ocrJob, err := validate.ValidatedOracleSpecToml(apps[i].Config.OCR2(), apps[i].Config.Insecure(), fmt.Sprintf(` + returnData := int(10) + for i := 0; i < 4; i++ { + s := i + require.NoError(t, apps[i].Start(testutils.Context(t))) + + // API speed is > observation timeout set in ContractSetConfigArgsForIntegrationTest + slowServers[i] = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + time.Sleep(5 * time.Second) + var result string + metaLock.Lock() + result = fmt.Sprintf(`{"data":%d}`, returnData) + metaLock.Unlock() + res.WriteHeader(http.StatusOK) + t.Logf("Slow Bridge %d returning data:10", s) + _, err := res.Write([]byte(result)) + require.NoError(t, err) + })) + t.Cleanup(slowServers[s].Close) + servers[i] = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) { + b, err := io.ReadAll(req.Body) + require.NoError(t, err) + var m bridges.BridgeMetaDataJSON + require.NoError(t, json.Unmarshal(b, &m)) + var result string + metaLock.Lock() + result = fmt.Sprintf(`{"data":%d}`, returnData) + metaLock.Unlock() + if m.Meta.LatestAnswer != nil && m.Meta.UpdatedAt != nil { + t.Logf("Bridge %d deleting %s, from request body: %s", s, m.Meta.LatestAnswer, b) + metaLock.Lock() + delete(expectedMeta, m.Meta.LatestAnswer.String()) + metaLock.Unlock() + } + res.WriteHeader(http.StatusOK) + _, err = res.Write([]byte(result)) + require.NoError(t, err) + })) + t.Cleanup(servers[s].Close) + u, _ := url.Parse(servers[i].URL) + require.NoError(t, apps[i].BridgeORM().CreateBridgeType(&bridges.BridgeType{ + Name: bridges.BridgeName(fmt.Sprintf("bridge%d", i)), + URL: models.WebURL(*u), + })) + + var chainReaderSpec string + if test.chainReaderAndCodec { + chainReaderSpec = ` +[relayConfig.chainReader.contracts.median] +contractABI = ''' +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "round", + "type": "uint8" + } + ], + "name": "RoundRequested", + "type": "event" + }, + { + "inputs": [], + "name": "latestTransmissionDetails", + "outputs": [ + { + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "round", + "type": "uint8" + }, + { + "internalType": "int192", + "name": "latestAnswer_", + "type": "int192" + }, + { + "internalType": "uint64", + "name": "latestTimestamp_", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + } +] +''' + +[relayConfig.chainReader.contracts.median.configs] +LatestRoundRequested = ''' +{ + "chainSpecificName": "RoundRequested", + "readType": "event" +} +''' +LatestTransmissionDetails = ''' +{ + "chainSpecificName": "latestTransmissionDetails", + "outputModifications": [ + { + "Fields": [ + "LatestTimestamp_" + ], + "type": "epoch to time" + }, + { + "Fields": { + "LatestAnswer_": "LatestAnswer", + "LatestTimestamp_": "LatestTimestamp" + }, + "type": "rename" + } + ] +} +''' + +[relayConfig.codec.configs.MedianReport] +typeABI = ''' +[ + { + "Name": "Timestamp", + "Type": "uint32" + }, + { + "Name": "Observers", + "Type": "bytes32" + }, + { + "Name": "Observations", + "Type": "int192[]" + }, + { + "Name": "JuelsPerFeeCoin", + "Type": "int192" + } +] +''' +` + } + ocrJob, err := validate.ValidatedOracleSpecToml(apps[i].Config.OCR2(), apps[i].Config.Insecure(), fmt.Sprintf(` type = "offchainreporting2" relay = "evm" schemaVersion = 1 @@ -315,9 +464,12 @@ observationSource = """ answer1 [type=median index=0]; """ + [relayConfig] chainID = 1337 fromBlock = %d +%s + [pluginConfig] juelsPerFeeCoinSource = """ // data source 1 @@ -335,72 +487,131 @@ juelsPerFeeCoinSource = """ answer1 [type=median index=0]; """ -`, ocrContractAddress, kbs[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i, blockBeforeConfig.Number().Int64(), fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) - require.NoError(t, err) - err = apps[i].AddJobV2(testutils.Context(t), &ocrJob) - require.NoError(t, err) - jids = append(jids, ocrJob.ID) - } +`, ocrContractAddress, kbs[i].ID(), transmitters[i], fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i, blockBeforeConfig.Number().Int64(), chainReaderSpec, fmt.Sprintf("bridge%d", i), i, slowServers[i].URL, i)) + require.NoError(t, err) + err = apps[i].AddJobV2(testutils.Context(t), &ocrJob) + require.NoError(t, err) + jids = append(jids, ocrJob.ID) + } - // Assert that all the OCR jobs get a run with valid values eventually. - var wg sync.WaitGroup - for i := 0; i < 4; i++ { - ic := i - wg.Add(1) - go func() { - defer wg.Done() - // Want at least 2 runs so we see all the metadata. - pr := cltest.WaitForPipelineComplete(t, ic, jids[ic], 2, 7, apps[ic].JobORM(), 2*time.Minute, 5*time.Second) - jb, err := pr[0].Outputs.MarshalJSON() + // Watch for OCR2AggregatorTransmitted events + start := uint64(0) + txEvents := make(chan *ocr2aggregator.OCR2AggregatorTransmitted) + _, err := ocrContract.WatchTransmitted(&bind.WatchOpts{Start: &start, Context: testutils.Context(t)}, txEvents) require.NoError(t, err) - assert.Equal(t, []byte(fmt.Sprintf("[\"%d\"]", 10*ic)), jb, "pr[0] %+v pr[1] %+v", pr[0], pr[1]) + newTxEvents := make(chan *ocr2aggregator.OCR2AggregatorNewTransmission) + _, err = ocrContract.WatchNewTransmission(&bind.WatchOpts{Start: &start, Context: testutils.Context(t)}, newTxEvents, []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) require.NoError(t, err) - }() - } - wg.Wait() - // 4 oracles reporting 0, 10, 20, 30. Answer should be 20 (results[4/2]). - gomega.NewGomegaWithT(t).Eventually(func() string { - answer, err := ocrContract.LatestAnswer(nil) - require.NoError(t, err) - return answer.String() - }, 1*time.Minute, 200*time.Millisecond).Should(gomega.Equal("20")) + go func() { + var newTxEvent *ocr2aggregator.OCR2AggregatorNewTransmission + select { + case txEvent := <-txEvents: + t.Logf("txEvent: %v", txEvent) + if newTxEvent != nil { + assert.Equal(t, txEvent.Epoch, uint32(newTxEvent.EpochAndRound.Uint64())) + } + case newTxEvent = <-newTxEvents: + t.Logf("newTxEvent: %v", newTxEvent) + } + }() - for _, app := range apps { - jobs, _, err := app.JobORM().FindJobs(0, 1000) - require.NoError(t, err) - // No spec errors - for _, j := range jobs { - ignore := 0 - for i := range j.JobSpecErrors { - // Non-fatal timing related error, ignore for testing. - if strings.Contains(j.JobSpecErrors[i].Description, "leader's phase conflicts tGrace timeout") { - ignore++ + for trial := 0; trial < 2; trial++ { + var retVal int + + metaLock.Lock() + returnData = 10 * (trial + 1) + retVal = returnData + for i := 0; i < 4; i++ { + expectedMeta[fmt.Sprintf("%d", returnData*i)] = struct{}{} + } + metaLock.Unlock() + + // Assert that all the OCR jobs get a run with valid values eventually. + var wg sync.WaitGroup + for i := 0; i < 4; i++ { + ic := i + wg.Add(1) + go func() { + defer wg.Done() + completedRuns, err2 := apps[ic].JobORM().FindPipelineRunIDsByJobID(jids[ic], 0, 1000) + require.NoError(t, err2) + // Want at least 2 runs so we see all the metadata. + pr := cltest.WaitForPipelineComplete(t, ic, jids[ic], len(completedRuns)+2, 7, apps[ic].JobORM(), 2*time.Minute, 5*time.Second) + jb, err2 := pr[0].Outputs.MarshalJSON() + require.NoError(t, err2) + assert.Equal(t, []byte(fmt.Sprintf("[\"%d\"]", retVal*ic)), jb, "pr[0] %+v pr[1] %+v", pr[0], pr[1]) + require.NoError(t, err2) + }() + } + wg.Wait() + + // Trail #1: 4 oracles reporting 0, 10, 20, 30. Answer should be 20 (results[4/2]). + // Trial #2: 4 oracles reporting 0, 20, 40, 60. Answer should be 40 (results[4/2]). + gomega.NewGomegaWithT(t).Eventually(func() string { + answer, err2 := ocrContract.LatestAnswer(nil) + require.NoError(t, err2) + return answer.String() + }, 1*time.Minute, 200*time.Millisecond).Should(gomega.Equal(fmt.Sprintf("%d", 2*retVal))) + + for _, app := range apps { + jobs, _, err2 := app.JobORM().FindJobs(0, 1000) + require.NoError(t, err2) + // No spec errors + for _, j := range jobs { + ignore := 0 + for i := range j.JobSpecErrors { + // Non-fatal timing related error, ignore for testing. + if strings.Contains(j.JobSpecErrors[i].Description, "leader's phase conflicts tGrace timeout") { + ignore++ + } + } + require.Len(t, j.JobSpecErrors, ignore) + } + } + em := map[string]struct{}{} + metaLock.Lock() + maps.Copy(em, expectedMeta) + metaLock.Unlock() + assert.Len(t, em, 0, "expected metadata %v", em) + + t.Logf("======= Summary =======") + roundId, err2 := ocrContract.LatestRound(nil) + require.NoError(t, err2) + for i := 0; i <= int(roundId.Int64()); i++ { + roundData, err3 := ocrContract.GetRoundData(nil, big.NewInt(int64(i))) + require.NoError(t, err3) + t.Logf("RoundId: %d, AnsweredInRound: %d, Answer: %d, StartedAt: %v, UpdatedAt: %v", roundData.RoundId, roundData.AnsweredInRound, roundData.Answer, roundData.StartedAt, roundData.UpdatedAt) + } + + expectedAnswer := big.NewInt(2 * int64(retVal)) + + // Assert we can read the latest config digest and epoch after a report has been submitted. + contractABI, err2 := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) + require.NoError(t, err2) + apps[0].GetRelayers().LegacyEVMChains().Slice() + ct, err2 := evm.NewOCRContractTransmitter(ocrContractAddress, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].Client(), contractABI, nil, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].LogPoller(), lggr, nil) + require.NoError(t, err2) + configDigest, epoch, err2 := ct.LatestConfigDigestAndEpoch(testutils.Context(t)) + require.NoError(t, err2) + details, err2 := ocrContract.LatestConfigDetails(nil) + require.NoError(t, err2) + assert.True(t, bytes.Equal(configDigest[:], details.ConfigDigest[:])) + digestAndEpoch, err2 := ocrContract.LatestConfigDigestAndEpoch(nil) + require.NoError(t, err2) + assert.Equal(t, digestAndEpoch.Epoch, epoch) + latestTransmissionDetails, err2 := ocrContract.LatestTransmissionDetails(nil) + require.NoError(t, err2) + assert.Equal(t, expectedAnswer, latestTransmissionDetails.LatestAnswer) + require.NoError(t, err2) + newTransmissionEvents, err2 := ocrContract.FilterTransmitted(&bind.FilterOpts{Start: 0, End: nil}) + require.NoError(t, err2) + for newTransmissionEvents.Next() { + assert.Equal(t, 3, newTransmissionEvents.Event.Epoch) } } - require.Len(t, j.JobSpecErrors, ignore) - } + }) } - em := map[string]struct{}{} - metaLock.Lock() - maps.Copy(em, expectedMeta) - metaLock.Unlock() - assert.Len(t, em, 0, "expected metadata %v", em) - - // Assert we can read the latest config digest and epoch after a report has been submitted. - contractABI, err := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) - require.NoError(t, err) - apps[0].GetRelayers().LegacyEVMChains().Slice() - ct, err := evm.NewOCRContractTransmitter(ocrContractAddress, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].Client(), contractABI, nil, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].LogPoller(), lggr, nil) - require.NoError(t, err) - configDigest, epoch, err := ct.LatestConfigDigestAndEpoch(testutils.Context(t)) - require.NoError(t, err) - details, err := ocrContract.LatestConfigDetails(nil) - require.NoError(t, err) - assert.True(t, bytes.Equal(configDigest[:], details.ConfigDigest[:])) - digestAndEpoch, err := ocrContract.LatestConfigDigestAndEpoch(nil) - require.NoError(t, err) - assert.Equal(t, digestAndEpoch.Epoch, epoch) } func initOCR2(t *testing.T, lggr logger.Logger, b *backends.SimulatedBackend, diff --git a/core/internal/mocks/application.go b/core/internal/mocks/application.go index 48f8e12dac3..20874e4b60e 100644 --- a/core/internal/mocks/application.go +++ b/core/internal/mocks/application.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -53,6 +53,10 @@ type Application struct { func (_m *Application) AddJobV2(ctx context.Context, _a1 *job.Job) error { ret := _m.Called(ctx, _a1) + if len(ret) == 0 { + panic("no return value specified for AddJobV2") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *job.Job) error); ok { r0 = rf(ctx, _a1) @@ -67,6 +71,10 @@ func (_m *Application) AddJobV2(ctx context.Context, _a1 *job.Job) error { func (_m *Application) AuthenticationProvider() sessions.AuthenticationProvider { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AuthenticationProvider") + } + var r0 sessions.AuthenticationProvider if rf, ok := ret.Get(0).(func() sessions.AuthenticationProvider); ok { r0 = rf() @@ -83,6 +91,10 @@ func (_m *Application) AuthenticationProvider() sessions.AuthenticationProvider func (_m *Application) BasicAdminUsersORM() sessions.BasicAdminUsersORM { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BasicAdminUsersORM") + } + var r0 sessions.BasicAdminUsersORM if rf, ok := ret.Get(0).(func() sessions.BasicAdminUsersORM); ok { r0 = rf() @@ -99,6 +111,10 @@ func (_m *Application) BasicAdminUsersORM() sessions.BasicAdminUsersORM { func (_m *Application) BridgeORM() bridges.ORM { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for BridgeORM") + } + var r0 bridges.ORM if rf, ok := ret.Get(0).(func() bridges.ORM); ok { r0 = rf() @@ -115,6 +131,10 @@ func (_m *Application) BridgeORM() bridges.ORM { func (_m *Application) DeleteJob(ctx context.Context, jobID int32) error { ret := _m.Called(ctx, jobID) + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int32) error); ok { r0 = rf(ctx, jobID) @@ -129,6 +149,10 @@ func (_m *Application) DeleteJob(ctx context.Context, jobID int32) error { func (_m *Application) EVMORM() types.Configs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVMORM") + } + var r0 types.Configs if rf, ok := ret.Get(0).(func() types.Configs); ok { r0 = rf() @@ -145,6 +169,10 @@ func (_m *Application) EVMORM() types.Configs { func (_m *Application) GetAuditLogger() audit.AuditLogger { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAuditLogger") + } + var r0 audit.AuditLogger if rf, ok := ret.Get(0).(func() audit.AuditLogger); ok { r0 = rf() @@ -161,6 +189,10 @@ func (_m *Application) GetAuditLogger() audit.AuditLogger { func (_m *Application) GetConfig() chainlink.GeneralConfig { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetConfig") + } + var r0 chainlink.GeneralConfig if rf, ok := ret.Get(0).(func() chainlink.GeneralConfig); ok { r0 = rf() @@ -177,6 +209,10 @@ func (_m *Application) GetConfig() chainlink.GeneralConfig { func (_m *Application) GetExternalInitiatorManager() webhook.ExternalInitiatorManager { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetExternalInitiatorManager") + } + var r0 webhook.ExternalInitiatorManager if rf, ok := ret.Get(0).(func() webhook.ExternalInitiatorManager); ok { r0 = rf() @@ -193,6 +229,10 @@ func (_m *Application) GetExternalInitiatorManager() webhook.ExternalInitiatorMa func (_m *Application) GetFeedsService() feeds.Service { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetFeedsService") + } + var r0 feeds.Service if rf, ok := ret.Get(0).(func() feeds.Service); ok { r0 = rf() @@ -209,6 +249,10 @@ func (_m *Application) GetFeedsService() feeds.Service { func (_m *Application) GetHealthChecker() services.Checker { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetHealthChecker") + } + var r0 services.Checker if rf, ok := ret.Get(0).(func() services.Checker); ok { r0 = rf() @@ -225,6 +269,10 @@ func (_m *Application) GetHealthChecker() services.Checker { func (_m *Application) GetKeyStore() keystore.Master { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetKeyStore") + } + var r0 keystore.Master if rf, ok := ret.Get(0).(func() keystore.Master); ok { r0 = rf() @@ -241,6 +289,10 @@ func (_m *Application) GetKeyStore() keystore.Master { func (_m *Application) GetLogger() logger.SugaredLogger { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetLogger") + } + var r0 logger.SugaredLogger if rf, ok := ret.Get(0).(func() logger.SugaredLogger); ok { r0 = rf() @@ -257,6 +309,10 @@ func (_m *Application) GetLogger() logger.SugaredLogger { func (_m *Application) GetLoopRegistry() *plugins.LoopRegistry { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetLoopRegistry") + } + var r0 *plugins.LoopRegistry if rf, ok := ret.Get(0).(func() *plugins.LoopRegistry); ok { r0 = rf() @@ -273,6 +329,10 @@ func (_m *Application) GetLoopRegistry() *plugins.LoopRegistry { func (_m *Application) GetRelayers() chainlink.RelayerChainInteroperators { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetRelayers") + } + var r0 chainlink.RelayerChainInteroperators if rf, ok := ret.Get(0).(func() chainlink.RelayerChainInteroperators); ok { r0 = rf() @@ -289,6 +349,10 @@ func (_m *Application) GetRelayers() chainlink.RelayerChainInteroperators { func (_m *Application) GetSqlxDB() *sqlx.DB { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetSqlxDB") + } + var r0 *sqlx.DB if rf, ok := ret.Get(0).(func() *sqlx.DB); ok { r0 = rf() @@ -305,6 +369,10 @@ func (_m *Application) GetSqlxDB() *sqlx.DB { func (_m *Application) GetWebAuthnConfiguration() sessions.WebAuthnConfiguration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetWebAuthnConfiguration") + } + var r0 sessions.WebAuthnConfiguration if rf, ok := ret.Get(0).(func() sessions.WebAuthnConfiguration); ok { r0 = rf() @@ -319,6 +387,10 @@ func (_m *Application) GetWebAuthnConfiguration() sessions.WebAuthnConfiguration func (_m *Application) ID() uuid.UUID { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ID") + } + var r0 uuid.UUID if rf, ok := ret.Get(0).(func() uuid.UUID); ok { r0 = rf() @@ -335,6 +407,10 @@ func (_m *Application) ID() uuid.UUID { func (_m *Application) JobORM() job.ORM { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for JobORM") + } + var r0 job.ORM if rf, ok := ret.Get(0).(func() job.ORM); ok { r0 = rf() @@ -351,6 +427,10 @@ func (_m *Application) JobORM() job.ORM { func (_m *Application) JobSpawner() job.Spawner { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for JobSpawner") + } + var r0 job.Spawner if rf, ok := ret.Get(0).(func() job.Spawner); ok { r0 = rf() @@ -367,6 +447,10 @@ func (_m *Application) JobSpawner() job.Spawner { func (_m *Application) PipelineORM() pipeline.ORM { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for PipelineORM") + } + var r0 pipeline.ORM if rf, ok := ret.Get(0).(func() pipeline.ORM); ok { r0 = rf() @@ -383,6 +467,10 @@ func (_m *Application) PipelineORM() pipeline.ORM { func (_m *Application) ReplayFromBlock(chainID *big.Int, number uint64, forceBroadcast bool) error { ret := _m.Called(chainID, number, forceBroadcast) + if len(ret) == 0 { + panic("no return value specified for ReplayFromBlock") + } + var r0 error if rf, ok := ret.Get(0).(func(*big.Int, uint64, bool) error); ok { r0 = rf(chainID, number, forceBroadcast) @@ -397,6 +485,10 @@ func (_m *Application) ReplayFromBlock(chainID *big.Int, number uint64, forceBro func (_m *Application) ResumeJobV2(ctx context.Context, taskID uuid.UUID, result pipeline.Result) error { ret := _m.Called(ctx, taskID, result) + if len(ret) == 0 { + panic("no return value specified for ResumeJobV2") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, pipeline.Result) error); ok { r0 = rf(ctx, taskID, result) @@ -411,6 +503,10 @@ func (_m *Application) ResumeJobV2(ctx context.Context, taskID uuid.UUID, result func (_m *Application) RunJobV2(ctx context.Context, jobID int32, meta map[string]interface{}) (int64, error) { ret := _m.Called(ctx, jobID, meta) + if len(ret) == 0 { + panic("no return value specified for RunJobV2") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, int32, map[string]interface{}) (int64, error)); ok { @@ -435,6 +531,10 @@ func (_m *Application) RunJobV2(ctx context.Context, jobID int32, meta map[strin func (_m *Application) RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, requestBody string, meta pipeline.JSONSerializable) (int64, error) { ret := _m.Called(ctx, jobUUID, requestBody, meta) + if len(ret) == 0 { + panic("no return value specified for RunWebhookJobV2") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, uuid.UUID, string, pipeline.JSONSerializable) (int64, error)); ok { @@ -459,6 +559,10 @@ func (_m *Application) RunWebhookJobV2(ctx context.Context, jobUUID uuid.UUID, r func (_m *Application) SecretGenerator() chainlink.SecretGenerator { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SecretGenerator") + } + var r0 chainlink.SecretGenerator if rf, ok := ret.Get(0).(func() chainlink.SecretGenerator); ok { r0 = rf() @@ -475,6 +579,10 @@ func (_m *Application) SecretGenerator() chainlink.SecretGenerator { func (_m *Application) 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) @@ -489,6 +597,10 @@ func (_m *Application) SetLogLevel(lvl zapcore.Level) error { func (_m *Application) Start(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -503,6 +615,10 @@ func (_m *Application) Start(ctx context.Context) error { func (_m *Application) Stop() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Stop") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -517,6 +633,10 @@ func (_m *Application) Stop() error { func (_m *Application) TxmStorageService() txmgr.EvmTxStore { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TxmStorageService") + } + var r0 txmgr.EvmTxStore if rf, ok := ret.Get(0).(func() txmgr.EvmTxStore); ok { r0 = rf() diff --git a/core/internal/mocks/flags.go b/core/internal/mocks/flags.go index 5b5aa812680..32d21326ba0 100644 --- a/core/internal/mocks/flags.go +++ b/core/internal/mocks/flags.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -26,6 +26,10 @@ type Flags struct { func (_m *Flags) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -52,6 +56,10 @@ func (_m *Flags) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, e func (_m *Flags) AddAccess(opts *bind.TransactOpts, _user common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _user) + if len(ret) == 0 { + panic("no return value specified for AddAccess") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -78,6 +86,10 @@ func (_m *Flags) AddAccess(opts *bind.TransactOpts, _user common.Address) (*type func (_m *Flags) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -94,6 +106,10 @@ func (_m *Flags) Address() common.Address { func (_m *Flags) CheckEnabled(opts *bind.CallOpts) (bool, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for CheckEnabled") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (bool, error)); ok { @@ -118,6 +134,10 @@ func (_m *Flags) CheckEnabled(opts *bind.CallOpts) (bool, error) { func (_m *Flags) DisableAccessCheck(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for DisableAccessCheck") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -144,6 +164,10 @@ func (_m *Flags) DisableAccessCheck(opts *bind.TransactOpts) (*types.Transaction func (_m *Flags) EnableAccessCheck(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for EnableAccessCheck") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -170,6 +194,10 @@ func (_m *Flags) EnableAccessCheck(opts *bind.TransactOpts) (*types.Transaction, func (_m *Flags) FilterAddedAccess(opts *bind.FilterOpts) (*flags_wrapper.FlagsAddedAccessIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterAddedAccess") + } + var r0 *flags_wrapper.FlagsAddedAccessIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*flags_wrapper.FlagsAddedAccessIterator, error)); ok { @@ -196,6 +224,10 @@ func (_m *Flags) FilterAddedAccess(opts *bind.FilterOpts) (*flags_wrapper.FlagsA func (_m *Flags) FilterCheckAccessDisabled(opts *bind.FilterOpts) (*flags_wrapper.FlagsCheckAccessDisabledIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCheckAccessDisabled") + } + var r0 *flags_wrapper.FlagsCheckAccessDisabledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*flags_wrapper.FlagsCheckAccessDisabledIterator, error)); ok { @@ -222,6 +254,10 @@ func (_m *Flags) FilterCheckAccessDisabled(opts *bind.FilterOpts) (*flags_wrappe func (_m *Flags) FilterCheckAccessEnabled(opts *bind.FilterOpts) (*flags_wrapper.FlagsCheckAccessEnabledIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCheckAccessEnabled") + } + var r0 *flags_wrapper.FlagsCheckAccessEnabledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*flags_wrapper.FlagsCheckAccessEnabledIterator, error)); ok { @@ -248,6 +284,10 @@ func (_m *Flags) FilterCheckAccessEnabled(opts *bind.FilterOpts) (*flags_wrapper func (_m *Flags) FilterFlagLowered(opts *bind.FilterOpts, subject []common.Address) (*flags_wrapper.FlagsFlagLoweredIterator, error) { ret := _m.Called(opts, subject) + if len(ret) == 0 { + panic("no return value specified for FilterFlagLowered") + } + var r0 *flags_wrapper.FlagsFlagLoweredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*flags_wrapper.FlagsFlagLoweredIterator, error)); ok { @@ -274,6 +314,10 @@ func (_m *Flags) FilterFlagLowered(opts *bind.FilterOpts, subject []common.Addre func (_m *Flags) FilterFlagRaised(opts *bind.FilterOpts, subject []common.Address) (*flags_wrapper.FlagsFlagRaisedIterator, error) { ret := _m.Called(opts, subject) + if len(ret) == 0 { + panic("no return value specified for FilterFlagRaised") + } + var r0 *flags_wrapper.FlagsFlagRaisedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*flags_wrapper.FlagsFlagRaisedIterator, error)); ok { @@ -300,6 +344,10 @@ func (_m *Flags) FilterFlagRaised(opts *bind.FilterOpts, subject []common.Addres func (_m *Flags) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*flags_wrapper.FlagsOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *flags_wrapper.FlagsOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flags_wrapper.FlagsOwnershipTransferRequestedIterator, error)); ok { @@ -326,6 +374,10 @@ func (_m *Flags) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from [] func (_m *Flags) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*flags_wrapper.FlagsOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *flags_wrapper.FlagsOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flags_wrapper.FlagsOwnershipTransferredIterator, error)); ok { @@ -352,6 +404,10 @@ func (_m *Flags) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common func (_m *Flags) FilterRaisingAccessControllerUpdated(opts *bind.FilterOpts, previous []common.Address, current []common.Address) (*flags_wrapper.FlagsRaisingAccessControllerUpdatedIterator, error) { ret := _m.Called(opts, previous, current) + if len(ret) == 0 { + panic("no return value specified for FilterRaisingAccessControllerUpdated") + } + var r0 *flags_wrapper.FlagsRaisingAccessControllerUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flags_wrapper.FlagsRaisingAccessControllerUpdatedIterator, error)); ok { @@ -378,6 +434,10 @@ func (_m *Flags) FilterRaisingAccessControllerUpdated(opts *bind.FilterOpts, pre func (_m *Flags) FilterRemovedAccess(opts *bind.FilterOpts) (*flags_wrapper.FlagsRemovedAccessIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterRemovedAccess") + } + var r0 *flags_wrapper.FlagsRemovedAccessIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*flags_wrapper.FlagsRemovedAccessIterator, error)); ok { @@ -404,6 +464,10 @@ func (_m *Flags) FilterRemovedAccess(opts *bind.FilterOpts) (*flags_wrapper.Flag func (_m *Flags) GetFlag(opts *bind.CallOpts, subject common.Address) (bool, error) { ret := _m.Called(opts, subject) + if len(ret) == 0 { + panic("no return value specified for GetFlag") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (bool, error)); ok { @@ -428,6 +492,10 @@ func (_m *Flags) GetFlag(opts *bind.CallOpts, subject common.Address) (bool, err func (_m *Flags) GetFlags(opts *bind.CallOpts, subjects []common.Address) ([]bool, error) { ret := _m.Called(opts, subjects) + if len(ret) == 0 { + panic("no return value specified for GetFlags") + } + var r0 []bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, []common.Address) ([]bool, error)); ok { @@ -454,6 +522,10 @@ func (_m *Flags) GetFlags(opts *bind.CallOpts, subjects []common.Address) ([]boo func (_m *Flags) HasAccess(opts *bind.CallOpts, _user common.Address, _calldata []byte) (bool, error) { ret := _m.Called(opts, _user, _calldata) + if len(ret) == 0 { + panic("no return value specified for HasAccess") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, []byte) (bool, error)); ok { @@ -478,6 +550,10 @@ func (_m *Flags) HasAccess(opts *bind.CallOpts, _user common.Address, _calldata func (_m *Flags) LowerFlags(opts *bind.TransactOpts, subjects []common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subjects) + if len(ret) == 0 { + panic("no return value specified for LowerFlags") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address) (*types.Transaction, error)); ok { @@ -504,6 +580,10 @@ func (_m *Flags) LowerFlags(opts *bind.TransactOpts, subjects []common.Address) func (_m *Flags) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -530,6 +610,10 @@ func (_m *Flags) Owner(opts *bind.CallOpts) (common.Address, error) { func (_m *Flags) ParseAddedAccess(log types.Log) (*flags_wrapper.FlagsAddedAccess, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseAddedAccess") + } + var r0 *flags_wrapper.FlagsAddedAccess var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsAddedAccess, error)); ok { @@ -556,6 +640,10 @@ func (_m *Flags) ParseAddedAccess(log types.Log) (*flags_wrapper.FlagsAddedAcces func (_m *Flags) ParseCheckAccessDisabled(log types.Log) (*flags_wrapper.FlagsCheckAccessDisabled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCheckAccessDisabled") + } + var r0 *flags_wrapper.FlagsCheckAccessDisabled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsCheckAccessDisabled, error)); ok { @@ -582,6 +670,10 @@ func (_m *Flags) ParseCheckAccessDisabled(log types.Log) (*flags_wrapper.FlagsCh func (_m *Flags) ParseCheckAccessEnabled(log types.Log) (*flags_wrapper.FlagsCheckAccessEnabled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCheckAccessEnabled") + } + var r0 *flags_wrapper.FlagsCheckAccessEnabled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsCheckAccessEnabled, error)); ok { @@ -608,6 +700,10 @@ func (_m *Flags) ParseCheckAccessEnabled(log types.Log) (*flags_wrapper.FlagsChe func (_m *Flags) ParseFlagLowered(log types.Log) (*flags_wrapper.FlagsFlagLowered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseFlagLowered") + } + var r0 *flags_wrapper.FlagsFlagLowered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsFlagLowered, error)); ok { @@ -634,6 +730,10 @@ func (_m *Flags) ParseFlagLowered(log types.Log) (*flags_wrapper.FlagsFlagLowere func (_m *Flags) ParseFlagRaised(log types.Log) (*flags_wrapper.FlagsFlagRaised, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseFlagRaised") + } + var r0 *flags_wrapper.FlagsFlagRaised var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsFlagRaised, error)); ok { @@ -660,6 +760,10 @@ func (_m *Flags) ParseFlagRaised(log types.Log) (*flags_wrapper.FlagsFlagRaised, func (_m *Flags) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -686,6 +790,10 @@ func (_m *Flags) ParseLog(log types.Log) (generated.AbigenLog, error) { func (_m *Flags) ParseOwnershipTransferRequested(log types.Log) (*flags_wrapper.FlagsOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *flags_wrapper.FlagsOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsOwnershipTransferRequested, error)); ok { @@ -712,6 +820,10 @@ func (_m *Flags) ParseOwnershipTransferRequested(log types.Log) (*flags_wrapper. func (_m *Flags) ParseOwnershipTransferred(log types.Log) (*flags_wrapper.FlagsOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *flags_wrapper.FlagsOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsOwnershipTransferred, error)); ok { @@ -738,6 +850,10 @@ func (_m *Flags) ParseOwnershipTransferred(log types.Log) (*flags_wrapper.FlagsO func (_m *Flags) ParseRaisingAccessControllerUpdated(log types.Log) (*flags_wrapper.FlagsRaisingAccessControllerUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRaisingAccessControllerUpdated") + } + var r0 *flags_wrapper.FlagsRaisingAccessControllerUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsRaisingAccessControllerUpdated, error)); ok { @@ -764,6 +880,10 @@ func (_m *Flags) ParseRaisingAccessControllerUpdated(log types.Log) (*flags_wrap func (_m *Flags) ParseRemovedAccess(log types.Log) (*flags_wrapper.FlagsRemovedAccess, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRemovedAccess") + } + var r0 *flags_wrapper.FlagsRemovedAccess var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flags_wrapper.FlagsRemovedAccess, error)); ok { @@ -790,6 +910,10 @@ func (_m *Flags) ParseRemovedAccess(log types.Log) (*flags_wrapper.FlagsRemovedA func (_m *Flags) RaiseFlag(opts *bind.TransactOpts, subject common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subject) + if len(ret) == 0 { + panic("no return value specified for RaiseFlag") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -816,6 +940,10 @@ func (_m *Flags) RaiseFlag(opts *bind.TransactOpts, subject common.Address) (*ty func (_m *Flags) RaiseFlags(opts *bind.TransactOpts, subjects []common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subjects) + if len(ret) == 0 { + panic("no return value specified for RaiseFlags") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address) (*types.Transaction, error)); ok { @@ -842,6 +970,10 @@ func (_m *Flags) RaiseFlags(opts *bind.TransactOpts, subjects []common.Address) func (_m *Flags) RaisingAccessController(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for RaisingAccessController") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -868,6 +1000,10 @@ func (_m *Flags) RaisingAccessController(opts *bind.CallOpts) (common.Address, e func (_m *Flags) RemoveAccess(opts *bind.TransactOpts, _user common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _user) + if len(ret) == 0 { + panic("no return value specified for RemoveAccess") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -894,6 +1030,10 @@ func (_m *Flags) RemoveAccess(opts *bind.TransactOpts, _user common.Address) (*t func (_m *Flags) SetRaisingAccessController(opts *bind.TransactOpts, racAddress common.Address) (*types.Transaction, error) { ret := _m.Called(opts, racAddress) + if len(ret) == 0 { + panic("no return value specified for SetRaisingAccessController") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -920,6 +1060,10 @@ func (_m *Flags) SetRaisingAccessController(opts *bind.TransactOpts, racAddress func (_m *Flags) TransferOwnership(opts *bind.TransactOpts, _to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -946,6 +1090,10 @@ func (_m *Flags) TransferOwnership(opts *bind.TransactOpts, _to common.Address) func (_m *Flags) WatchAddedAccess(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsAddedAccess) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchAddedAccess") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsAddedAccess) (event.Subscription, error)); ok { @@ -972,6 +1120,10 @@ func (_m *Flags) WatchAddedAccess(opts *bind.WatchOpts, sink chan<- *flags_wrapp func (_m *Flags) WatchCheckAccessDisabled(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsCheckAccessDisabled) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCheckAccessDisabled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsCheckAccessDisabled) (event.Subscription, error)); ok { @@ -998,6 +1150,10 @@ func (_m *Flags) WatchCheckAccessDisabled(opts *bind.WatchOpts, sink chan<- *fla func (_m *Flags) WatchCheckAccessEnabled(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsCheckAccessEnabled) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCheckAccessEnabled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsCheckAccessEnabled) (event.Subscription, error)); ok { @@ -1024,6 +1180,10 @@ func (_m *Flags) WatchCheckAccessEnabled(opts *bind.WatchOpts, sink chan<- *flag func (_m *Flags) WatchFlagLowered(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsFlagLowered, subject []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, subject) + if len(ret) == 0 { + panic("no return value specified for WatchFlagLowered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsFlagLowered, []common.Address) (event.Subscription, error)); ok { @@ -1050,6 +1210,10 @@ func (_m *Flags) WatchFlagLowered(opts *bind.WatchOpts, sink chan<- *flags_wrapp func (_m *Flags) WatchFlagRaised(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsFlagRaised, subject []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, subject) + if len(ret) == 0 { + panic("no return value specified for WatchFlagRaised") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsFlagRaised, []common.Address) (event.Subscription, error)); ok { @@ -1076,6 +1240,10 @@ func (_m *Flags) WatchFlagRaised(opts *bind.WatchOpts, sink chan<- *flags_wrappe func (_m *Flags) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1102,6 +1270,10 @@ func (_m *Flags) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan func (_m *Flags) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1128,6 +1300,10 @@ func (_m *Flags) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *fl func (_m *Flags) WatchRaisingAccessControllerUpdated(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsRaisingAccessControllerUpdated, previous []common.Address, current []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, previous, current) + if len(ret) == 0 { + panic("no return value specified for WatchRaisingAccessControllerUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsRaisingAccessControllerUpdated, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1154,6 +1330,10 @@ func (_m *Flags) WatchRaisingAccessControllerUpdated(opts *bind.WatchOpts, sink func (_m *Flags) WatchRemovedAccess(opts *bind.WatchOpts, sink chan<- *flags_wrapper.FlagsRemovedAccess) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchRemovedAccess") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flags_wrapper.FlagsRemovedAccess) (event.Subscription, error)); ok { diff --git a/core/internal/mocks/flux_aggregator.go b/core/internal/mocks/flux_aggregator.go index e3da1b83dff..ac72bd07db8 100644 --- a/core/internal/mocks/flux_aggregator.go +++ b/core/internal/mocks/flux_aggregator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ type FluxAggregator struct { func (_m *FluxAggregator) AcceptAdmin(opts *bind.TransactOpts, _oracle common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _oracle) + if len(ret) == 0 { + panic("no return value specified for AcceptAdmin") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *FluxAggregator) AcceptAdmin(opts *bind.TransactOpts, _oracle common.Ad func (_m *FluxAggregator) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -80,6 +88,10 @@ func (_m *FluxAggregator) AcceptOwnership(opts *bind.TransactOpts) (*types.Trans func (_m *FluxAggregator) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -96,6 +108,10 @@ func (_m *FluxAggregator) Address() common.Address { func (_m *FluxAggregator) AllocatedFunds(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AllocatedFunds") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -122,6 +138,10 @@ func (_m *FluxAggregator) AllocatedFunds(opts *bind.CallOpts) (*big.Int, error) func (_m *FluxAggregator) AvailableFunds(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AvailableFunds") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -148,6 +168,10 @@ func (_m *FluxAggregator) AvailableFunds(opts *bind.CallOpts) (*big.Int, error) func (_m *FluxAggregator) ChangeOracles(opts *bind.TransactOpts, _removed []common.Address, _added []common.Address, _addedAdmins []common.Address, _minSubmissions uint32, _maxSubmissions uint32, _restartDelay uint32) (*types.Transaction, error) { ret := _m.Called(opts, _removed, _added, _addedAdmins, _minSubmissions, _maxSubmissions, _restartDelay) + if len(ret) == 0 { + panic("no return value specified for ChangeOracles") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, []common.Address, uint32, uint32, uint32) (*types.Transaction, error)); ok { @@ -174,6 +198,10 @@ func (_m *FluxAggregator) ChangeOracles(opts *bind.TransactOpts, _removed []comm func (_m *FluxAggregator) Decimals(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Decimals") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -198,6 +226,10 @@ func (_m *FluxAggregator) Decimals(opts *bind.CallOpts) (uint8, error) { func (_m *FluxAggregator) Description(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Description") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -222,6 +254,10 @@ func (_m *FluxAggregator) Description(opts *bind.CallOpts) (string, error) { func (_m *FluxAggregator) FilterAnswerUpdated(opts *bind.FilterOpts, current []*big.Int, roundId []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator, error) { ret := _m.Called(opts, current, roundId) + if len(ret) == 0 { + panic("no return value specified for FilterAnswerUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdatedIterator, error)); ok { @@ -248,6 +284,10 @@ func (_m *FluxAggregator) FilterAnswerUpdated(opts *bind.FilterOpts, current []* func (_m *FluxAggregator) FilterAvailableFundsUpdated(opts *bind.FilterOpts, amount []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator, error) { ret := _m.Called(opts, amount) + if len(ret) == 0 { + panic("no return value specified for FilterAvailableFundsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdatedIterator, error)); ok { @@ -274,6 +314,10 @@ func (_m *FluxAggregator) FilterAvailableFundsUpdated(opts *bind.FilterOpts, amo func (_m *FluxAggregator) FilterNewRound(opts *bind.FilterOpts, roundId []*big.Int, startedBy []common.Address) (*flux_aggregator_wrapper.FluxAggregatorNewRoundIterator, error) { ret := _m.Called(opts, roundId, startedBy) + if len(ret) == 0 { + panic("no return value specified for FilterNewRound") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorNewRoundIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorNewRoundIterator, error)); ok { @@ -300,6 +344,10 @@ func (_m *FluxAggregator) FilterNewRound(opts *bind.FilterOpts, roundId []*big.I func (_m *FluxAggregator) FilterOracleAdminUpdateRequested(opts *bind.FilterOpts, oracle []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator, error) { ret := _m.Called(opts, oracle) + if len(ret) == 0 { + panic("no return value specified for FilterOracleAdminUpdateRequested") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequestedIterator, error)); ok { @@ -326,6 +374,10 @@ func (_m *FluxAggregator) FilterOracleAdminUpdateRequested(opts *bind.FilterOpts func (_m *FluxAggregator) FilterOracleAdminUpdated(opts *bind.FilterOpts, oracle []common.Address, newAdmin []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator, error) { ret := _m.Called(opts, oracle, newAdmin) + if len(ret) == 0 { + panic("no return value specified for FilterOracleAdminUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdatedIterator, error)); ok { @@ -352,6 +404,10 @@ func (_m *FluxAggregator) FilterOracleAdminUpdated(opts *bind.FilterOpts, oracle func (_m *FluxAggregator) FilterOraclePermissionsUpdated(opts *bind.FilterOpts, oracle []common.Address, whitelisted []bool) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator, error) { ret := _m.Called(opts, oracle, whitelisted) + if len(ret) == 0 { + panic("no return value specified for FilterOraclePermissionsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []bool) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdatedIterator, error)); ok { @@ -378,6 +434,10 @@ func (_m *FluxAggregator) FilterOraclePermissionsUpdated(opts *bind.FilterOpts, func (_m *FluxAggregator) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequestedIterator, error)); ok { @@ -404,6 +464,10 @@ func (_m *FluxAggregator) FilterOwnershipTransferRequested(opts *bind.FilterOpts func (_m *FluxAggregator) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferredIterator, error)); ok { @@ -430,6 +494,10 @@ func (_m *FluxAggregator) FilterOwnershipTransferred(opts *bind.FilterOpts, from func (_m *FluxAggregator) FilterRequesterPermissionsSet(opts *bind.FilterOpts, requester []common.Address) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator, error) { ret := _m.Called(opts, requester) + if len(ret) == 0 { + panic("no return value specified for FilterRequesterPermissionsSet") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSetIterator, error)); ok { @@ -456,6 +524,10 @@ func (_m *FluxAggregator) FilterRequesterPermissionsSet(opts *bind.FilterOpts, r func (_m *FluxAggregator) FilterRoundDetailsUpdated(opts *bind.FilterOpts, paymentAmount []*big.Int, minSubmissionCount []uint32, maxSubmissionCount []uint32) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator, error) { ret := _m.Called(opts, paymentAmount, minSubmissionCount, maxSubmissionCount) + if len(ret) == 0 { + panic("no return value specified for FilterRoundDetailsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []uint32, []uint32) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdatedIterator, error)); ok { @@ -482,6 +554,10 @@ func (_m *FluxAggregator) FilterRoundDetailsUpdated(opts *bind.FilterOpts, payme func (_m *FluxAggregator) FilterSubmissionReceived(opts *bind.FilterOpts, submission []*big.Int, round []uint32, oracle []common.Address) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator, error) { ret := _m.Called(opts, submission, round, oracle) + if len(ret) == 0 { + panic("no return value specified for FilterSubmissionReceived") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []uint32, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceivedIterator, error)); ok { @@ -508,6 +584,10 @@ func (_m *FluxAggregator) FilterSubmissionReceived(opts *bind.FilterOpts, submis func (_m *FluxAggregator) FilterValidatorUpdated(opts *bind.FilterOpts, previous []common.Address, current []common.Address) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator, error) { ret := _m.Called(opts, previous, current) + if len(ret) == 0 { + panic("no return value specified for FilterValidatorUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdatedIterator, error)); ok { @@ -534,6 +614,10 @@ func (_m *FluxAggregator) FilterValidatorUpdated(opts *bind.FilterOpts, previous func (_m *FluxAggregator) GetAdmin(opts *bind.CallOpts, _oracle common.Address) (common.Address, error) { ret := _m.Called(opts, _oracle) + if len(ret) == 0 { + panic("no return value specified for GetAdmin") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (common.Address, error)); ok { @@ -560,6 +644,10 @@ func (_m *FluxAggregator) GetAdmin(opts *bind.CallOpts, _oracle common.Address) func (_m *FluxAggregator) GetAnswer(opts *bind.CallOpts, _roundId *big.Int) (*big.Int, error) { ret := _m.Called(opts, _roundId) + if len(ret) == 0 { + panic("no return value specified for GetAnswer") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (*big.Int, error)); ok { @@ -586,6 +674,10 @@ func (_m *FluxAggregator) GetAnswer(opts *bind.CallOpts, _roundId *big.Int) (*bi func (_m *FluxAggregator) GetOracles(opts *bind.CallOpts) ([]common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetOracles") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([]common.Address, error)); ok { @@ -612,6 +704,10 @@ func (_m *FluxAggregator) GetOracles(opts *bind.CallOpts) ([]common.Address, err func (_m *FluxAggregator) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (flux_aggregator_wrapper.GetRoundData, error) { ret := _m.Called(opts, _roundId) + if len(ret) == 0 { + panic("no return value specified for GetRoundData") + } + var r0 flux_aggregator_wrapper.GetRoundData var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (flux_aggregator_wrapper.GetRoundData, error)); ok { @@ -636,6 +732,10 @@ func (_m *FluxAggregator) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) ( func (_m *FluxAggregator) GetTimestamp(opts *bind.CallOpts, _roundId *big.Int) (*big.Int, error) { ret := _m.Called(opts, _roundId) + if len(ret) == 0 { + panic("no return value specified for GetTimestamp") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (*big.Int, error)); ok { @@ -662,6 +762,10 @@ func (_m *FluxAggregator) GetTimestamp(opts *bind.CallOpts, _roundId *big.Int) ( func (_m *FluxAggregator) LatestAnswer(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestAnswer") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -688,6 +792,10 @@ func (_m *FluxAggregator) LatestAnswer(opts *bind.CallOpts) (*big.Int, error) { func (_m *FluxAggregator) LatestRound(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestRound") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -714,6 +822,10 @@ func (_m *FluxAggregator) LatestRound(opts *bind.CallOpts) (*big.Int, error) { func (_m *FluxAggregator) LatestRoundData(opts *bind.CallOpts) (flux_aggregator_wrapper.LatestRoundData, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestRoundData") + } + var r0 flux_aggregator_wrapper.LatestRoundData var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (flux_aggregator_wrapper.LatestRoundData, error)); ok { @@ -738,6 +850,10 @@ func (_m *FluxAggregator) LatestRoundData(opts *bind.CallOpts) (flux_aggregator_ func (_m *FluxAggregator) LatestTimestamp(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestTimestamp") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -764,6 +880,10 @@ func (_m *FluxAggregator) LatestTimestamp(opts *bind.CallOpts) (*big.Int, error) func (_m *FluxAggregator) LinkToken(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LinkToken") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -790,6 +910,10 @@ func (_m *FluxAggregator) LinkToken(opts *bind.CallOpts) (common.Address, error) func (_m *FluxAggregator) MaxSubmissionCount(opts *bind.CallOpts) (uint32, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MaxSubmissionCount") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { @@ -814,6 +938,10 @@ func (_m *FluxAggregator) MaxSubmissionCount(opts *bind.CallOpts) (uint32, error func (_m *FluxAggregator) MaxSubmissionValue(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MaxSubmissionValue") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -840,6 +968,10 @@ func (_m *FluxAggregator) MaxSubmissionValue(opts *bind.CallOpts) (*big.Int, err func (_m *FluxAggregator) MinSubmissionCount(opts *bind.CallOpts) (uint32, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MinSubmissionCount") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { @@ -864,6 +996,10 @@ func (_m *FluxAggregator) MinSubmissionCount(opts *bind.CallOpts) (uint32, error func (_m *FluxAggregator) MinSubmissionValue(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MinSubmissionValue") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -890,6 +1026,10 @@ func (_m *FluxAggregator) MinSubmissionValue(opts *bind.CallOpts) (*big.Int, err func (_m *FluxAggregator) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, arg1 *big.Int, _data []byte) (*types.Transaction, error) { ret := _m.Called(opts, arg0, arg1, _data) + if len(ret) == 0 { + panic("no return value specified for OnTokenTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -916,6 +1056,10 @@ func (_m *FluxAggregator) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.A func (_m *FluxAggregator) OracleCount(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for OracleCount") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -940,6 +1084,10 @@ func (_m *FluxAggregator) OracleCount(opts *bind.CallOpts) (uint8, error) { func (_m *FluxAggregator) OracleRoundState(opts *bind.CallOpts, _oracle common.Address, _queriedRoundId uint32) (flux_aggregator_wrapper.OracleRoundState, error) { ret := _m.Called(opts, _oracle, _queriedRoundId) + if len(ret) == 0 { + panic("no return value specified for OracleRoundState") + } + var r0 flux_aggregator_wrapper.OracleRoundState var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address, uint32) (flux_aggregator_wrapper.OracleRoundState, error)); ok { @@ -964,6 +1112,10 @@ func (_m *FluxAggregator) OracleRoundState(opts *bind.CallOpts, _oracle common.A func (_m *FluxAggregator) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -990,6 +1142,10 @@ func (_m *FluxAggregator) Owner(opts *bind.CallOpts) (common.Address, error) { func (_m *FluxAggregator) ParseAnswerUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseAnswerUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, error)); ok { @@ -1016,6 +1172,10 @@ func (_m *FluxAggregator) ParseAnswerUpdated(log types.Log) (*flux_aggregator_wr func (_m *FluxAggregator) ParseAvailableFundsUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseAvailableFundsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, error)); ok { @@ -1042,6 +1202,10 @@ func (_m *FluxAggregator) ParseAvailableFundsUpdated(log types.Log) (*flux_aggre func (_m *FluxAggregator) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -1068,6 +1232,10 @@ func (_m *FluxAggregator) ParseLog(log types.Log) (generated.AbigenLog, error) { func (_m *FluxAggregator) ParseNewRound(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorNewRound, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseNewRound") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorNewRound var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorNewRound, error)); ok { @@ -1094,6 +1262,10 @@ func (_m *FluxAggregator) ParseNewRound(log types.Log) (*flux_aggregator_wrapper func (_m *FluxAggregator) ParseOracleAdminUpdateRequested(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOracleAdminUpdateRequested") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, error)); ok { @@ -1120,6 +1292,10 @@ func (_m *FluxAggregator) ParseOracleAdminUpdateRequested(log types.Log) (*flux_ func (_m *FluxAggregator) ParseOracleAdminUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOracleAdminUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, error)); ok { @@ -1146,6 +1322,10 @@ func (_m *FluxAggregator) ParseOracleAdminUpdated(log types.Log) (*flux_aggregat func (_m *FluxAggregator) ParseOraclePermissionsUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOraclePermissionsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, error)); ok { @@ -1172,6 +1352,10 @@ func (_m *FluxAggregator) ParseOraclePermissionsUpdated(log types.Log) (*flux_ag func (_m *FluxAggregator) ParseOwnershipTransferRequested(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, error)); ok { @@ -1198,6 +1382,10 @@ func (_m *FluxAggregator) ParseOwnershipTransferRequested(log types.Log) (*flux_ func (_m *FluxAggregator) ParseOwnershipTransferred(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, error)); ok { @@ -1224,6 +1412,10 @@ func (_m *FluxAggregator) ParseOwnershipTransferred(log types.Log) (*flux_aggreg func (_m *FluxAggregator) ParseRequesterPermissionsSet(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRequesterPermissionsSet") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, error)); ok { @@ -1250,6 +1442,10 @@ func (_m *FluxAggregator) ParseRequesterPermissionsSet(log types.Log) (*flux_agg func (_m *FluxAggregator) ParseRoundDetailsUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRoundDetailsUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, error)); ok { @@ -1276,6 +1472,10 @@ func (_m *FluxAggregator) ParseRoundDetailsUpdated(log types.Log) (*flux_aggrega func (_m *FluxAggregator) ParseSubmissionReceived(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubmissionReceived") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, error)); ok { @@ -1302,6 +1502,10 @@ func (_m *FluxAggregator) ParseSubmissionReceived(log types.Log) (*flux_aggregat func (_m *FluxAggregator) ParseValidatorUpdated(log types.Log) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseValidatorUpdated") + } + var r0 *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, error)); ok { @@ -1328,6 +1532,10 @@ func (_m *FluxAggregator) ParseValidatorUpdated(log types.Log) (*flux_aggregator func (_m *FluxAggregator) PaymentAmount(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for PaymentAmount") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -1354,6 +1562,10 @@ func (_m *FluxAggregator) PaymentAmount(opts *bind.CallOpts) (*big.Int, error) { func (_m *FluxAggregator) RequestNewRound(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for RequestNewRound") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -1380,6 +1592,10 @@ func (_m *FluxAggregator) RequestNewRound(opts *bind.TransactOpts) (*types.Trans func (_m *FluxAggregator) RestartDelay(opts *bind.CallOpts) (uint32, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for RestartDelay") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { @@ -1404,6 +1620,10 @@ func (_m *FluxAggregator) RestartDelay(opts *bind.CallOpts) (uint32, error) { func (_m *FluxAggregator) SetRequesterPermissions(opts *bind.TransactOpts, _requester common.Address, _authorized bool, _delay uint32) (*types.Transaction, error) { ret := _m.Called(opts, _requester, _authorized, _delay) + if len(ret) == 0 { + panic("no return value specified for SetRequesterPermissions") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, bool, uint32) (*types.Transaction, error)); ok { @@ -1430,6 +1650,10 @@ func (_m *FluxAggregator) SetRequesterPermissions(opts *bind.TransactOpts, _requ func (_m *FluxAggregator) SetValidator(opts *bind.TransactOpts, _newValidator common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _newValidator) + if len(ret) == 0 { + panic("no return value specified for SetValidator") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1456,6 +1680,10 @@ func (_m *FluxAggregator) SetValidator(opts *bind.TransactOpts, _newValidator co func (_m *FluxAggregator) Submit(opts *bind.TransactOpts, _roundId *big.Int, _submission *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _roundId, _submission) + if len(ret) == 0 { + panic("no return value specified for Submit") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int) (*types.Transaction, error)); ok { @@ -1482,6 +1710,10 @@ func (_m *FluxAggregator) Submit(opts *bind.TransactOpts, _roundId *big.Int, _su func (_m *FluxAggregator) Timeout(opts *bind.CallOpts) (uint32, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Timeout") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { @@ -1506,6 +1738,10 @@ func (_m *FluxAggregator) Timeout(opts *bind.CallOpts) (uint32, error) { func (_m *FluxAggregator) TransferAdmin(opts *bind.TransactOpts, _oracle common.Address, _newAdmin common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _oracle, _newAdmin) + if len(ret) == 0 { + panic("no return value specified for TransferAdmin") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)); ok { @@ -1532,6 +1768,10 @@ func (_m *FluxAggregator) TransferAdmin(opts *bind.TransactOpts, _oracle common. func (_m *FluxAggregator) TransferOwnership(opts *bind.TransactOpts, _to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1558,6 +1798,10 @@ func (_m *FluxAggregator) TransferOwnership(opts *bind.TransactOpts, _to common. func (_m *FluxAggregator) UpdateAvailableFunds(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for UpdateAvailableFunds") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -1584,6 +1828,10 @@ func (_m *FluxAggregator) UpdateAvailableFunds(opts *bind.TransactOpts) (*types. func (_m *FluxAggregator) UpdateFutureRounds(opts *bind.TransactOpts, _paymentAmount *big.Int, _minSubmissions uint32, _maxSubmissions uint32, _restartDelay uint32, _timeout uint32) (*types.Transaction, error) { ret := _m.Called(opts, _paymentAmount, _minSubmissions, _maxSubmissions, _restartDelay, _timeout) + if len(ret) == 0 { + panic("no return value specified for UpdateFutureRounds") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint32, uint32, uint32, uint32) (*types.Transaction, error)); ok { @@ -1610,6 +1858,10 @@ func (_m *FluxAggregator) UpdateFutureRounds(opts *bind.TransactOpts, _paymentAm func (_m *FluxAggregator) Validator(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Validator") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -1636,6 +1888,10 @@ func (_m *FluxAggregator) Validator(opts *bind.CallOpts) (common.Address, error) func (_m *FluxAggregator) Version(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Version") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -1662,6 +1918,10 @@ func (_m *FluxAggregator) Version(opts *bind.CallOpts) (*big.Int, error) { func (_m *FluxAggregator) WatchAnswerUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, current []*big.Int, roundId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, current, roundId) + if len(ret) == 0 { + panic("no return value specified for WatchAnswerUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAnswerUpdated, []*big.Int, []*big.Int) (event.Subscription, error)); ok { @@ -1688,6 +1948,10 @@ func (_m *FluxAggregator) WatchAnswerUpdated(opts *bind.WatchOpts, sink chan<- * func (_m *FluxAggregator) WatchAvailableFundsUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, amount []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, amount) + if len(ret) == 0 { + panic("no return value specified for WatchAvailableFundsUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorAvailableFundsUpdated, []*big.Int) (event.Subscription, error)); ok { @@ -1714,6 +1978,10 @@ func (_m *FluxAggregator) WatchAvailableFundsUpdated(opts *bind.WatchOpts, sink func (_m *FluxAggregator) WatchNewRound(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound, roundId []*big.Int, startedBy []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, roundId, startedBy) + if len(ret) == 0 { + panic("no return value specified for WatchNewRound") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorNewRound, []*big.Int, []common.Address) (event.Subscription, error)); ok { @@ -1740,6 +2008,10 @@ func (_m *FluxAggregator) WatchNewRound(opts *bind.WatchOpts, sink chan<- *flux_ func (_m *FluxAggregator) WatchOracleAdminUpdateRequested(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, oracle []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, oracle) + if len(ret) == 0 { + panic("no return value specified for WatchOracleAdminUpdateRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdateRequested, []common.Address) (event.Subscription, error)); ok { @@ -1766,6 +2038,10 @@ func (_m *FluxAggregator) WatchOracleAdminUpdateRequested(opts *bind.WatchOpts, func (_m *FluxAggregator) WatchOracleAdminUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, oracle []common.Address, newAdmin []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, oracle, newAdmin) + if len(ret) == 0 { + panic("no return value specified for WatchOracleAdminUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOracleAdminUpdated, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1792,6 +2068,10 @@ func (_m *FluxAggregator) WatchOracleAdminUpdated(opts *bind.WatchOpts, sink cha func (_m *FluxAggregator) WatchOraclePermissionsUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, oracle []common.Address, whitelisted []bool) (event.Subscription, error) { ret := _m.Called(opts, sink, oracle, whitelisted) + if len(ret) == 0 { + panic("no return value specified for WatchOraclePermissionsUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOraclePermissionsUpdated, []common.Address, []bool) (event.Subscription, error)); ok { @@ -1818,6 +2098,10 @@ func (_m *FluxAggregator) WatchOraclePermissionsUpdated(opts *bind.WatchOpts, si func (_m *FluxAggregator) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1844,6 +2128,10 @@ func (_m *FluxAggregator) WatchOwnershipTransferRequested(opts *bind.WatchOpts, func (_m *FluxAggregator) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1870,6 +2158,10 @@ func (_m *FluxAggregator) WatchOwnershipTransferred(opts *bind.WatchOpts, sink c func (_m *FluxAggregator) WatchRequesterPermissionsSet(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, requester []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, requester) + if len(ret) == 0 { + panic("no return value specified for WatchRequesterPermissionsSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRequesterPermissionsSet, []common.Address) (event.Subscription, error)); ok { @@ -1896,6 +2188,10 @@ func (_m *FluxAggregator) WatchRequesterPermissionsSet(opts *bind.WatchOpts, sin func (_m *FluxAggregator) WatchRoundDetailsUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, paymentAmount []*big.Int, minSubmissionCount []uint32, maxSubmissionCount []uint32) (event.Subscription, error) { ret := _m.Called(opts, sink, paymentAmount, minSubmissionCount, maxSubmissionCount) + if len(ret) == 0 { + panic("no return value specified for WatchRoundDetailsUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorRoundDetailsUpdated, []*big.Int, []uint32, []uint32) (event.Subscription, error)); ok { @@ -1922,6 +2218,10 @@ func (_m *FluxAggregator) WatchRoundDetailsUpdated(opts *bind.WatchOpts, sink ch func (_m *FluxAggregator) WatchSubmissionReceived(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, submission []*big.Int, round []uint32, oracle []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, submission, round, oracle) + if len(ret) == 0 { + panic("no return value specified for WatchSubmissionReceived") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorSubmissionReceived, []*big.Int, []uint32, []common.Address) (event.Subscription, error)); ok { @@ -1948,6 +2248,10 @@ func (_m *FluxAggregator) WatchSubmissionReceived(opts *bind.WatchOpts, sink cha func (_m *FluxAggregator) WatchValidatorUpdated(opts *bind.WatchOpts, sink chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, previous []common.Address, current []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, previous, current) + if len(ret) == 0 { + panic("no return value specified for WatchValidatorUpdated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *flux_aggregator_wrapper.FluxAggregatorValidatorUpdated, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1974,6 +2278,10 @@ func (_m *FluxAggregator) WatchValidatorUpdated(opts *bind.WatchOpts, sink chan< func (_m *FluxAggregator) WithdrawFunds(opts *bind.TransactOpts, _recipient common.Address, _amount *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _recipient, _amount) + if len(ret) == 0 { + panic("no return value specified for WithdrawFunds") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -2000,6 +2308,10 @@ func (_m *FluxAggregator) WithdrawFunds(opts *bind.TransactOpts, _recipient comm func (_m *FluxAggregator) WithdrawPayment(opts *bind.TransactOpts, _oracle common.Address, _recipient common.Address, _amount *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, _oracle, _recipient, _amount) + if len(ret) == 0 { + panic("no return value specified for WithdrawPayment") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -2026,6 +2338,10 @@ func (_m *FluxAggregator) WithdrawPayment(opts *bind.TransactOpts, _oracle commo func (_m *FluxAggregator) WithdrawablePayment(opts *bind.CallOpts, _oracle common.Address) (*big.Int, error) { ret := _m.Called(opts, _oracle) + if len(ret) == 0 { + panic("no return value specified for WithdrawablePayment") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok { diff --git a/core/internal/mocks/prometheus_backend.go b/core/internal/mocks/prometheus_backend.go index b2556a0bad4..6573dbaf03f 100644 --- a/core/internal/mocks/prometheus_backend.go +++ b/core/internal/mocks/prometheus_backend.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/core/internal/testutils/configtest/general_config.go b/core/internal/testutils/configtest/general_config.go index 93d388b2d30..d2851035855 100644 --- a/core/internal/testutils/configtest/general_config.go +++ b/core/internal/testutils/configtest/general_config.go @@ -7,14 +7,15 @@ import ( "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmcfg "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" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const DefaultPeerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X" @@ -45,35 +46,34 @@ func overrides(c *chainlink.Config, s *chainlink.Secrets) { c.Insecure.OCRDevelopmentMode = ptr(true) c.InsecureFastScrypt = ptr(true) - c.ShutdownGracePeriod = models.MustNewDuration(testutils.DefaultWaitTimeout) + c.ShutdownGracePeriod = commonconfig.MustNewDuration(testutils.DefaultWaitTimeout) c.Database.Dialect = dialects.TransactionWrappedPostgres c.Database.Lock.Enabled = ptr(false) c.Database.MaxIdleConns = ptr[int64](20) c.Database.MaxOpenConns = ptr[int64](20) c.Database.MigrateOnStartup = ptr(false) - c.Database.DefaultLockTimeout = models.MustNewDuration(1 * time.Minute) + c.Database.DefaultLockTimeout = commonconfig.MustNewDuration(1 * time.Minute) - c.JobPipeline.ReaperInterval = models.MustNewDuration(0) + c.JobPipeline.ReaperInterval = commonconfig.MustNewDuration(0) - c.P2P.V1.Enabled = ptr(false) c.P2P.V2.Enabled = ptr(false) - c.WebServer.SessionTimeout = models.MustNewDuration(2 * time.Minute) - c.WebServer.BridgeResponseURL = models.MustParseURL("http://localhost:6688") + c.WebServer.SessionTimeout = commonconfig.MustNewDuration(2 * time.Minute) + c.WebServer.BridgeResponseURL = commonconfig.MustParseURL("http://localhost:6688") testIP := net.ParseIP("127.0.0.1") c.WebServer.ListenIP = &testIP c.WebServer.TLS.ListenIP = &testIP - chainID := utils.NewBigI(evmclient.NullClientChainID) + chainID := big.NewI(evmclient.NullClientChainID) c.EVM = append(c.EVM, &evmcfg.EVMConfig{ ChainID: chainID, Chain: evmcfg.Defaults(chainID), Nodes: evmcfg.EVMNodes{ &evmcfg.Node{ Name: ptr("test"), - WSURL: &models.URL{}, - HTTPURL: &models.URL{}, + WSURL: &commonconfig.URL{}, + HTTPURL: &commonconfig.URL{}, SendOnly: new(bool), Order: ptr[int32](100), }, @@ -96,7 +96,7 @@ func NewGeneralConfigSimulated(t testing.TB, overrideFn func(*chainlink.Config, // simulated is a config override func that appends the simulated EVM chain (testutils.SimulatedChainID), // or replaces the null chain (client.NullClientChainID) if that is the only entry. func simulated(c *chainlink.Config, s *chainlink.Secrets) { - chainID := utils.NewBig(testutils.SimulatedChainID) + chainID := big.New(testutils.SimulatedChainID) enabled := true cfg := evmcfg.EVMConfig{ ChainID: chainID, @@ -104,7 +104,7 @@ func simulated(c *chainlink.Config, s *chainlink.Secrets) { Enabled: &enabled, Nodes: evmcfg.EVMNodes{&validTestNode}, } - if len(c.EVM) == 1 && c.EVM[0].ChainID.Cmp(utils.NewBigI(client.NullClientChainID)) == 0 { + if len(c.EVM) == 1 && c.EVM[0].ChainID.Cmp(big.NewI(client.NullClientChainID)) == 0 { c.EVM[0] = &cfg // replace null, if only entry } else { c.EVM = append(c.EVM, &cfg) @@ -113,8 +113,8 @@ func simulated(c *chainlink.Config, s *chainlink.Secrets) { var validTestNode = evmcfg.Node{ Name: ptr("simulated-node"), - WSURL: models.MustParseURL("WSS://simulated-wss.com/ws"), - HTTPURL: models.MustParseURL("http://simulated.com"), + WSURL: commonconfig.MustParseURL("WSS://simulated-wss.com/ws"), + HTTPURL: commonconfig.MustParseURL("http://simulated.com"), SendOnly: nil, Order: ptr(int32(1)), } diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 423615145e5..cc56c3c9e9b 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -15,7 +15,10 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" commonmocks "github.com/smartcontractkit/chainlink/v2/common/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains" @@ -29,15 +32,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "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/pg" "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/srvctest" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func NewChainScopedConfig(t testing.TB, cfg legacyevm.AppConfig) evmconfig.ChainScopedConfig { @@ -45,7 +46,7 @@ func NewChainScopedConfig(t testing.TB, cfg legacyevm.AppConfig) evmconfig.Chain if len(cfg.EVMConfigs()) > 0 { evmCfg = cfg.EVMConfigs()[0] } else { - var chainID = (*utils.Big)(testutils.FixtureChainID) + var chainID = (*ubig.Big)(testutils.FixtureChainID) evmCfg = &evmtoml.EVMConfig{ ChainID: chainID, Chain: evmtoml.Defaults(chainID), @@ -65,7 +66,7 @@ type TestChainOpts struct { DB *sqlx.DB TxManager txmgr.TxManager KeyStore keystore.Eth - MailMon *utils.MailboxMonitor + MailMon *mailbox.Monitor GasEstimator gas.EvmFeeEstimator } @@ -80,15 +81,15 @@ func NewChainRelayExtenders(t testing.TB, testopts TestChainOpts) *evmrelay.Chai func NewChainRelayExtOpts(t testing.TB, testopts TestChainOpts) legacyevm.ChainRelayExtenderConfig { require.NotNil(t, testopts.KeyStore) + lggr := logger.TestLogger(t) opts := legacyevm.ChainRelayExtenderConfig{ - Logger: logger.TestLogger(t), + Logger: lggr, KeyStore: testopts.KeyStore, ChainOpts: legacyevm.ChainOpts{ - AppConfig: testopts.GeneralConfig, - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: testopts.MailMon, - GasEstimator: testopts.GasEstimator, - DB: testopts.DB, + AppConfig: testopts.GeneralConfig, + MailMon: testopts.MailMon, + GasEstimator: testopts.GasEstimator, + DB: testopts.DB, }, } opts.GenEthClient = func(*big.Int) evmclient.Client { @@ -118,7 +119,7 @@ func NewChainRelayExtOpts(t testing.TB, testopts TestChainOpts) legacyevm.ChainR } } if opts.MailMon == nil { - opts.MailMon = srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + opts.MailMon = servicetest.Run(t, mailboxtest.NewMonitor(t)) } if testopts.GasEstimator != nil { opts.GenGasEstimator = func(*big.Int) gas.EvmFeeEstimator { @@ -266,7 +267,7 @@ func (mo *TestConfigs) NodeStatusesPaged(offset int, limit int, chainIDs ...stri return } -func legacyNode(n *evmtoml.Node, chainID *utils.Big) (v2 evmtypes.Node) { +func legacyNode(n *evmtoml.Node, chainID *ubig.Big) (v2 evmtypes.Node) { v2.Name = *n.Name v2.EVMChainID = *chainID if n.HTTPURL != nil { diff --git a/core/internal/testutils/evmtest/v2/evmtest.go b/core/internal/testutils/evmtest/v2/evmtest.go index fa22588c8fb..22b2bc5e0ca 100644 --- a/core/internal/testutils/evmtest/v2/evmtest.go +++ b/core/internal/testutils/evmtest/v2/evmtest.go @@ -5,9 +5,9 @@ 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" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func ChainEthMainnet(t *testing.T) config.ChainScopedConfig { return scopedConfig(t, 1) } @@ -16,7 +16,7 @@ func ChainArbitrumMainnet(t *testing.T) config.ChainScopedConfig { return scoped func ChainArbitrumRinkeby(t *testing.T) config.ChainScopedConfig { return scopedConfig(t, 421611) } func scopedConfig(t *testing.T, chainID int64) config.ChainScopedConfig { - id := utils.NewBigI(chainID) + id := big.NewI(chainID) evmCfg := toml.EVMConfig{ChainID: id, Chain: toml.Defaults(id)} return config.NewTOMLChainScopedConfig(configtest.NewTestGeneralConfig(t), &evmCfg, logger.TestLogger(t)) } diff --git a/core/internal/testutils/pgtest/pgtest.go b/core/internal/testutils/pgtest/pgtest.go index 01024b39c37..686483f2d41 100644 --- a/core/internal/testutils/pgtest/pgtest.go +++ b/core/internal/testutils/pgtest/pgtest.go @@ -10,10 +10,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/store/dialects" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func NewQConfig(logSQL bool) pg.QConfig { diff --git a/core/internal/testutils/testutils.go b/core/internal/testutils/testutils.go index 6ffd873d092..81c09b1c362 100644 --- a/core/internal/testutils/testutils.go +++ b/core/internal/testutils/testutils.go @@ -425,15 +425,6 @@ func AssertCount(t *testing.T, db *sqlx.DB, tableName string, expected int64) { require.Equal(t, expected, count) } -func AssertCountPerSubject(t *testing.T, db *sqlx.DB, expected int64, subject uuid.UUID) { - t.Helper() - var count int64 - err := db.Get(&count, `SELECT COUNT(*) FROM evm.txes - WHERE state = 'unstarted' AND subject = $1;`, subject) - require.NoError(t, err) - require.Equal(t, expected, count) -} - func NewTestFlagSet() *flag.FlagSet { return flag.NewFlagSet("test", flag.PanicOnError) } diff --git a/core/logger/audit/audit_logger.go b/core/logger/audit/audit_logger.go index ef66a063a55..2f96c40586f 100644 --- a/core/logger/audit/audit_logger.go +++ b/core/logger/audit/audit_logger.go @@ -13,8 +13,8 @@ import ( "os" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -38,7 +38,7 @@ type HTTPAuditLoggerInterface interface { type AuditLoggerService struct { logger logger.Logger // The standard logger configured in the node enabled bool // Whether the audit logger is enabled or not - forwardToUrl models.URL // Location we are going to send logs to + forwardToUrl commonconfig.URL // Location we are going to send logs to headers []models.ServiceHeader // Headers to be sent along with logs for identification/authentication jsonWrapperKey string // Wrap audit data as a map under this key if present environmentName string // Decorate the environment this is coming from diff --git a/core/logger/audit/audit_logger_test.go b/core/logger/audit/audit_logger_test.go index 576d11df3a4..a28c35b129d 100644 --- a/core/logger/audit/audit_logger_test.go +++ b/core/logger/audit/audit_logger_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -65,10 +66,10 @@ func (c Config) Environment() string { return "test" } -func (c Config) ForwardToUrl() (models.URL, error) { - url, err := models.ParseURL("http://localhost:9898") +func (c Config) ForwardToUrl() (commonconfig.URL, error) { + url, err := commonconfig.ParseURL("http://localhost:9898") if err != nil { - return models.URL{}, err + return commonconfig.URL{}, err } return *url, nil } diff --git a/core/logger/logger_mock_test.go b/core/logger/logger_mock_test.go index 2b6dfcf3b22..afddd031888 100644 --- a/core/logger/logger_mock_test.go +++ b/core/logger/logger_mock_test.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package logger @@ -108,6 +108,10 @@ func (_m *MockLogger) Fatalw(msg string, keysAndValues ...interface{}) { func (_m *MockLogger) Helper(skip int) Logger { ret := _m.Called(skip) + if len(ret) == 0 { + panic("no return value specified for Helper") + } + var r0 Logger if rf, ok := ret.Get(0).(func(int) Logger); ok { r0 = rf(skip) @@ -147,6 +151,10 @@ func (_m *MockLogger) Infow(msg string, keysAndValues ...interface{}) { func (_m *MockLogger) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -161,6 +169,10 @@ func (_m *MockLogger) Name() string { func (_m *MockLogger) Named(name string) Logger { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for Named") + } + var r0 Logger if rf, ok := ret.Get(0).(func(string) Logger); ok { r0 = rf(name) @@ -210,6 +222,10 @@ func (_m *MockLogger) SetLogLevel(_a0 zapcore.Level) { func (_m *MockLogger) Sync() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Sync") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -272,6 +288,10 @@ func (_m *MockLogger) With(args ...interface{}) Logger { _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for With") + } + var r0 Logger if rf, ok := ret.Get(0).(func(...interface{}) Logger); ok { r0 = rf(args...) diff --git a/core/logger/mocks/logger.go b/core/logger/mocks/logger.go index 965bd57baaf..316f6216b90 100644 --- a/core/logger/mocks/logger.go +++ b/core/logger/mocks/logger.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -110,6 +110,10 @@ func (_m *Logger) Fatalw(msg string, keysAndValues ...interface{}) { func (_m *Logger) Helper(skip int) logger.Logger { ret := _m.Called(skip) + if len(ret) == 0 { + panic("no return value specified for Helper") + } + var r0 logger.Logger if rf, ok := ret.Get(0).(func(int) logger.Logger); ok { r0 = rf(skip) @@ -149,6 +153,10 @@ func (_m *Logger) Infow(msg string, keysAndValues ...interface{}) { func (_m *Logger) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -163,6 +171,10 @@ func (_m *Logger) Name() string { func (_m *Logger) Named(name string) logger.Logger { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for Named") + } + var r0 logger.Logger if rf, ok := ret.Get(0).(func(string) logger.Logger); ok { r0 = rf(name) @@ -212,6 +224,10 @@ func (_m *Logger) SetLogLevel(_a0 zapcore.Level) { func (_m *Logger) Sync() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Sync") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -274,6 +290,10 @@ func (_m *Logger) With(args ...interface{}) logger.Logger { _ca = append(_ca, args...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for With") + } + var r0 logger.Logger if rf, ok := ret.Get(0).(func(...interface{}) logger.Logger); ok { r0 = rf(args...) diff --git a/core/null/int64.go b/core/null/int64.go index 2a31aea7594..ca236784486 100644 --- a/core/null/int64.go +++ b/core/null/int64.go @@ -43,7 +43,7 @@ func (i *Int64) UnmarshalJSON(data []byte) error { // Unmarshal again, directly to value, to avoid intermediate float64 err = json.Unmarshal(data, &i.Int64) case string: - str := string(x) + str := x if len(str) == 0 { i.Valid = false return nil @@ -85,7 +85,7 @@ func (i Int64) MarshalJSON() ([]byte, error) { if !i.Valid { return []byte("null"), nil } - return []byte(strconv.FormatInt(int64(i.Int64), 10)), nil + return []byte(strconv.FormatInt(i.Int64, 10)), nil } // MarshalText implements encoding.TextMarshaler. @@ -94,7 +94,7 @@ func (i Int64) MarshalText() ([]byte, error) { if !i.Valid { return []byte{}, nil } - return []byte(strconv.FormatInt(int64(i.Int64), 10)), nil + return []byte(strconv.FormatInt(i.Int64, 10)), nil } // SetValid changes this Int64's value and also sets it to be non-null. @@ -112,7 +112,7 @@ func (i Int64) Value() (driver.Value, error) { // golang's sql driver types as determined by IsValue only supports: // []byte, bool, float64, int64, string, time.Time // https://golang.org/src/database/sql/driver/types.go - return int64(i.Int64), nil + return i.Int64, nil } // Scan reads the database value and returns an instance. @@ -130,7 +130,7 @@ func (i *Int64) Scan(value interface{}) error { safe := int64(typed) *i = Int64From(safe) case int64: - safe := int64(typed) + safe := typed *i = Int64From(safe) case uint: if typed > uint(math.MaxInt64) { diff --git a/core/null/uint32.go b/core/null/uint32.go index 0bafef0c24e..1d4fbc15b79 100644 --- a/core/null/uint32.go +++ b/core/null/uint32.go @@ -42,7 +42,7 @@ func (i *Uint32) UnmarshalJSON(data []byte) error { // Unmarshal again, directly to value, to avoid intermediate float64 err = json.Unmarshal(data, &i.Uint32) case string: - str := string(x) + str := x if len(str) == 0 { i.Valid = false return nil diff --git a/core/scripts/chaincli/.env.debugging.example b/core/scripts/chaincli/.env.debugging.example new file mode 100644 index 00000000000..c2942b99076 --- /dev/null +++ b/core/scripts/chaincli/.env.debugging.example @@ -0,0 +1,15 @@ +# [Mandatory] http url of the archival node for your network +NODE_URL= +# [Mandatory] address of the KeeperRegistry contract for your upkeep +KEEPER_REGISTRY_ADDRESS= + +# [Optional] it is strongly recommended (not mandatory) to use tenderly for more debugging info +#TENDERLY_KEY= +#TENDERLY_ACCOUNT_NAME= +#TENDERLY_PROJECT_NAME= + +# [Optional] add data streams (https://docs.chain.link/data-streams) info only if your upkeep uses data streams +#DATA_STREAMS_ID= +#DATA_STREAMS_KEY= +#DATA_STREAMS_URL= +#DATA_STREAMS_LEGACY_URL= \ No newline at end of file diff --git a/core/scripts/chaincli/DEBUGGING.md b/core/scripts/chaincli/DEBUGGING.md new file mode 100644 index 00000000000..6466a40fc31 --- /dev/null +++ b/core/scripts/chaincli/DEBUGGING.md @@ -0,0 +1,95 @@ +## Automation Debugging Script + +### Context + +The debugging script is a tool within ChainCLI designed to facilitate the debugging of upkeeps in Automation v21, covering both conditional and log-based scenarios. + +### Setup + +Before starting, you will need: +1. Git clone this chainlink [repo](https://github.com/smartcontractkit/chainlink) +2. A working [Go](https://go.dev/doc/install) installation +2. Change directory to `core/scripts/chaincli` and create a `.env` file based on the example `.env.debugging.example` + +### Configuration in `.env` File + +#### Mandatory Fields + +Ensure the following fields are provided in your `.env` file: + +- `NODE_URL`: Archival node URL +- `KEEPER_REGISTRY_ADDRESS`: Address of the Keeper Registry contract. Refer to the [Supported Networks](https://docs.chain.link/chainlink-automation/overview/supported-networks#configurations) doc for addresses. + +#### Optional Fields (Streams Lookup) + +If your targeted upkeep involves streams lookup, please provide the following details. If you are using Data Streams v0.3 (which is likely), only provide the DATA_STREAMS_URL. The DATA_STREAMS_LEGACY_URL is specifically for Data Streams v0.2. + +- `DATA_STREAMS_ID` +- `DATA_STREAMS_KEY` +- `DATA_STREAMS_LEGACY_URL` +- `DATA_STREAMS_URL` + +#### Optional Fields (Tenderly Integration) + +For detailed transaction simulation logs, set up Tenderly credentials. Refer to the [Tenderly Documentation](https://docs.tenderly.co/other/platform-access/how-to-generate-api-access-tokens) for creating an API key, account name, and project name. + +- `TENDERLY_KEY` +- `TENDERLY_ACCOUNT_NAME` +- `TENDERLY_PROJECT_NAME` + +### Usage + +Execute the following command based on your upkeep type: + +- For conditional upkeep, if a block number is given we use that block, otherwise we use the latest block: + + ```bash + go run main.go keeper debug UPKEEP_ID [OPTIONAL BLOCK_NUMBER] + ``` + +- For log trigger upkeep: + + ```bash + go run main.go keeper debug UPKEEP_ID TX_HASH LOG_INDEX + ``` + +### Checks Performed by the Debugging Script + +1. **Fetch and Sanity Check Upkeep:** + - Verify upkeep status: active, paused, or canceled + - Check upkeep balance + +2. **For Conditional Upkeep:** + - Check conditional upkeep + - Simulate `performUpkeep` + +3. **For Log Trigger Upkeep:** + - Check if the upkeep has already run for log-trigger-based upkeep + - Verify if log matches trigger configuration + - Check upkeep + - If check result indicates a streams lookup is required (TargetCheckReverted): + - Verify if the upkeep is allowed to use Mercury + - Execute Mercury request + - Execute check callback + + - Simulate `performUpkeep` + +### Examples +- Eligible and log trigger based and using mercury lookup v0.3: + + ```bash + go run main.go keeper debug 5591498142036749453487419299781783197030971023186134955311257372668222176389 0xdc6d0e547a5aa85fefa5b0f3a37e3493eafb5aeba8b5f3071ce53c9e9a539e9c 0 + ``` + +- Ineligible and conditional upkeep: + + ```bash + go run main.go keeper debug 52635131310730056105456985154251306793887717546629785340977553840883117540096 + ``` + +- Ineligible and Log does not match trigger config: + + ```bash + go run main.go keeper debug 5591498142036749453487419299781783197030971023186134955311257372668222176389 0xc0686ae85d2a7a976ef46df6c613517b9fd46f23340ac583be4e44f5c8b7a186 1 + ``` +--- \ No newline at end of file diff --git a/core/scripts/chaincli/README.md b/core/scripts/chaincli/README.md index da7aa7cc777..992250ae77c 100644 --- a/core/scripts/chaincli/README.md +++ b/core/scripts/chaincli/README.md @@ -122,3 +122,5 @@ You can use the `grep` and `grepv` flags to filter log lines, e.g. to only show ```shell ./chaincli keeper logs --grep keepers-plugin ``` + +--- \ No newline at end of file diff --git a/core/scripts/chaincli/command/keeper/upkeep.go b/core/scripts/chaincli/command/keeper/upkeep.go index 8e2bc8bd993..c615bbf1aec 100644 --- a/core/scripts/chaincli/command/keeper/upkeep.go +++ b/core/scripts/chaincli/command/keeper/upkeep.go @@ -82,14 +82,11 @@ var ocr2UpkeepReportHistoryCmd = &cobra.Command{ hdlr := handler.NewBaseHandler(cfg) var hashes []string - var err error - var path string - - path, err = cmd.Flags().GetString("csv") + path, err := cmd.Flags().GetString("csv") if err == nil && len(path) != 0 { - rec, err := readCsvFile(path) - if err != nil { - log.Fatal(err) + rec, err2 := readCsvFile(path) + if err2 != nil { + log.Fatal(err2) } if len(rec) < 1 { @@ -107,7 +104,7 @@ var ocr2UpkeepReportHistoryCmd = &cobra.Command{ } } - if err := handler.OCR2AutomationReports(hdlr, hashes); err != nil { + if err = handler.OCR2AutomationReports(hdlr, hashes); err != nil { log.Fatalf("failed to collect transaction data: %s", err) } }, diff --git a/core/scripts/chaincli/command/keeper/verifiable_load.go b/core/scripts/chaincli/command/keeper/verifiable_load.go index 33acf9bf3b2..ce0acddfbdb 100644 --- a/core/scripts/chaincli/command/keeper/verifiable_load.go +++ b/core/scripts/chaincli/command/keeper/verifiable_load.go @@ -21,7 +21,7 @@ var verifiableLoad = &cobra.Command{ if err != nil { log.Fatal("failed to get verify flag: ", err) } - hdlr.GetVerifiableLoadStats(cmd.Context(), csv) + hdlr.PrintVerifiableLoadStats(cmd.Context(), csv) }, } diff --git a/core/scripts/chaincli/config/config.go b/core/scripts/chaincli/config/config.go index d227aa2e298..a17671bf8a8 100644 --- a/core/scripts/chaincli/config/config.go +++ b/core/scripts/chaincli/config/config.go @@ -90,12 +90,12 @@ type Config struct { FeedQuoteAddr string `mapstructure:"FEED_QUOTE_ADDR"` FeedDecimals uint8 `mapstructure:"FEED_DECIMALS"` - // Mercury Config - MercuryURL string `mapstructure:"MERCURY_URL"` - MercuryLegacyURL string `mapstructure:"MERCURY_LEGACY_URL"` - MercuryID string `mapstructure:"MERCURY_ID"` - MercuryKey string `mapstructure:"MERCURY_KEY"` - MercuryCredName string `mapstructure:"MERCURY_CRED_NAME"` + // Data Streams Config + DataStreamsURL string `mapstructure:"DATA_STREAMS_URL"` + DataStreamsLegacyURL string `mapstructure:"DATA_STREAMS_LEGACY_URL"` + DataStreamsID string `mapstructure:"DATA_STREAMS_ID"` + DataStreamsKey string `mapstructure:"DATA_STREAMS_KEY"` + DataStreamsCredName string `mapstructure:"DATA_STREAMS_CRED_NAME"` // Tenderly TenderlyKey string `mapstructure:"TENDERLY_KEY"` diff --git a/core/scripts/chaincli/handler/bootstrap.go b/core/scripts/chaincli/handler/bootstrap.go index 4cc19299cca..bf79f5698dc 100644 --- a/core/scripts/chaincli/handler/bootstrap.go +++ b/core/scripts/chaincli/handler/bootstrap.go @@ -47,17 +47,17 @@ func (h *baseHandler) StartBootstrapNode(ctx context.Context, addr string, uiPor lggr.Fatal("Failed to launch chainlink node, ", err) } - cl, err := authenticate(urlRaw, defaultChainlinkNodeLogin, defaultChainlinkNodePassword, lggr) + cl, err := authenticate(ctx, urlRaw, defaultChainlinkNodeLogin, defaultChainlinkNodePassword, lggr) if err != nil { lggr.Fatal("Authentication failed, ", err) } - p2pKeyID, err := getP2PKeyID(cl) + p2pKeyID, err := getP2PKeyID(ctx, cl) if err != nil { lggr.Fatal("Failed to get P2P key ID, ", err) } - if err = h.createBootstrapJob(cl, addr); err != nil { + if err = h.createBootstrapJob(ctx, cl, addr); err != nil { lggr.Fatal("Failed to create keeper job: ", err) } @@ -68,7 +68,7 @@ func (h *baseHandler) StartBootstrapNode(ctx context.Context, addr string, uiPor } // createBootstrapJob creates a bootstrap job in the chainlink node by the given address -func (h *baseHandler) createBootstrapJob(client cmd.HTTPClient, contractAddr string) error { +func (h *baseHandler) createBootstrapJob(ctx context.Context, client cmd.HTTPClient, contractAddr string) error { request, err := json.Marshal(web.CreateJobRequest{ TOML: fmt.Sprintf(bootstrapJobSpec, contractAddr, h.cfg.ChainID), }) @@ -76,7 +76,7 @@ func (h *baseHandler) createBootstrapJob(client cmd.HTTPClient, contractAddr str return fmt.Errorf("failed to marshal request: %s", err) } - resp, err := client.Post("/v2/jobs", bytes.NewReader(request)) + resp, err := client.Post(ctx, "/v2/jobs", bytes.NewReader(request)) if err != nil { return fmt.Errorf("failed to create bootstrap job: %s", err) } diff --git a/core/scripts/chaincli/handler/debug.go b/core/scripts/chaincli/handler/debug.go index fec8c6cd414..cfd260e16a9 100644 --- a/core/scripts/chaincli/handler/debug.go +++ b/core/scripts/chaincli/handler/debug.go @@ -14,22 +14,28 @@ import ( "os" "strconv" + types2 "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/accounts/abi/bind" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" + + evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" + + commonhex "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" "github.com/smartcontractkit/chainlink/core/scripts/chaincli/config" "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" - "github.com/smartcontractkit/chainlink/v2/core/utils" bigmath "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) @@ -44,6 +50,7 @@ const ( timestamp = "timestamp" ) +var mercuryPacker = mercury.NewAbiPacker() var packer = encoding.NewAbiPacker() var links []string @@ -52,24 +59,31 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if len(args) < 1 { failCheckArgs("no upkeepID supplied", nil) } + // test that we are connected to an archive node _, err := k.client.BalanceAt(ctx, gethcommon.Address{}, big.NewInt(1)) if err != nil { failCheckConfig("you are not connected to an archive node; try using infura or alchemy", err) } + chainIDBig, err := k.client.ChainID(ctx) if err != nil { failUnknown("unable to retrieve chainID from rpc client", err) } chainID := chainIDBig.Int64() + + // Log triggers: always use block from tx + // Conditional: use latest block if no block number is provided, otherwise use block from user input + var triggerCallOpts *bind.CallOpts // use a certain block + latestCallOpts := &bind.CallOpts{Context: ctx} // use the latest block + // connect to registry contract - latestCallOpts := &bind.CallOpts{Context: ctx} // always use latest block - triggerCallOpts := &bind.CallOpts{Context: ctx} // use latest block for conditionals, but use block from tx for log triggers registryAddress := gethcommon.HexToAddress(k.cfg.RegistryAddress) keeperRegistry21, err := iregistry21.NewIKeeperRegistryMaster(registryAddress, k.client) if err != nil { - failUnknown("failed to connect to registry contract", err) + failUnknown("failed to connect to the registry contract", err) } + // verify contract is correct typeAndVersion, err := keeperRegistry21.TypeAndVersion(latestCallOpts) if err != nil { @@ -80,7 +94,7 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { } // get upkeepID from command args upkeepID := big.NewInt(0) - upkeepIDNoPrefix := utils.RemoveHexPrefix(args[0]) + upkeepIDNoPrefix := commonhex.TrimPrefix(args[0]) _, wasBase10 := upkeepID.SetString(upkeepIDNoPrefix, 10) if !wasBase10 { _, wasBase16 := upkeepID.SetString(upkeepIDNoPrefix, 16) @@ -105,8 +119,8 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if (upkeepInfo.Target == gethcommon.Address{}) { failCheckArgs("this upkeep does not exist on this registry", nil) } - addLink("upkeep", common.UpkeepLink(chainID, upkeepID)) - addLink("target", common.ContractExplorerLink(chainID, upkeepInfo.Target)) + addLink("upkeep link", common.UpkeepLink(chainID, upkeepID)) + addLink("upkeep contract address", common.ContractExplorerLink(chainID, upkeepInfo.Target)) if upkeepInfo.Paused { resolveIneligible("upkeep is paused") } @@ -129,17 +143,32 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { // check upkeep if triggerType == ConditionTrigger { message("upkeep identified as conditional trigger") - tmpCheckResult, err := keeperRegistry21.CheckUpkeep0(latestCallOpts, upkeepID) + + if len(args) > 1 { + // if a block number is provided, use that block for both checkUpkeep and simulatePerformUpkeep + blockNum, err = strconv.ParseUint(args[1], 10, 64) + if err != nil { + failCheckArgs("unable to parse block number", err) + } + triggerCallOpts = &bind.CallOpts{Context: ctx, BlockNumber: new(big.Int).SetUint64(blockNum)} + } else { + // if no block number is provided, use latest block for both checkUpkeep and simulatePerformUpkeep + triggerCallOpts = latestCallOpts + } + + var tmpCheckResult iregistry21.CheckUpkeep0 + tmpCheckResult, err = keeperRegistry21.CheckUpkeep0(triggerCallOpts, upkeepID) if err != nil { failUnknown("failed to check upkeep: ", err) } checkResult = iregistry21.CheckUpkeep(tmpCheckResult) // do tenderly simulation - rawCall, err := core.RegistryABI.Pack("checkUpkeep", upkeepID, []byte{}) + var rawCall []byte + rawCall, err = core.RegistryABI.Pack("checkUpkeep", upkeepID, []byte{}) if err != nil { failUnknown("failed to pack raw checkUpkeep call", err) } - addLink("checkUpkeep simulation", tenderlySimLink(k.cfg, chainID, 0, rawCall, registryAddress)) + addLink("checkUpkeep simulation", tenderlySimLink(ctx, k.cfg, chainID, 0, rawCall, registryAddress)) } else if triggerType == LogTrigger { // validate inputs message("upkeep identified as log trigger") @@ -147,23 +176,30 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { failCheckArgs("txHash and log index must be supplied to command in order to debug log triggered upkeeps", nil) } txHash := gethcommon.HexToHash(args[1]) - logIndex, err := strconv.ParseInt(args[2], 10, 64) + + var logIndex int64 + logIndex, err = strconv.ParseInt(args[2], 10, 64) if err != nil { failCheckArgs("unable to parse log index", err) } - // find transaction receipt - _, isPending, err := k.client.TransactionByHash(ctx, txHash) + + // check that tx is confirmed + var isPending bool + _, isPending, err = k.client.TransactionByHash(ctx, txHash) if err != nil { log.Fatal("failed to get tx by hash", err) } if isPending { resolveIneligible(fmt.Sprintf("tx %s is still pending confirmation", txHash)) } - receipt, err := k.client.TransactionReceipt(ctx, txHash) + + // find transaction receipt + var receipt *types.Receipt + receipt, err = k.client.TransactionReceipt(ctx, txHash) if err != nil { failCheckArgs("failed to fetch tx receipt", err) } - addLink("trigger", common.ExplorerLink(chainID, txHash)) + addLink("trigger transaction", common.ExplorerLink(chainID, txHash)) blockNum = receipt.BlockNumber.Uint64() // find matching log event in tx var triggeringEvent *types.Log @@ -179,7 +215,8 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { message(fmt.Sprintf("LogTrigger{blockNum: %d, blockHash: %s, txHash: %s, logIndex: %d}", blockNum, receipt.BlockHash.Hex(), txHash, logIndex)) workID := mustUpkeepWorkID(upkeepID, blockNum, receipt.BlockHash, txHash, logIndex) message(fmt.Sprintf("workID computed: %s", hex.EncodeToString(workID[:]))) - hasKey, err := keeperRegistry21.HasDedupKey(latestCallOpts, workID) + var hasKey bool + hasKey, err = keeperRegistry21.HasDedupKey(latestCallOpts, workID) if err != nil { failUnknown("failed to check if upkeep was already performed: ", err) } @@ -187,11 +224,13 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { resolveIneligible("upkeep was already performed") } triggerCallOpts = &bind.CallOpts{Context: ctx, BlockNumber: big.NewInt(receipt.BlockNumber.Int64())} - rawTriggerConfig, err := keeperRegistry21.GetUpkeepTriggerConfig(triggerCallOpts, upkeepID) + var rawTriggerConfig []byte + rawTriggerConfig, err = keeperRegistry21.GetUpkeepTriggerConfig(triggerCallOpts, upkeepID) if err != nil { failUnknown("failed to fetch trigger config for upkeep", err) } - triggerConfig, err := packer.UnpackLogTriggerConfig(rawTriggerConfig) + var triggerConfig automation_utils_2_1.LogTriggerConfig + triggerConfig, err = packer.UnpackLogTriggerConfig(rawTriggerConfig) if err != nil { failUnknown("failed to unpack trigger config", err) } @@ -201,11 +240,13 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if !logMatchesTriggerConfig(triggeringEvent, triggerConfig) { resolveIneligible("log does not match trigger config") } - header, err := k.client.HeaderByHash(ctx, receipt.BlockHash) + var header *types.Header + header, err = k.client.HeaderByHash(ctx, receipt.BlockHash) if err != nil { failUnknown("failed to find block", err) } - triggerData, err := packTriggerData(triggeringEvent, header.Time) + var triggerData []byte + triggerData, err = packTriggerData(triggeringEvent, header.Time) if err != nil { failUnknown("failed to pack trigger data", err) } @@ -214,92 +255,112 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { failUnknown("failed to check upkeep", err) } // do tenderly simulations - rawCall, err := core.RegistryABI.Pack("checkUpkeep", upkeepID, triggerData) + var rawCall []byte + rawCall, err = core.RegistryABI.Pack("checkUpkeep", upkeepID, triggerData) if err != nil { failUnknown("failed to pack raw checkUpkeep call", err) } - addLink("checkUpkeep simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) + addLink("checkUpkeep simulation", tenderlySimLink(ctx, k.cfg, chainID, blockNum, rawCall, registryAddress)) rawCall = append(core.ILogAutomationABI.Methods["checkLog"].ID, triggerData...) - addLink("checkLog (direct) simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, upkeepInfo.Target)) + addLink("checkLog (direct) simulation", tenderlySimLink(ctx, k.cfg, chainID, blockNum, rawCall, upkeepInfo.Target)) } else { resolveIneligible(fmt.Sprintf("invalid trigger type: %d", triggerType)) } upkeepNeeded, performData = checkResult.UpkeepNeeded, checkResult.PerformData - // handle streams lookup + if checkResult.UpkeepFailureReason != 0 { - message(fmt.Sprintf("checkUpkeep failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) + message(fmt.Sprintf("checkUpkeep failed with UpkeepFailureReason %s", getCheckUpkeepFailureReason(checkResult.UpkeepFailureReason))) } + + // handle data streams lookup if checkResult.UpkeepFailureReason == uint8(encoding.UpkeepFailureReasonTargetCheckReverted) { - // TODO use the new streams lookup lib - //mc := &models.MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey} - //mercuryConfig := evm.NewMercuryConfig(mc, core.StreamsCompatibleABI) - //lggr, _ := logger.NewLogger() - //blockSub := &blockSubscriber{k.client} - //_ = streams.NewStreamsLookup(packer, mercuryConfig, blockSub, keeperRegistry21, k.rpcClient, lggr) - - streamsLookupErr, err := packer.DecodeStreamsLookupRequest(checkResult.PerformData) + mc := &types2.MercuryCredentials{LegacyURL: k.cfg.DataStreamsLegacyURL, URL: k.cfg.DataStreamsURL, Username: k.cfg.DataStreamsID, Password: k.cfg.DataStreamsKey} + mercuryConfig := evm21.NewMercuryConfig(mc, core.StreamsCompatibleABI) + lggr, _ := logger.NewLogger() + blockSub := &blockSubscriber{k.client} + streams := streams.NewStreamsLookup(mercuryConfig, blockSub, k.rpcClient, keeperRegistry21, lggr) + + var streamsLookupErr *mercury.StreamsLookupError + streamsLookupErr, err = mercuryPacker.DecodeStreamsLookupRequest(checkResult.PerformData) if err == nil { message("upkeep reverted with StreamsLookup") message(fmt.Sprintf("StreamsLookup data: {FeedParamKey: %s, Feeds: %v, TimeParamKey: %s, Time: %d, ExtraData: %s}", streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time.Uint64(), hexutil.Encode(streamsLookupErr.ExtraData))) - if streamsLookupErr.FeedParamKey == feedIdHex && streamsLookupErr.TimeParamKey == blockNumber { - message("using mercury lookup v0.2") - // handle v0.2 - cfg, err := keeperRegistry21.GetUpkeepPrivilegeConfig(triggerCallOpts, upkeepID) + + streamsLookup := &mercury.StreamsLookup{ + StreamsLookupError: &mercury.StreamsLookupError{ + FeedParamKey: streamsLookupErr.FeedParamKey, + Feeds: streamsLookupErr.Feeds, + TimeParamKey: streamsLookupErr.TimeParamKey, + Time: streamsLookupErr.Time, + ExtraData: streamsLookupErr.ExtraData, + }, + UpkeepId: upkeepID, + Block: blockNum, + } + + if streamsLookup.IsMercuryV02() { + message("using data streams lookup v0.2") + // check if upkeep is allowed to use mercury v0.2 + var allowed bool + _, _, _, allowed, err = streams.AllowedToUseMercury(triggerCallOpts, upkeepID) if err != nil { - failUnknown("failed to get upkeep privilege config ", err) - } - allowed := false - if len(cfg) > 0 { - var privilegeConfig streams.UpkeepPrivilegeConfig - if err := json.Unmarshal(cfg, &privilegeConfig); err != nil { - failUnknown("failed to unmarshal privilege config ", err) - } - allowed = privilegeConfig.MercuryEnabled + failUnknown("failed to check if upkeep is allowed to use data streams", err) } if !allowed { resolveIneligible("upkeep reverted with StreamsLookup but is not allowed to access streams") } } else if streamsLookupErr.FeedParamKey != feedIDs || streamsLookupErr.TimeParamKey != timestamp { // handle v0.3 + message("using data streams lookup v0.3") + } else { resolveIneligible("upkeep reverted with StreamsLookup but the configuration is invalid") } else { message("using mercury lookup v0.3") } streamsLookup := &StreamsLookup{streamsLookupErr.FeedParamKey, streamsLookupErr.Feeds, streamsLookupErr.TimeParamKey, streamsLookupErr.Time, streamsLookupErr.ExtraData, upkeepID, blockNum} - if k.cfg.MercuryLegacyURL == "" || k.cfg.MercuryURL == "" || k.cfg.MercuryID == "" || k.cfg.MercuryKey == "" { - failCheckConfig("Mercury configs not set properly, check your MERCURY_LEGACY_URL, MERCURY_URL, MERCURY_ID and MERCURY_KEY", nil) + if k.cfg.DataStreamsLegacyURL == "" || k.cfg.DataStreamsURL == "" || k.cfg.DataStreamsID == "" || k.cfg.DataStreamsKey == "" { + failCheckConfig("Data streams configs not set properly, check your DATA_STREAMS_LEGACY_URL, DATA_STREAMS_URL, DATA_STREAMS_ID and DATA_STREAMS_KEY", nil) } - handler := NewMercuryLookupHandler(&MercuryCredentials{k.cfg.MercuryLegacyURL, k.cfg.MercuryURL, k.cfg.MercuryID, k.cfg.MercuryKey}, k.rpcClient) - state, failureReason, values, _, err := handler.doMercuryRequest(ctx, streamsLookup) - if failureReason == UpkeepFailureReasonInvalidRevertDataInput { + + // do mercury request + automationCheckResult := mustAutomationCheckResult(upkeepID, checkResult, trigger) + checkResults := []ocr2keepers.CheckResult{automationCheckResult} + + var values [][]byte + values, err = streams.DoMercuryRequest(ctx, streamsLookup, checkResults, 0) + + if checkResults[0].IneligibilityReason == uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput) { resolveIneligible("upkeep used invalid revert data") } - if state == InvalidMercuryRequest { - resolveIneligible("the mercury request data is invalid") + if checkResults[0].PipelineExecutionState == uint8(encoding.InvalidMercuryRequest) { + resolveIneligible("the data streams request data is invalid") } if err != nil { - failCheckConfig("failed to do mercury request ", err) + failCheckConfig("failed to do data streams request ", err) } - callbackResult, err := keeperRegistry21.CheckCallback(triggerCallOpts, upkeepID, values, streamsLookup.extraData) + + // do checkCallback + err = streams.CheckCallback(ctx, values, streamsLookup, checkResults, 0) if err != nil { - failUnknown("failed to execute mercury callback ", err) + failUnknown("failed to execute data streams callback ", err) } - if callbackResult.UpkeepFailureReason != 0 { - message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", checkResult.UpkeepFailureReason)) + if checkResults[0].IneligibilityReason != 0 { + message(fmt.Sprintf("checkCallback failed with UpkeepFailureReason %d", checkResults[0].IneligibilityReason)) } - upkeepNeeded, performData = callbackResult.UpkeepNeeded, callbackResult.PerformData - // do tenderly simulations - rawCall, err := core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.extraData) + upkeepNeeded, performData = checkResults[0].Eligible, checkResults[0].PerformData + // do tenderly simulations for checkCallback + var rawCall []byte + rawCall, err = core.RegistryABI.Pack("checkCallback", upkeepID, values, streamsLookup.ExtraData) if err != nil { failUnknown("failed to pack raw checkCallback call", err) } - addLink("checkCallback simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, registryAddress)) - rawCall, err = core.StreamsCompatibleABI.Pack("checkCallback", values, streamsLookup.extraData) + addLink("checkCallback simulation", tenderlySimLink(ctx, k.cfg, chainID, blockNum, rawCall, registryAddress)) + rawCall, err = core.StreamsCompatibleABI.Pack("checkCallback", values, streamsLookup.ExtraData) if err != nil { failUnknown("failed to pack raw checkCallback (direct) call", err) } - addLink("checkCallback (direct) simulation", tenderlySimLink(k.cfg, chainID, blockNum, rawCall, upkeepInfo.Target)) + addLink("checkCallback (direct) simulation", tenderlySimLink(ctx, k.cfg, chainID, blockNum, rawCall, upkeepInfo.Target)) } else { message("did not revert with StreamsLookup error") } @@ -307,14 +368,73 @@ func (k *Keeper) Debug(ctx context.Context, args []string) { if !upkeepNeeded { resolveIneligible("upkeep is not needed") } - // simulate perform ukeep - simulateResult, err := keeperRegistry21.SimulatePerformUpkeep(latestCallOpts, upkeepID, performData) + // simulate perform upkeep + simulateResult, err := keeperRegistry21.SimulatePerformUpkeep(triggerCallOpts, upkeepID, performData) if err != nil { failUnknown("failed to simulate perform upkeep: ", err) } + + // do tenderly simulation + rawCall, err := core.RegistryABI.Pack("simulatePerformUpkeep", upkeepID, performData) + if err != nil { + failUnknown("failed to pack raw simulatePerformUpkeep call", err) + } + addLink("simulatePerformUpkeep simulation", tenderlySimLink(ctx, k.cfg, chainID, blockNum, rawCall, registryAddress)) + if simulateResult.Success { resolveEligible() + } else { + // Convert performGas to *big.Int for comparison + performGasBigInt := new(big.Int).SetUint64(uint64(upkeepInfo.PerformGas)) + // Compare PerformGas and GasUsed + result := performGasBigInt.Cmp(simulateResult.GasUsed) + + if result < 0 { + // PerformGas is smaller than GasUsed + resolveIneligible(fmt.Sprintf("simulate perform upkeep unsuccessful, PerformGas (%d) is lower than GasUsed (%s)", upkeepInfo.PerformGas, simulateResult.GasUsed.String())) + } else { + resolveIneligible("simulate perform upkeep unsuccessful") + } + } +} + +func getCheckUpkeepFailureReason(reasonIndex uint8) string { + // Copied from KeeperRegistryBase2_1.sol + reasonStrings := []string{ + "NONE", + "UPKEEP_CANCELLED", + "UPKEEP_PAUSED", + "TARGET_CHECK_REVERTED", + "UPKEEP_NOT_NEEDED", + "PERFORM_DATA_EXCEEDS_LIMIT", + "INSUFFICIENT_BALANCE", + "CALLBACK_REVERTED", + "REVERT_DATA_EXCEEDS_LIMIT", + "REGISTRY_PAUSED", + } + + if int(reasonIndex) < len(reasonStrings) { + return reasonStrings[reasonIndex] + } + + return fmt.Sprintf("Unknown : %d", reasonIndex) +} + +func mustAutomationCheckResult(upkeepID *big.Int, checkResult iregistry21.CheckUpkeep, trigger ocr2keepers.Trigger) ocr2keepers.CheckResult { + upkeepIdentifier := mustUpkeepIdentifier(upkeepID) + checkResult2 := ocr2keepers.CheckResult{ + Eligible: checkResult.UpkeepNeeded, + IneligibilityReason: checkResult.UpkeepFailureReason, + UpkeepID: upkeepIdentifier, + Trigger: trigger, + WorkID: core.UpkeepWorkID(upkeepIdentifier, trigger), + GasAllocated: 0, + PerformData: checkResult.PerformData, + FastGasWei: checkResult.FastGasWei, + LinkNative: checkResult.LinkNative, } + + return checkResult2 } type blockSubscriber struct { @@ -402,11 +522,11 @@ func warning(msg string) { } func resolveIneligible(msg string) { - exit(fmt.Sprintf("✅ %s: this upkeep is not currently elligible", msg), nil, 0) + exit(fmt.Sprintf("❌ this upkeep is not eligible: %s", msg), nil, 0) } func resolveEligible() { - exit("❌ this upkeep is currently elligible", nil, 0) + exit("✅ this upkeep is eligible", nil, 0) } func rerun(msg string, err error) { @@ -450,7 +570,7 @@ type TenderlyAPIResponse struct { } } -func tenderlySimLink(cfg *config.Config, chainID int64, blockNumber uint64, input []byte, contractAddress gethcommon.Address) string { +func tenderlySimLink(ctx context.Context, cfg *config.Config, chainID int64, blockNumber uint64, input []byte, contractAddress gethcommon.Address) string { errResult := "" if cfg.TenderlyAccountName == "" || cfg.TenderlyKey == "" || cfg.TenderlyProjectName == "" { warning("tenderly credentials not properly configured - this is optional but helpful") @@ -472,7 +592,8 @@ func tenderlySimLink(cfg *config.Config, chainID int64, blockNumber uint64, inpu warning(fmt.Sprintf("unable to marshal tenderly request data: %v", err)) return errResult } - request, err := http.NewRequest( + request, err := http.NewRequestWithContext( + ctx, "POST", fmt.Sprintf("https://api.tenderly.co/api/v1/account/%s/project/%s/simulate", cfg.TenderlyAccountName, cfg.TenderlyProjectName), bytes.NewBuffer(jsonData), diff --git a/core/scripts/chaincli/handler/handler.go b/core/scripts/chaincli/handler/handler.go index f72e94605d4..a5b6798836a 100644 --- a/core/scripts/chaincli/handler/handler.go +++ b/core/scripts/chaincli/handler/handler.go @@ -333,7 +333,7 @@ func (h *baseHandler) launchChainlinkNode(ctx context.Context, port int, contain if err != nil { return "", nil, fmt.Errorf("failed to create toml file: %w", err) } - var secretTOMLStr = fmt.Sprintf(secretTOML, h.cfg.MercuryURL, h.cfg.MercuryID, h.cfg.MercuryKey) + var secretTOMLStr = fmt.Sprintf(secretTOML, h.cfg.DataStreamsURL, h.cfg.DataStreamsID, h.cfg.DataStreamsKey) secretFile, secretTOMLFileCleanup, err := createTomlFile(secretTOMLStr) if err != nil { return "", nil, fmt.Errorf("failed to create secret toml file: %w", err) @@ -399,7 +399,7 @@ func (h *baseHandler) launchChainlinkNode(ctx context.Context, port int, contain addr := fmt.Sprintf("http://localhost:%s", portStr) log.Println("Node docker container successfully created and started: ", nodeContainerResp.ID, addr) - if err = waitForNodeReady(addr); err != nil { + if err = waitForNodeReady(ctx, addr); err != nil { log.Fatal(err, nodeContainerResp.ID) } log.Println("Node ready: ", nodeContainerResp.ID) @@ -411,44 +411,44 @@ func (h *baseHandler) launchChainlinkNode(ctx context.Context, port int, contain if writeLogs { var rdr io.ReadCloser - rdr, err := dockerClient.ContainerLogs(ctx, nodeContainerResp.ID, types.ContainerLogsOptions{ + rdr, err2 := dockerClient.ContainerLogs(ctx, nodeContainerResp.ID, types.ContainerLogsOptions{ ShowStderr: true, Timestamps: true, }) - if err != nil { + if err2 != nil { rdr.Close() - log.Fatal("Failed to collect logs from container: ", err) + log.Fatal("Failed to collect logs from container: ", err2) } - stdErr, err := os.OpenFile(fmt.Sprintf("./%s-stderr.log", nodeContainerResp.ID), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { + stdErr, err2 := os.OpenFile(fmt.Sprintf("./%s-stderr.log", nodeContainerResp.ID), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) + if err2 != nil { rdr.Close() stdErr.Close() - log.Fatal("Failed to open file: ", err) + log.Fatal("Failed to open file: ", err2) } - if _, err := stdcopy.StdCopy(io.Discard, stdErr, rdr); err != nil { + if _, err2 := stdcopy.StdCopy(io.Discard, stdErr, rdr); err2 != nil { rdr.Close() stdErr.Close() - log.Fatal("Failed to write logs to file: ", err) + log.Fatal("Failed to write logs to file: ", err2) } rdr.Close() stdErr.Close() } - if err = dockerClient.ContainerStop(ctx, nodeContainerResp.ID, container.StopOptions{}); err != nil { - log.Fatal("Failed to stop node container: ", err) + if err2 := dockerClient.ContainerStop(ctx, nodeContainerResp.ID, container.StopOptions{}); err2 != nil { + log.Fatal("Failed to stop node container: ", err2) } - if err = dockerClient.ContainerRemove(ctx, nodeContainerResp.ID, types.ContainerRemoveOptions{}); err != nil { - log.Fatal("Failed to remove node container: ", err) + if err2 := dockerClient.ContainerRemove(ctx, nodeContainerResp.ID, types.ContainerRemoveOptions{}); err2 != nil { + log.Fatal("Failed to remove node container: ", err2) } - if err = dockerClient.ContainerStop(ctx, dbContainerResp.ID, container.StopOptions{}); err != nil { - log.Fatal("Failed to stop DB container: ", err) + if err2 := dockerClient.ContainerStop(ctx, dbContainerResp.ID, container.StopOptions{}); err2 != nil { + log.Fatal("Failed to stop DB container: ", err2) } - if err = dockerClient.ContainerRemove(ctx, dbContainerResp.ID, types.ContainerRemoveOptions{}); err != nil { - log.Fatal("Failed to remove DB container: ", err) + if err2 := dockerClient.ContainerRemove(ctx, dbContainerResp.ID, types.ContainerRemoveOptions{}); err2 != nil { + log.Fatal("Failed to remove DB container: ", err2) } }, nil } @@ -477,13 +477,13 @@ func checkAndRemoveContainer(ctx context.Context, dockerClient *client.Client, c return nil } -func waitForNodeReady(addr string) error { +func waitForNodeReady(ctx context.Context, addr string) error { client := &http.Client{} defer client.CloseIdleConnections() const timeout = 120 startTime := time.Now().Unix() for { - req, err := http.NewRequest("GET", fmt.Sprintf("%s/health", addr), nil) + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/health", addr), nil) if err != nil { return err } @@ -503,7 +503,7 @@ func waitForNodeReady(addr string) error { } // authenticate creates a http client with URL, email and password -func authenticate(urlStr, email, password string, lggr logger.Logger) (cmd.HTTPClient, error) { +func authenticate(ctx context.Context, urlStr, email, password string, lggr logger.Logger) (cmd.HTTPClient, error) { remoteNodeURL, err := url.Parse(urlStr) if err != nil { return nil, err @@ -514,7 +514,7 @@ func authenticate(urlStr, email, password string, lggr logger.Logger) (cmd.HTTPC store := &cmd.MemoryCookieStore{} tca := cmd.NewSessionCookieAuthenticator(c, store, lggr) - if _, err = tca.Authenticate(sr); err != nil { + if _, err = tca.Authenticate(ctx, sr); err != nil { log.Println("failed to authenticate: ", err) return nil, err } @@ -522,8 +522,8 @@ func authenticate(urlStr, email, password string, lggr logger.Logger) (cmd.HTTPC return cmd.NewAuthenticatedHTTPClient(lggr, c, tca, sr), nil } -func nodeRequest(client cmd.HTTPClient, path string) ([]byte, error) { - resp, err := client.Get(path) +func nodeRequest(ctx context.Context, client cmd.HTTPClient, path string) ([]byte, error) { + resp, err := client.Get(ctx, path) if err != nil { return []byte{}, fmt.Errorf("GET error from client: %w", err) } @@ -551,8 +551,8 @@ func nodeRequest(client cmd.HTTPClient, path string) ([]byte, error) { } // getNodeAddress returns chainlink node's wallet address -func getNodeAddress(client cmd.HTTPClient) (string, error) { - resp, err := nodeRequest(client, ethKeysEndpoint) +func getNodeAddress(ctx context.Context, client cmd.HTTPClient) (string, error) { + resp, err := nodeRequest(ctx, client, ethKeysEndpoint) if err != nil { return "", fmt.Errorf("failed to get ETH keys: %w", err) } @@ -566,8 +566,8 @@ func getNodeAddress(client cmd.HTTPClient) (string, error) { } // getNodeOCR2Config returns chainlink node's OCR2 bundle key ID -func getNodeOCR2Config(client cmd.HTTPClient) (*cmd.OCR2KeyBundlePresenter, error) { - resp, err := nodeRequest(client, ocr2KeysEndpoint) +func getNodeOCR2Config(ctx context.Context, client cmd.HTTPClient) (*cmd.OCR2KeyBundlePresenter, error) { + resp, err := nodeRequest(ctx, client, ocr2KeysEndpoint) if err != nil { return nil, fmt.Errorf("failed to get OCR2 keys: %w", err) } @@ -589,8 +589,8 @@ func getNodeOCR2Config(client cmd.HTTPClient) (*cmd.OCR2KeyBundlePresenter, erro } // getP2PKeyID returns chainlink node's P2P key ID -func getP2PKeyID(client cmd.HTTPClient) (string, error) { - resp, err := nodeRequest(client, p2pKeysEndpoint) +func getP2PKeyID(ctx context.Context, client cmd.HTTPClient) (string, error) { + resp, err := nodeRequest(ctx, client, p2pKeysEndpoint) if err != nil { return "", fmt.Errorf("failed to get P2P keys: %w", err) } diff --git a/core/scripts/chaincli/handler/jobs.go b/core/scripts/chaincli/handler/jobs.go index 9787d7fc175..89f1a3ea5bc 100644 --- a/core/scripts/chaincli/handler/jobs.go +++ b/core/scripts/chaincli/handler/jobs.go @@ -8,10 +8,10 @@ import ( ) func (k *Keeper) CreateJob(ctx context.Context) { - k.createJobs() + k.createJobs(ctx) } -func (k *Keeper) createJobs() { +func (k *Keeper) createJobs(ctx context.Context) { lggr, closeLggr := logger.NewLogger() logger.Sugared(lggr).ErrorIfFn(closeLggr, "Failed to close logger") @@ -27,12 +27,12 @@ func (k *Keeper) createJobs() { pwd = defaultChainlinkNodePassword } - cl, err := authenticate(url, email, pwd, lggr) + cl, err := authenticate(ctx, url, email, pwd, lggr) if err != nil { log.Fatal(err) } - if err = k.createKeeperJob(cl, k.cfg.RegistryAddress, keeperAddr); err != nil { + if err = k.createKeeperJob(ctx, cl, k.cfg.RegistryAddress, keeperAddr); err != nil { log.Fatal(err) } } diff --git a/core/scripts/chaincli/handler/keeper.go b/core/scripts/chaincli/handler/keeper.go index 439532430ab..1f56eb14080 100644 --- a/core/scripts/chaincli/handler/keeper.go +++ b/core/scripts/chaincli/handler/keeper.go @@ -77,13 +77,13 @@ func (k *Keeper) DeployKeepers(ctx context.Context) { pwd = defaultChainlinkNodePassword } - cl, err := authenticate(url, email, pwd, lggr) + cl, err := authenticate(ctx, url, email, pwd, lggr) if err != nil { log.Fatal(err) } cls[i] = cl - if err = k.createKeeperJob(cl, k.cfg.RegistryAddress, keeperAddr); err != nil { + if err = k.createKeeperJob(ctx, cl, k.cfg.RegistryAddress, keeperAddr); err != nil { log.Fatal(err) } } @@ -435,9 +435,8 @@ func (k *Keeper) getRegistry20(ctx context.Context) (common.Address, *registry20 } if k.cfg.RegistryConfigUpdate { panic("KeeperRegistry2.0 could not be updated") - } else { - log.Println("KeeperRegistry2.0 config not updated: KEEPER_CONFIG_UPDATE=false") } + log.Println("KeeperRegistry2.0 config not updated: KEEPER_CONFIG_UPDATE=false") return registryAddr, keeperRegistry20 } @@ -453,9 +452,8 @@ func (k *Keeper) getRegistry21(ctx context.Context) (common.Address, *iregistry2 } if k.cfg.RegistryConfigUpdate { panic("KeeperRegistry2.1 could not be updated") - } else { - log.Println("KeeperRegistry2.1 config not updated: KEEPER_CONFIG_UPDATE=false") } + log.Println("KeeperRegistry2.1 config not updated: KEEPER_CONFIG_UPDATE=false") return registryAddr, keeperRegistry21 } @@ -479,9 +477,8 @@ func (k *Keeper) getRegistry12(ctx context.Context) (common.Address, *registry12 log.Fatalf("KeeperRegistry config update failed on registry address: %s, error is: %s", k.cfg.RegistryAddress, err.Error()) } log.Println("KeeperRegistry config update:", k.cfg.RegistryAddress, "-", helpers.ExplorerLink(k.cfg.ChainID, transaction.Hash())) - } else { - log.Println("KeeperRegistry config not updated: KEEPER_CONFIG_UPDATE=false") } + log.Println("KeeperRegistry config not updated: KEEPER_CONFIG_UPDATE=false") return registryAddr, keeperRegistry12 } @@ -513,9 +510,8 @@ func (k *Keeper) getRegistry11(ctx context.Context) (common.Address, *registry11 log.Fatalf("KeeperRegistry config update failed on registry address: %s, error is %s", k.cfg.RegistryAddress, err.Error()) } log.Println("KeeperRegistry config update:", k.cfg.RegistryAddress, "-", helpers.ExplorerLink(k.cfg.ChainID, transaction.Hash())) - } else { - log.Println("KeeperRegistry config not updated: KEEPER_CONFIG_UPDATE=false") } + log.Println("KeeperRegistry config not updated: KEEPER_CONFIG_UPDATE=false") return registryAddr, keeperRegistry11 } @@ -532,13 +528,11 @@ func (k *Keeper) deployUpkeeps(ctx context.Context, registryAddr common.Address, var registerUpkeepTx *types.Transaction var logUpkeepCounter *log_upkeep_counter_wrapper.LogUpkeepCounter var checkData []byte - var err error + switch k.cfg.UpkeepType { case config.Conditional: checkData = []byte(k.cfg.UpkeepCheckData) - if err != nil { - log.Fatal(err) - } + var err error if k.cfg.UpkeepAverageEligibilityCadence > 0 { upkeepAddr, deployUpkeepTx, _, err = upkeep.DeployUpkeepPerformCounterRestrictive( k.buildTxOpts(ctx), @@ -574,9 +568,7 @@ func (k *Keeper) deployUpkeeps(ctx context.Context, registryAddr common.Address, } case config.Mercury: checkData = []byte(k.cfg.UpkeepCheckData) - if err != nil { - log.Fatal(err) - } + var err error if k.cfg.VerifiableLoadTest { upkeepAddr, deployUpkeepTx, _, err = verifiable_load_streams_lookup_upkeep_wrapper.DeployVerifiableLoadStreamsLookupUpkeep( k.buildTxOpts(ctx), @@ -607,6 +599,7 @@ func (k *Keeper) deployUpkeeps(ctx context.Context, registryAddr common.Address, log.Fatal(i, upkeepAddr.Hex(), ": RegisterUpkeep failed - ", err) } case config.LogTrigger: + var err error upkeepAddr, deployUpkeepTx, logUpkeepCounter, err = log_upkeep_counter_wrapper.DeployLogUpkeepCounter( k.buildTxOpts(ctx), k.client, @@ -641,7 +634,7 @@ func (k *Keeper) deployUpkeeps(ctx context.Context, registryAddr common.Address, if err != nil { log.Fatal("failed to start log upkeep counter", err) } - if err := k.waitTx(ctx, logUpkeepStartTx); err != nil { + if err = k.waitTx(ctx, logUpkeepStartTx); err != nil { log.Fatalf("Log upkeep Start() failed for upkeepId: %s, error is %s", upkeepAddr.Hex(), err.Error()) } log.Println(i, upkeepAddr.Hex(), ": Log upkeep successfully started - ", helpers.ExplorerLink(k.cfg.ChainID, logUpkeepStartTx.Hash())) @@ -657,32 +650,34 @@ func (k *Keeper) deployUpkeeps(ctx context.Context, registryAddr common.Address, upkeepAddrs = append(upkeepAddrs, upkeepAddr) } - var err error var upkeepGetter activeUpkeepGetter upkeepCount := big.NewInt(k.cfg.UpkeepCount) // second arg in GetActiveUpkeepIds (on registry) - switch k.cfg.RegistryVersion { - case keeper.RegistryVersion_1_1: - panic("not supported 1.1 registry") - case keeper.RegistryVersion_1_2: - upkeepGetter, err = registry12.NewKeeperRegistry( - registryAddr, - k.client, - ) - case keeper.RegistryVersion_2_0: - upkeepGetter, err = registry20.NewKeeperRegistry( - registryAddr, - k.client, - ) - case keeper.RegistryVersion_2_1: - upkeepGetter, err = iregistry21.NewIKeeperRegistryMaster( - registryAddr, - k.client, - ) - default: - panic("unexpected registry address") - } - if err != nil { - log.Fatal("Registry failed: ", err) + { + var err error + switch k.cfg.RegistryVersion { + case keeper.RegistryVersion_1_1: + panic("not supported 1.1 registry") + case keeper.RegistryVersion_1_2: + upkeepGetter, err = registry12.NewKeeperRegistry( + registryAddr, + k.client, + ) + case keeper.RegistryVersion_2_0: + upkeepGetter, err = registry20.NewKeeperRegistry( + registryAddr, + k.client, + ) + case keeper.RegistryVersion_2_1: + upkeepGetter, err = iregistry21.NewIKeeperRegistryMaster( + registryAddr, + k.client, + ) + default: + panic("unexpected registry address") + } + if err != nil { + log.Fatal("Registry failed: ", err) + } } activeUpkeepIds := k.getActiveUpkeepIds(ctx, upkeepGetter, big.NewInt(existingCount), upkeepCount) @@ -728,22 +723,24 @@ func (k *Keeper) deployUpkeeps(ctx context.Context, registryAddr common.Address, } for _, id := range activeUpkeepIds { - tx, err := reg21.SetUpkeepPrivilegeConfig(k.buildTxOpts(ctx), id, adminBytes) - if err != nil { - log.Fatalf("failed to upkeep privilege config: %v", err) + tx, err2 := reg21.SetUpkeepPrivilegeConfig(k.buildTxOpts(ctx), id, adminBytes) + if err2 != nil { + log.Fatalf("failed to upkeep privilege config: %v", err2) } - err = k.waitTx(ctx, tx) - if err != nil { - log.Fatalf("failed to wait for tx: %v", err) - } else { - log.Printf("upkeep privilege config is set for %s", id.String()) + err2 = k.waitTx(ctx, tx) + if err2 != nil { + log.Fatalf("failed to wait for tx: %v", err2) } + log.Printf("upkeep privilege config is set for %s", id.String()) - info, err := reg21.GetUpkeep(nil, id) - if err != nil { - log.Fatalf("failed to fetch upkeep id %s from registry 2.1: %v", id, err) + info, err2 := reg21.GetUpkeep(nil, id) + if err2 != nil { + log.Fatalf("failed to fetch upkeep id %s from registry 2.1: %v", id, err2) + } + min, err2 := reg21.GetMinBalanceForUpkeep(nil, id) + if err2 != nil { + log.Fatalf("failed to fetch upkeep id %s from registry 2.1: %v", id, err2) } - min, err := reg21.GetMinBalanceForUpkeep(nil, id) log.Printf(" Balance: %s", info.Balance) log.Printf("Min Balance: %s", min.String()) } @@ -756,12 +753,13 @@ func (k *Keeper) deployUpkeeps(ctx context.Context, registryAddr common.Address, func (k *Keeper) setKeepers(ctx context.Context, cls []cmd.HTTPClient, deployer keepersDeployer, keepers, owners []common.Address) { if len(keepers) > 0 { log.Println("Set keepers...") - setKeepersTx, err := deployer.SetKeepers(k.buildTxOpts(ctx), cls, keepers, owners) + opts := k.buildTxOpts(ctx) + setKeepersTx, err := deployer.SetKeepers(ctx, opts, cls, keepers, owners) if err != nil { log.Fatal("SetKeepers failed: ", err) } - if err := k.waitTx(ctx, setKeepersTx); err != nil { + if err = k.waitTx(ctx, setKeepersTx); err != nil { log.Fatalf("SetKeepers failed, error is: %s", err.Error()) } @@ -781,24 +779,6 @@ func (k *Keeper) keepers() ([]common.Address, []common.Address) { return addrs, fromAddrs } -// createKeeperJobOnExistingNode connect to existing node to create keeper job -func (k *Keeper) createKeeperJobOnExistingNode(urlStr, email, password, registryAddr, nodeAddr string) error { - lggr, closeLggr := logger.NewLogger() - logger.Sugared(lggr).ErrorIfFn(closeLggr, "Failed to close logger") - - cl, err := authenticate(urlStr, email, password, lggr) - if err != nil { - return err - } - - if err = k.createKeeperJob(cl, registryAddr, nodeAddr); err != nil { - log.Println("Failed to create keeper job: ", err) - return err - } - - return nil -} - type activeUpkeepGetter interface { Address() common.Address GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) diff --git a/core/scripts/chaincli/handler/keeper_deployer.go b/core/scripts/chaincli/handler/keeper_deployer.go index 7c532753426..118cbbb0ff9 100644 --- a/core/scripts/chaincli/handler/keeper_deployer.go +++ b/core/scripts/chaincli/handler/keeper_deployer.go @@ -1,6 +1,7 @@ package handler import ( + "context" "crypto/ed25519" "encoding/hex" "encoding/json" @@ -48,14 +49,14 @@ type upkeepDeployer interface { type keepersDeployer interface { canceller upkeepDeployer - SetKeepers(opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) + SetKeepers(ctx context.Context, opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) } type v11KeeperDeployer struct { registry11.KeeperRegistryInterface } -func (d *v11KeeperDeployer) SetKeepers(opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) { +func (d *v11KeeperDeployer) SetKeepers(ctx context.Context, opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) { return d.KeeperRegistryInterface.SetKeepers(opts, keepers, payees) } @@ -71,7 +72,7 @@ type v12KeeperDeployer struct { registry12.KeeperRegistryInterface } -func (d *v12KeeperDeployer) SetKeepers(opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) { +func (d *v12KeeperDeployer) SetKeepers(ctx context.Context, opts *bind.TransactOpts, _ []cmd.HTTPClient, keepers []common.Address, payees []common.Address) (*types.Transaction, error) { return d.KeeperRegistryInterface.SetKeepers(opts, keepers, payees) } @@ -88,7 +89,7 @@ type v20KeeperDeployer struct { cfg *config.Config } -func (d *v20KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPClient, keepers []common.Address, _ []common.Address) (*types.Transaction, error) { +func (d *v20KeeperDeployer) SetKeepers(ctx context.Context, opts *bind.TransactOpts, cls []cmd.HTTPClient, keepers []common.Address, _ []common.Address) (*types.Transaction, error) { S := make([]int, len(cls)) oracleIdentities := make([]ocr2config.OracleIdentityExtra, len(cls)) sharedSecretEncryptionPublicKeys := make([]ocr2types.ConfigEncryptionPublicKey, len(cls)) @@ -98,12 +99,12 @@ func (d *v20KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPCl go func(i int, cl cmd.HTTPClient) { defer wg.Done() - ocr2Config, err := getNodeOCR2Config(cl) + ocr2Config, err := getNodeOCR2Config(ctx, cl) if err != nil { panic(err) } - p2pKeyID, err := getP2PKeyID(cl) + p2pKeyID, err := getP2PKeyID(ctx, cl) if err != nil { panic(err) } @@ -228,7 +229,7 @@ type v21KeeperDeployer struct { cfg *config.Config } -func (d *v21KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPClient, keepers []common.Address, _ []common.Address) (*types.Transaction, error) { +func (d *v21KeeperDeployer) SetKeepers(ctx context.Context, opts *bind.TransactOpts, cls []cmd.HTTPClient, keepers []common.Address, _ []common.Address) (*types.Transaction, error) { S := make([]int, len(cls)) oracleIdentities := make([]ocr2config.OracleIdentityExtra, len(cls)) sharedSecretEncryptionPublicKeys := make([]ocr2types.ConfigEncryptionPublicKey, len(cls)) @@ -238,12 +239,12 @@ func (d *v21KeeperDeployer) SetKeepers(opts *bind.TransactOpts, cls []cmd.HTTPCl go func(i int, cl cmd.HTTPClient) { defer wg.Done() - ocr2Config, err := getNodeOCR2Config(cl) + ocr2Config, err := getNodeOCR2Config(ctx, cl) if err != nil { panic(err) } - p2pKeyID, err := getP2PKeyID(cl) + p2pKeyID, err := getP2PKeyID(ctx, cl) if err != nil { panic(err) } diff --git a/core/scripts/chaincli/handler/keeper_launch.go b/core/scripts/chaincli/handler/keeper_launch.go index 83ee6a77129..1db3884ae4e 100644 --- a/core/scripts/chaincli/handler/keeper_launch.go +++ b/core/scripts/chaincli/handler/keeper_launch.go @@ -18,6 +18,8 @@ import ( ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink/v2/core/cmd" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" registry12 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_2" @@ -91,7 +93,7 @@ func (k *Keeper) LaunchAndTest(ctx context.Context, withdraw, printLogs, force, // Create authenticated client var cl cmd.HTTPClient var err error - cl, err = authenticate(startedNode.url, defaultChainlinkNodeLogin, defaultChainlinkNodePassword, lggr) + cl, err = authenticate(ctx, startedNode.url, defaultChainlinkNodeLogin, defaultChainlinkNodePassword, lggr) if err != nil { log.Fatal("Authentication failed, ", err) } @@ -100,15 +102,13 @@ func (k *Keeper) LaunchAndTest(ctx context.Context, withdraw, printLogs, force, if len(k.cfg.KeeperKeys) > 0 { // import key if exists - var err error - nodeAddrHex, err = k.addKeyToKeeper(cl, k.cfg.KeeperKeys[i]) + nodeAddrHex, err = k.addKeyToKeeper(ctx, cl, k.cfg.KeeperKeys[i]) if err != nil { log.Fatal("could not add key to keeper", err) } } else { // get node's default wallet address - var err error - nodeAddrHex, err = getNodeAddress(cl) + nodeAddrHex, err = getNodeAddress(ctx, cl) if err != nil { log.Println("Failed to get node addr: ", err) continue @@ -118,7 +118,7 @@ func (k *Keeper) LaunchAndTest(ctx context.Context, withdraw, printLogs, force, nodeAddr := common.HexToAddress(nodeAddrHex) // Create keepers - if err = k.createKeeperJob(cl, registryAddr.Hex(), nodeAddr.Hex()); err != nil { + if err = k.createKeeperJob(ctx, cl, registryAddr.Hex(), nodeAddr.Hex()); err != nil { log.Println("Failed to create keeper job: ", err) continue } @@ -220,35 +220,35 @@ func (k *Keeper) LaunchAndTest(ctx context.Context, withdraw, printLogs, force, // cancelAndWithdrawActiveUpkeeps cancels all active upkeeps and withdraws funds for registry 1.2 func (k *Keeper) cancelAndWithdrawActiveUpkeeps(ctx context.Context, activeUpkeepIds []*big.Int, canceller canceller) error { - var err error for i := 0; i < len(activeUpkeepIds); i++ { - var tx *ethtypes.Transaction upkeepId := activeUpkeepIds[i] - if tx, err = canceller.CancelUpkeep(k.buildTxOpts(ctx), upkeepId); err != nil { + tx, err := canceller.CancelUpkeep(k.buildTxOpts(ctx), upkeepId) + if err != nil { return fmt.Errorf("failed to cancel upkeep %s: %s", upkeepId.String(), err) } - if err := k.waitTx(ctx, tx); err != nil { + if err = k.waitTx(ctx, tx); err != nil { log.Fatalf("failed to cancel upkeep for upkeepId: %s, error is: %s", upkeepId.String(), err.Error()) } - if tx, err = canceller.WithdrawFunds(k.buildTxOpts(ctx), upkeepId, k.fromAddr); err != nil { + tx, err = canceller.WithdrawFunds(k.buildTxOpts(ctx), upkeepId, k.fromAddr) + if err != nil { return fmt.Errorf("failed to withdraw upkeep %s: %s", upkeepId.String(), err) } - if err := k.waitTx(ctx, tx); err != nil { + if err = k.waitTx(ctx, tx); err != nil { log.Fatalf("failed to withdraw upkeep for upkeepId: %s, error is: %s", upkeepId.String(), err.Error()) } log.Printf("Upkeep %s successfully canceled and refunded: ", upkeepId.String()) } - var tx *ethtypes.Transaction - if tx, err = canceller.RecoverFunds(k.buildTxOpts(ctx)); err != nil { + tx, err := canceller.RecoverFunds(k.buildTxOpts(ctx)) + if err != nil { return fmt.Errorf("failed to recover funds: %s", err) } - if err := k.waitTx(ctx, tx); err != nil { + if err = k.waitTx(ctx, tx); err != nil { log.Fatalf("failed to recover funds, error is: %s", err.Error()) } @@ -264,7 +264,7 @@ func (k *Keeper) cancelAndWithdrawUpkeeps(ctx context.Context, upkeepCount *big. return fmt.Errorf("failed to cancel upkeep %d: %s", i, err) } - if err := k.waitTx(ctx, tx); err != nil { + if err = k.waitTx(ctx, tx); err != nil { log.Fatalf("failed to cancel upkeep, error is: %s", err.Error()) } @@ -272,7 +272,7 @@ func (k *Keeper) cancelAndWithdrawUpkeeps(ctx context.Context, upkeepCount *big. return fmt.Errorf("failed to withdraw upkeep %d: %s", i, err) } - if err := k.waitTx(ctx, tx); err != nil { + if err = k.waitTx(ctx, tx); err != nil { log.Fatalf("failed to withdraw upkeep, error is: %s", err.Error()) } @@ -284,7 +284,7 @@ func (k *Keeper) cancelAndWithdrawUpkeeps(ctx context.Context, upkeepCount *big. return fmt.Errorf("failed to recover funds: %s", err) } - if err := k.waitTx(ctx, tx); err != nil { + if err = k.waitTx(ctx, tx); err != nil { log.Fatalf("failed to recover funds, error is: %s", err.Error()) } @@ -292,12 +292,12 @@ func (k *Keeper) cancelAndWithdrawUpkeeps(ctx context.Context, upkeepCount *big. } // createKeeperJob creates a keeper job in the chainlink node by the given address -func (k *Keeper) createKeeperJob(client cmd.HTTPClient, registryAddr, nodeAddr string) error { +func (k *Keeper) createKeeperJob(ctx context.Context, client cmd.HTTPClient, registryAddr, nodeAddr string) error { var err error if k.cfg.OCR2Keepers { - err = k.createOCR2KeeperJob(client, registryAddr, nodeAddr) + err = k.createOCR2KeeperJob(ctx, client, registryAddr, nodeAddr) } else { - err = k.createLegacyKeeperJob(client, registryAddr, nodeAddr) + err = k.createLegacyKeeperJob(ctx, client, registryAddr, nodeAddr) } if err != nil { return err @@ -309,7 +309,7 @@ func (k *Keeper) createKeeperJob(client cmd.HTTPClient, registryAddr, nodeAddr s } // createLegacyKeeperJob creates a legacy keeper job in the chainlink node by the given address -func (k *Keeper) createLegacyKeeperJob(client cmd.HTTPClient, registryAddr, nodeAddr string) error { +func (k *Keeper) createLegacyKeeperJob(ctx context.Context, client cmd.HTTPClient, registryAddr, nodeAddr string) error { request, err := json.Marshal(web.CreateJobRequest{ TOML: testspecs.GenerateKeeperSpec(testspecs.KeeperSpecParams{ Name: fmt.Sprintf("keeper job - registry %s", registryAddr), @@ -322,7 +322,7 @@ func (k *Keeper) createLegacyKeeperJob(client cmd.HTTPClient, registryAddr, node return fmt.Errorf("failed to marshal request: %s", err) } - resp, err := client.Post("/v2/jobs", bytes.NewReader(request)) + resp, err := client.Post(ctx, "/v2/jobs", bytes.NewReader(request)) if err != nil { return fmt.Errorf("failed to create keeper job: %s", err) } @@ -364,34 +364,34 @@ contractVersion = "%s" mercuryCredentialName = "%s"` // createOCR2KeeperJob creates an ocr2keeper job in the chainlink node by the given address -func (k *Keeper) createOCR2KeeperJob(client cmd.HTTPClient, contractAddr, nodeAddr string) error { - ocr2KeyConfig, err := getNodeOCR2Config(client) +func (k *Keeper) createOCR2KeeperJob(ctx context.Context, client cmd.HTTPClient, contractAddr, nodeAddr string) error { + ocr2KeyConfig, err := getNodeOCR2Config(ctx, client) if err != nil { return fmt.Errorf("failed to get node OCR2 key bundle ID: %s", err) } // Correctly assign contract version in OCR job spec. - var contractVersion string = "v2.0" + contractVersion := "v2.0" if k.cfg.RegistryVersion == keeper.RegistryVersion_2_1 { contractVersion = "v2.1" } request, err := json.Marshal(web.CreateJobRequest{ TOML: fmt.Sprintf(ocr2keeperJobTemplate, - contractAddr, // contractID - ocr2KeyConfig.ID, // ocrKeyBundleID - nodeAddr, // transmitterID - node wallet address - k.cfg.BootstrapNodeAddr, // bootstrap node key and address - k.cfg.ChainID, // chainID - contractVersion, // contractVersion - k.cfg.MercuryCredName, // mercury credential name + contractAddr, // contractID + ocr2KeyConfig.ID, // ocrKeyBundleID + nodeAddr, // transmitterID - node wallet address + k.cfg.BootstrapNodeAddr, // bootstrap node key and address + k.cfg.ChainID, // chainID + contractVersion, // contractVersion + k.cfg.DataStreamsCredName, // mercury credential name ), }) if err != nil { return fmt.Errorf("failed to marshal request: %s", err) } - resp, err := client.Post("/v2/jobs", bytes.NewReader(request)) + resp, err := client.Post(ctx, "/v2/jobs", bytes.NewReader(request)) if err != nil { return fmt.Errorf("failed to create ocr2keeper job: %s", err) } @@ -410,8 +410,8 @@ func (k *Keeper) createOCR2KeeperJob(client cmd.HTTPClient, contractAddr, nodeAd } // addKeyToKeeper imports the provided ETH sending key to the keeper -func (k *Keeper) addKeyToKeeper(client cmd.HTTPClient, privKeyHex string) (string, error) { - privkey, err := crypto.HexToECDSA(utils.RemoveHexPrefix(privKeyHex)) +func (k *Keeper) addKeyToKeeper(ctx context.Context, client cmd.HTTPClient, privKeyHex string) (string, error) { + privkey, err := crypto.HexToECDSA(hex.TrimPrefix(privKeyHex)) if err != nil { log.Fatalf("Failed to decode priv key %s: %v", privKeyHex, err) } @@ -430,7 +430,7 @@ func (k *Keeper) addKeyToKeeper(client cmd.HTTPClient, privKeyHex string) (strin query.Set("evmChainID", fmt.Sprint(k.cfg.ChainID)) importUrl.RawQuery = query.Encode() - resp, err := client.Post(importUrl.String(), bytes.NewReader(keyJSON)) + resp, err := client.Post(ctx, importUrl.String(), bytes.NewReader(keyJSON)) if err != nil { log.Fatalf("Failed to import priv key %s: %v", privKeyHex, err) } diff --git a/core/scripts/chaincli/handler/keeper_verifiable_load.go b/core/scripts/chaincli/handler/keeper_verifiable_load.go index b71a9af3387..aa62d820101 100644 --- a/core/scripts/chaincli/handler/keeper_verifiable_load.go +++ b/core/scripts/chaincli/handler/keeper_verifiable_load.go @@ -58,7 +58,7 @@ type upkeepStats struct { SortedAllDelays []float64 } -func (k *Keeper) GetVerifiableLoadStats(ctx context.Context, csv bool) { +func (k *Keeper) PrintVerifiableLoadStats(ctx context.Context, csv bool) { var v verifiableLoad var err error addr := common.HexToAddress(k.cfg.VerifiableLoadContractAddress) @@ -99,7 +99,7 @@ func (k *Keeper) GetVerifiableLoadStats(ctx context.Context, csv bool) { // create a number of workers to process the upkeep ids in batch for i := 0; i < workerNum; i++ { wg.Add(1) - go k.getUpkeepInfo(idChan, resultsChan, v, opts, &wg, csv) + go k.fetchUpkeepInfo(idChan, resultsChan, v, opts, &wg, csv) } for _, id := range upkeepIds { @@ -134,7 +134,7 @@ func (k *Keeper) GetVerifiableLoadStats(ctx context.Context, csv bool) { log.Printf("All STATS ABOVE ARE CALCULATED AT BLOCK %d", blockNum) } -func (k *Keeper) getUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInfo, v verifiableLoad, opts *bind.CallOpts, wg *sync.WaitGroup, csv bool) { +func (k *Keeper) fetchUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInfo, v verifiableLoad, opts *bind.CallOpts, wg *sync.WaitGroup, csv bool) { defer wg.Done() for id := range idChan { @@ -161,7 +161,7 @@ func (k *Keeper) getUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInf var wg1 sync.WaitGroup for i := uint16(0); i <= b; i++ { wg1.Add(1) - go k.getBucketData(v, opts, id, i, &wg1, info) + go k.fetchBucketData(v, opts, id, i, &wg1, info) } wg1.Wait() @@ -196,7 +196,7 @@ func (k *Keeper) getUpkeepInfo(idChan chan *big.Int, resultsChan chan *upkeepInf } } -func (k *Keeper) getBucketData(v verifiableLoad, opts *bind.CallOpts, id *big.Int, bucketNum uint16, wg *sync.WaitGroup, info *upkeepInfo) { +func (k *Keeper) fetchBucketData(v verifiableLoad, opts *bind.CallOpts, id *big.Int, bucketNum uint16, wg *sync.WaitGroup, info *upkeepInfo) { defer wg.Done() var bucketDelays []*big.Int diff --git a/core/scripts/chaincli/handler/ocr2_config.go b/core/scripts/chaincli/handler/ocr2_config.go index 21b2ad414a3..caa96112ea8 100644 --- a/core/scripts/chaincli/handler/ocr2_config.go +++ b/core/scripts/chaincli/handler/ocr2_config.go @@ -54,7 +54,7 @@ func OCR2GetConfig(hdlr *baseHandler, registry_addr string) error { func configFromBlock(bl *types.Block, addr common.Address, detail keeper_registry_wrapper2_0.LatestConfigDetails) (*confighelper.PublicConfig, error) { for _, tx := range bl.Transactions() { - if tx.To() != nil && bytes.Compare(tx.To()[:], addr[:]) == 0 { + if tx.To() != nil && bytes.Equal(tx.To()[:], addr[:]) { // this is our transaction // txRes, txErr, err := getTransactionDetailForHashes(hdlr, []string{tx}) ocr2Tx, err := NewBaseOCR2Tx(tx) diff --git a/core/scripts/chaincli/handler/report.go b/core/scripts/chaincli/handler/report.go index 622963f1ac0..1dcbb21ee83 100644 --- a/core/scripts/chaincli/handler/report.go +++ b/core/scripts/chaincli/handler/report.go @@ -85,24 +85,26 @@ func OCR2AutomationReports(hdlr *baseHandler, txs []string) error { } txRes, txErr, err = getSimulationsForTxs(hdlr, simBatch) + if err != nil { + return err + } for i := range txRes { if txErr[i] == nil { continue } - err, ok := txErr[i].(JsonError) + err2, ok := txErr[i].(JsonError) //nolint:errorlint if ok { - decoded, err := hexutil.Decode(err.ErrorData().(string)) + decoded, err := hexutil.Decode(err2.ErrorData().(string)) if err != nil { elements[i].Err = err.Error() continue } elements[i].Err = ocr2Txs[i].DecodeError(decoded) - } else if err != nil { - elements[i].Err = err.Error() + } else if err2 != nil { + elements[i].Err = err2.Error() } - } data := make([][]string, len(elements)) @@ -235,15 +237,12 @@ func (t *OCR2Transaction) BlockNumber() (uint64, error) { block, err := hexutil.DecodeUint64(blStr) if err != nil { return 0, fmt.Errorf("failed to parse block number: %s", err) - } else { - return block, nil } - } else { - return 0, fmt.Errorf("not a string") + return block, nil } - } else { - return 0, fmt.Errorf("not found") + return 0, fmt.Errorf("not a string") } + return 0, fmt.Errorf("not found") } func (t *OCR2Transaction) To() *common.Address { @@ -278,7 +277,7 @@ func (t *OCR2Transaction) DecodeError(b []byte) string { } } - return fmt.Sprintf("%s", j) + return j } func NewOCR2TransmitTx(raw map[string]interface{}) (*OCR2TransmitTx, error) { @@ -335,17 +334,15 @@ func (t *OCR2TransmitTx) SetStaticValues(elem *OCR2ReportDataElem) { if err != nil { elem.Err = err.Error() return - } else { - elem.From = from.String() } + elem.From = from.String() block, err := t.BlockNumber() if err != nil { elem.Err = err.Error() return - } else { - elem.BlockNumber = fmt.Sprintf("%d", block) } + elem.BlockNumber = fmt.Sprintf("%d", block) upkeeps, err := t.UpkeepsInTransmit() if err != nil { diff --git a/core/scripts/chaincli/handler/scrape_node_config.go b/core/scripts/chaincli/handler/scrape_node_config.go index f00beb4b4fe..6525a4794d0 100644 --- a/core/scripts/chaincli/handler/scrape_node_config.go +++ b/core/scripts/chaincli/handler/scrape_node_config.go @@ -114,7 +114,7 @@ func (h *baseHandler) scrapeNodes(ctx context.Context, log logger.Logger) { pwd = defaultChainlinkNodePassword } - cl, err := authenticate(url, email, pwd, log) + cl, err := authenticate(ctx, url, email, pwd, log) if err != nil { log.Fatal(err) } @@ -125,7 +125,7 @@ func (h *baseHandler) scrapeNodes(ctx context.Context, log logger.Logger) { var wg sync.WaitGroup for i, cl := range cls { wg.Add(1) - go h.scrapeNodeInfo(&wg, i, cl, nodes, log) + go h.scrapeNodeInfo(ctx, &wg, i, cl, nodes, log) } wg.Wait() @@ -184,8 +184,8 @@ func (h *baseHandler) fetchNodeInfosFromWeiwatchers(ctx context.Context, log log return nodeInfos } -func (h *baseHandler) fetchNodeInfosFromNodes(i int, cl cmd.HTTPClient, log logger.Logger) ([]string, *cmd.OCR2KeyBundlePresenter, string, *cmd.CSAKeyPresenters) { - resp, err := nodeRequest(cl, ethKeysEndpoint) +func (h *baseHandler) fetchNodeInfosFromNodes(ctx context.Context, i int, cl cmd.HTTPClient, log logger.Logger) ([]string, *cmd.OCR2KeyBundlePresenter, string, *cmd.CSAKeyPresenters) { + resp, err := nodeRequest(ctx, cl, ethKeysEndpoint) if err != nil { log.Fatalf("failed to get ETH keys: %s", err) } @@ -204,17 +204,17 @@ func (h *baseHandler) fetchNodeInfosFromNodes(i int, cl cmd.HTTPClient, log logg log.Warnf("%d th node has more than 1 node addresses. is this a multi-chain node? or this node used to serve another chain?", i) } - ocr2Config, err := getNodeOCR2Config(cl) + ocr2Config, err := getNodeOCR2Config(ctx, cl) if err != nil { log.Fatalf("failed to get node OCR2 config: %s", err) } - peerId, err := getP2PKeyID(cl) + peerId, err := getP2PKeyID(ctx, cl) if err != nil { log.Fatalf("failed to get p2p keys: %s", err) } - resp, err = nodeRequest(cl, csaKeysEndpoint) + resp, err = nodeRequest(ctx, cl, csaKeysEndpoint) if err != nil { log.Fatalf("failed to get CSA keys: %s", err) } @@ -232,10 +232,10 @@ func (h *baseHandler) fetchNodeInfosFromNodes(i int, cl cmd.HTTPClient, log logg return nodeAddresses, ocr2Config, peerId, &csaKeys } -func (h *baseHandler) scrapeNodeInfo(wg *sync.WaitGroup, i int, cl cmd.HTTPClient, nodes map[string]*NodeInfo, log logger.Logger) { +func (h *baseHandler) scrapeNodeInfo(ctx context.Context, wg *sync.WaitGroup, i int, cl cmd.HTTPClient, nodes map[string]*NodeInfo, log logger.Logger) { defer wg.Done() - nodeAddresses, ocr2Config, peerId, csaKeys := h.fetchNodeInfosFromNodes(i, cl, log) + nodeAddresses, ocr2Config, peerId, csaKeys := h.fetchNodeInfosFromNodes(ctx, i, cl, log) // this assumes the nodes are not multichain nodes and have only 1 node address assigned. // for a multichain node, we can pass in a chain id and filter `ethKeys` array based on the chain id @@ -279,5 +279,5 @@ func writeJSON(data interface{}, path string) error { return err } - return os.WriteFile(path, dataBytes, 0644) + return os.WriteFile(path, dataBytes, 0644) //nolint:gosec } diff --git a/core/scripts/common/avalanche.go b/core/scripts/common/avalanche.go new file mode 100644 index 00000000000..8699463c365 --- /dev/null +++ b/core/scripts/common/avalanche.go @@ -0,0 +1,265 @@ +package common + +import ( + "encoding/binary" + "encoding/json" + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" +) + +const ( + // BloomByteLength represents the number of bytes used in a header log bloom. + BloomByteLength = 256 + + // BloomBitLength represents the number of bits used in a header log bloom. + BloomBitLength = 8 * BloomByteLength +) + +// AvaBloom represents a 2048 bit bloom filter. +type AvaBloom [BloomByteLength]byte + +// SetBytes sets the content of b to the given bytes. +// It panics if d is not of suitable size. +func (b *AvaBloom) SetBytes(d []byte) { + if len(b) < len(d) { + panic(fmt.Sprintf("bloom bytes too big %d %d", len(b), len(d))) + } + copy(b[BloomByteLength-len(d):], d) +} + +// Add adds d to the filter. Future calls of Test(d) will return true. +func (b *AvaBloom) Add(d []byte) { + b.add(d, make([]byte, 6)) +} + +// add is internal version of Add, which takes a scratch buffer for reuse (needs to be at least 6 bytes) +func (b *AvaBloom) add(d []byte, buf []byte) { + i1, v1, i2, v2, i3, v3 := bloomValues(d, buf) + b[i1] |= v1 + b[i2] |= v2 + b[i3] |= v3 +} + +// Big converts b to a big integer. +// Note: Converting a bloom filter to a big.Int and then calling GetBytes +// does not return the same bytes, since big.Int will trim leading zeroes +func (b AvaBloom) Big() *big.Int { + return new(big.Int).SetBytes(b[:]) +} + +// Bytes returns the backing byte slice of the bloom +func (b AvaBloom) Bytes() []byte { + return b[:] +} + +// Test checks if the given topic is present in the bloom filter +func (b AvaBloom) Test(topic []byte) bool { + i1, v1, i2, v2, i3, v3 := bloomValues(topic, make([]byte, 6)) + return v1 == v1&b[i1] && + v2 == v2&b[i2] && + v3 == v3&b[i3] +} + +// MarshalText encodes b as a hex string with 0x prefix. +func (b AvaBloom) MarshalText() ([]byte, error) { + return hexutil.Bytes(b[:]).MarshalText() +} + +// UnmarshalText b as a hex string with 0x prefix. +func (b *AvaBloom) UnmarshalText(input []byte) error { + return hexutil.UnmarshalFixedText("Bloom", input, b[:]) +} + +// bloomValues returns the bytes (index-value pairs) to set for the given data +func bloomValues(data []byte, hashbuf []byte) (uint, byte, uint, byte, uint, byte) { + sha := crypto.NewKeccakState() + sha.Write(data) //nolint:errcheck + sha.Read(hashbuf) //nolint:errcheck + // The actual bits to flip + v1 := byte(1 << (hashbuf[1] & 0x7)) + v2 := byte(1 << (hashbuf[3] & 0x7)) + v3 := byte(1 << (hashbuf[5] & 0x7)) + // The indices for the bytes to OR in + i1 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf)&0x7ff)>>3) - 1 + i2 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf[2:])&0x7ff)>>3) - 1 + i3 := BloomByteLength - uint((binary.BigEndian.Uint16(hashbuf[4:])&0x7ff)>>3) - 1 + + return i1, v1, i2, v2, i3, v3 +} + +// A AvaBlockNonce is a 64-bit hash which proves (combined with the +// mix-hash) that a sufficient amount of computation has been carried +// out on a block. +type AvaBlockNonce [8]byte + +// EncodeNonce converts the given integer to a block nonce. +func EncodeNonce(i uint64) AvaBlockNonce { + var n AvaBlockNonce + binary.BigEndian.PutUint64(n[:], i) + return n +} + +// Uint64 returns the integer value of a block nonce. +func (n AvaBlockNonce) Uint64() uint64 { + return binary.BigEndian.Uint64(n[:]) +} + +// MarshalText encodes n as a hex string with 0x prefix. +func (n AvaBlockNonce) MarshalText() ([]byte, error) { + return hexutil.Bytes(n[:]).MarshalText() +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (n *AvaBlockNonce) UnmarshalText(input []byte) error { + return hexutil.UnmarshalFixedText("AvaBlockNonce", input, n[:]) +} + +// AvaHeader is a copy of [github.com/ava-labs/coreth/core/types.Header] to avoid importing the whole module. +type AvaHeader struct { + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase common.Address `json:"miner" gencodec:"required"` + Root common.Hash `json:"stateRoot" gencodec:"required"` + TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom AvaBloom `json:"logsBloom" gencodec:"required"` + Difficulty *big.Int `json:"difficulty" gencodec:"required"` + Number *big.Int `json:"number" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed" gencodec:"required"` + Time uint64 `json:"timestamp" gencodec:"required"` + Extra []byte `json:"extraData" gencodec:"required"` + MixDigest common.Hash `json:"mixHash"` + Nonce AvaBlockNonce `json:"nonce"` + ExtDataHash common.Hash `json:"extDataHash" gencodec:"required"` + + // BaseFee was added by EIP-1559 and is ignored in legacy headers. + BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` + + // ExtDataGasUsed was added by Apricot Phase 4 and is ignored in legacy + // headers. + // + // It is not a uint64 like GasLimit or GasUsed because it is not possible to + // correctly encode this field optionally with uint64. + ExtDataGasUsed *big.Int `json:"extDataGasUsed" rlp:"optional"` + + // BlockGasCost was added by Apricot Phase 4 and is ignored in legacy + // headers. + BlockGasCost *big.Int `json:"blockGasCost" rlp:"optional"` +} + +func (h *AvaHeader) UnmarshalJSON(input []byte) error { + type Header struct { + ParentHash *common.Hash `json:"parentHash" gencodec:"required"` + UncleHash *common.Hash `json:"sha3Uncles" gencodec:"required"` + Coinbase *common.Address `json:"miner" gencodec:"required"` + Root *common.Hash `json:"stateRoot" gencodec:"required"` + TxHash *common.Hash `json:"transactionsRoot" gencodec:"required"` + ReceiptHash *common.Hash `json:"receiptsRoot" gencodec:"required"` + Bloom *AvaBloom `json:"logsBloom" gencodec:"required"` + Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` + Number *hexutil.Big `json:"number" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` + Time *hexutil.Uint64 `json:"timestamp" gencodec:"required"` + Extra *hexutil.Bytes `json:"extraData" gencodec:"required"` + MixDigest *common.Hash `json:"mixHash"` + Nonce *AvaBlockNonce `json:"nonce"` + ExtDataHash *common.Hash `json:"extDataHash" gencodec:"required"` + BaseFee *hexutil.Big `json:"baseFeePerGas" rlp:"optional"` + ExtDataGasUsed *hexutil.Big `json:"extDataGasUsed" rlp:"optional"` + BlockGasCost *hexutil.Big `json:"blockGasCost" rlp:"optional"` + } + var dec Header + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.ParentHash == nil { + return errors.New("missing required field 'parentHash' for Header") + } + h.ParentHash = *dec.ParentHash + if dec.UncleHash == nil { + return errors.New("missing required field 'sha3Uncles' for Header") + } + h.UncleHash = *dec.UncleHash + if dec.Coinbase == nil { + return errors.New("missing required field 'miner' for Header") + } + h.Coinbase = *dec.Coinbase + if dec.Root == nil { + return errors.New("missing required field 'stateRoot' for Header") + } + h.Root = *dec.Root + if dec.TxHash == nil { + return errors.New("missing required field 'transactionsRoot' for Header") + } + h.TxHash = *dec.TxHash + if dec.ReceiptHash == nil { + return errors.New("missing required field 'receiptsRoot' for Header") + } + h.ReceiptHash = *dec.ReceiptHash + if dec.Bloom == nil { + return errors.New("missing required field 'logsBloom' for Header") + } + h.Bloom = *dec.Bloom + if dec.Difficulty == nil { + return errors.New("missing required field 'difficulty' for Header") + } + h.Difficulty = (*big.Int)(dec.Difficulty) + if dec.Number == nil { + return errors.New("missing required field 'number' for Header") + } + h.Number = (*big.Int)(dec.Number) + if dec.GasLimit == nil { + return errors.New("missing required field 'gasLimit' for Header") + } + h.GasLimit = uint64(*dec.GasLimit) + if dec.GasUsed == nil { + return errors.New("missing required field 'gasUsed' for Header") + } + h.GasUsed = uint64(*dec.GasUsed) + if dec.Time == nil { + return errors.New("missing required field 'timestamp' for Header") + } + h.Time = uint64(*dec.Time) + if dec.Extra == nil { + return errors.New("missing required field 'extraData' for Header") + } + h.Extra = *dec.Extra + if dec.MixDigest != nil { + h.MixDigest = *dec.MixDigest + } + if dec.Nonce != nil { + h.Nonce = *dec.Nonce + } + if dec.ExtDataHash == nil { + return errors.New("missing required field 'extDataHash' for Header") + } + h.ExtDataHash = *dec.ExtDataHash + if dec.BaseFee != nil { + h.BaseFee = (*big.Int)(dec.BaseFee) + } + if dec.ExtDataGasUsed != nil { + h.ExtDataGasUsed = (*big.Int)(dec.ExtDataGasUsed) + } + if dec.BlockGasCost != nil { + h.BlockGasCost = (*big.Int)(dec.BlockGasCost) + } + return nil +} +func (h *AvaHeader) Hash() common.Hash { + return rlpHash(h) +} +func rlpHash(x interface{}) (h common.Hash) { + sha := crypto.NewKeccakState() + sha.Reset() + rlp.Encode(sha, x) //nolint:errcheck + sha.Read(h[:]) //nolint:errcheck + return h +} diff --git a/core/scripts/common/helpers.go b/core/scripts/common/helpers.go index c141e8a29c4..0ed9929956a 100644 --- a/core/scripts/common/helpers.go +++ b/core/scripts/common/helpers.go @@ -12,7 +12,6 @@ import ( "strings" "time" - avaxclient "github.com/ava-labs/coreth/ethclient" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -34,11 +33,6 @@ type Environment struct { Jc *rpc.Client - // AvaxEc is appropriately set if the environment is configured to interact with an avalanche - // chain. It should be used instead of the regular Ec field because avalanche calculates - // blockhashes differently and the regular Ec will give consistently incorrect results on basic - // queries (like e.g eth_blockByNumber). - AvaxEc avaxclient.Client ChainID int64 } @@ -84,12 +78,6 @@ func SetupEnv(overrideNonce bool) Environment { chainID, err := strconv.ParseInt(chainIDEnv, 10, 64) PanicErr(err) - var avaxClient avaxclient.Client - if IsAvaxNetwork(chainID) { - avaxClient, err = avaxclient.Dial(ethURL) - PanicErr(err) - } - // Owner key. Make sure it has eth b, err := hex.DecodeString(accountKey) PanicErr(err) @@ -136,7 +124,6 @@ func SetupEnv(overrideNonce bool) Environment { Owner: owner, Ec: ec, Jc: jsonRPCClient, - AvaxEc: avaxClient, ChainID: chainID, } } @@ -184,6 +171,8 @@ func explorerLinkPrefix(chainID int64) (prefix string) { prefix = "https://goerli.arbiscan.io" case ArbitrumOneChainID: // Arbitrum mainnet prefix = "https://arbiscan.io" + case ArbitrumSepoliaChainID: // Arbitrum Sepolia + prefix = "https://sepolia.arbiscan.io" case 56: // BSC mainnet prefix = "https://bscscan.com" @@ -246,6 +235,8 @@ func automationExplorerNetworkName(chainID int64) (prefix string) { prefix = "arbitrum-goerli" case ArbitrumOneChainID: // Arbitrum mainnet prefix = "arbitrum" + case ArbitrumSepoliaChainID: // Arbitrum Sepolia + prefix = "arbitrum-sepolia" case 56: // BSC mainnet prefix = "bsc" @@ -408,12 +399,12 @@ func FundNode(e Environment, address string, fundingAmount *big.Int) { var gasLimit uint64 if IsArbitrumChainID(e.ChainID) { to := common.HexToAddress(address) - estimated, err := e.Ec.EstimateGas(context.Background(), ethereum.CallMsg{ + estimated, err2 := e.Ec.EstimateGas(context.Background(), ethereum.CallMsg{ From: e.Owner.From, To: &to, Value: fundingAmount, }) - PanicErr(err) + PanicErr(err2) gasLimit = estimated } else { gasLimit = uint64(21_000) @@ -474,7 +465,7 @@ func GetRlpHeaders(env Environment, blockNumbers []*big.Int, getParentBlocks boo hashes = make([]string, 0) - var offset *big.Int = big.NewInt(0) + offset := big.NewInt(0) if getParentBlocks { offset = big.NewInt(1) } @@ -485,19 +476,18 @@ func GetRlpHeaders(env Environment, blockNumbers []*big.Int, getParentBlocks boo // Avalanche block headers are special, handle them by using the avalanche rpc client // rather than the regular go-ethereum ethclient. if IsAvaxNetwork(env.ChainID) { + var h AvaHeader // Get child block since it's the one that has the parent hash in its header. - h, err := env.AvaxEc.HeaderByNumber( - context.Background(), - new(big.Int).Set(blockNum).Add(blockNum, offset), - ) - if err != nil { - return nil, hashes, fmt.Errorf("failed to get header: %+v", err) + nextBlockNum := new(big.Int).Set(blockNum).Add(blockNum, offset) + err2 := env.Jc.CallContext(context.Background(), &h, "eth_getBlockByNumber", hexutil.EncodeBig(nextBlockNum), false) + if err2 != nil { + return nil, hashes, fmt.Errorf("failed to get header: %+v", err2) } // We can still use vanilla go-ethereum rlp.EncodeToBytes, see e.g // https://github.com/ava-labs/coreth/blob/e3ca41bf5295a9a7ca1aeaf29d541fcbb94f79b1/core/types/hashing.go#L49-L57. - rlpHeader, err = rlp.EncodeToBytes(h) - if err != nil { - return nil, hashes, fmt.Errorf("failed to encode rlp: %+v", err) + rlpHeader, err2 = rlp.EncodeToBytes(h) + if err2 != nil { + return nil, hashes, fmt.Errorf("failed to encode rlp: %+v", err2) } hashes = append(hashes, h.Hash().String()) @@ -523,16 +513,16 @@ func GetRlpHeaders(env Environment, blockNumbers []*big.Int, getParentBlocks boo } else { // Get child block since it's the one that has the parent hash in its header. - h, err := env.Ec.HeaderByNumber( + h, err2 := env.Ec.HeaderByNumber( context.Background(), new(big.Int).Set(blockNum).Add(blockNum, offset), ) - if err != nil { - return nil, hashes, fmt.Errorf("failed to get header: %+v", err) + if err2 != nil { + return nil, hashes, fmt.Errorf("failed to get header: %+v", err2) } - rlpHeader, err = rlp.EncodeToBytes(h) - if err != nil { - return nil, hashes, fmt.Errorf("failed to encode rlp: %+v", err) + rlpHeader, err2 = rlp.EncodeToBytes(h) + if err2 != nil { + return nil, hashes, fmt.Errorf("failed to encode rlp: %+v", err2) } hashes = append(hashes, h.Hash().String()) diff --git a/core/scripts/common/vrf/jobs/jobs.go b/core/scripts/common/vrf/jobs/jobs.go index 674cca175c8..7e304f431be 100644 --- a/core/scripts/common/vrf/jobs/jobs.go +++ b/core/scripts/common/vrf/jobs/jobs.go @@ -7,13 +7,14 @@ schemaVersion = 1 coordinatorAddress = "%s" batchCoordinatorAddress = "%s" batchFulfillmentEnabled = %t -batchFulfillmentGasMultiplier = 1.1 +batchFulfillmentGasMultiplier = %f +customRevertsPipelineEnabled = %t publicKey = "%s" minIncomingConfirmations = %d evmChainID = "%d" fromAddresses = ["%s"] -pollPeriod = "300ms" -requestTimeout = "30m0s" +pollPeriod = "%s" +requestTimeout = "%s" observationSource = """decode_log [type=ethabidecodelog abi="RandomWordsRequested(bytes32 indexed keyHash,uint256 requestId,uint256 preSeed,uint64 indexed subId,uint16 minimumRequestConfirmations,uint32 callbackGasLimit,uint32 numWords,address indexed sender)" data="$(jobRun.logData)" @@ -25,7 +26,7 @@ vrf [type=vrfv2 topics="$(jobRun.logTopics)"] estimate_gas [type=estimategaslimit to="%s" - multiplier="1.1" + multiplier="%f" data="$(vrf.output)"] simulate [type=ethcall from="%s" @@ -45,13 +46,13 @@ schemaVersion = 1 coordinatorAddress = "%s" batchCoordinatorAddress = "%s" batchFulfillmentEnabled = %t -batchFulfillmentGasMultiplier = 1.1 +batchFulfillmentGasMultiplier = %f publicKey = "%s" minIncomingConfirmations = %d evmChainID = "%d" fromAddresses = ["%s"] -pollPeriod = "300ms" -requestTimeout = "30m0s" +pollPeriod = "%s" +requestTimeout = "%s" observationSource = """ decode_log [type=ethabidecodelog abi="RandomWordsRequested(bytes32 indexed keyHash,uint256 requestId,uint256 preSeed,uint256 indexed subId,uint16 minimumRequestConfirmations,uint32 callbackGasLimit,uint32 numWords,bytes extraArgs,address indexed sender)" @@ -64,7 +65,7 @@ generate_proof [type=vrfv2plus topics="$(jobRun.logTopics)"] estimate_gas [type=estimategaslimit to="%s" - multiplier="1.1" + multiplier="%f" data="$(generate_proof.output)"] simulate_fulfillment [type=ethcall from="%s" @@ -91,6 +92,20 @@ runTimeout = "1m0s" evmChainID = "%d" fromAddresses = ["%s"] ` + BHSPlusJobFormatted = `type = "blockhashstore" +schemaVersion = 1 +name = "blockhashstore" +forwardingAllowed = false +coordinatorV2PlusAddress = "%s" +waitBlocks = %d +lookbackBlocks = %d +blockhashStoreAddress = "%s" +pollPeriod = "30s" +runTimeout = "1m0s" +evmChainID = "%d" +fromAddresses = ["%s"] +` + BHFJobFormatted = `type = "blockheaderfeeder" schemaVersion = 1 name = "blockheaderfeeder" @@ -106,5 +121,22 @@ evmChainID = "%d" fromAddresses = ["%s"] getBlockhashesBatchSize = 50 storeBlockhashesBatchSize = 10 +` + + BHFPlusJobFormatted = `type = "blockheaderfeeder" +schemaVersion = 1 +name = "blockheaderfeeder" +forwardingAllowed = false +coordinatorV2PlusAddress = "%s" +waitBlocks = 256 +lookbackBlocks = 1_000 +blockhashStoreAddress = "%s" +batchBlockhashStoreAddress = "%s" +pollPeriod = "10s" +runTimeout = "30s" +evmChainID = "%d" +fromAddresses = ["%s"] +getBlockhashesBatchSize = 50 +storeBlockhashesBatchSize = 10 ` ) diff --git a/core/scripts/common/vrf/model/model.go b/core/scripts/common/vrf/model/model.go index 0972c47e618..ba919eb3c4b 100644 --- a/core/scripts/common/vrf/model/model.go +++ b/core/scripts/common/vrf/model/model.go @@ -21,7 +21,6 @@ type Node struct { NumberOfSendingKeysToCreate int SendingKeyFundingAmount *big.Int VrfKeys []string - jobSpec string } type SendingKey struct { @@ -50,3 +49,12 @@ type VRFKeyRegistrationConfig struct { VRFKeyUncompressedPubKey string RegisterAgainstAddress string } + +type CoordinatorJobSpecConfig struct { + BatchFulfillmentEnabled bool + BatchFulfillmentGasMultiplier float64 + EstimateGasMultiplier float64 + PollPeriod string + RequestTimeout string + RevertsPipelineEnabled bool +} diff --git a/core/scripts/common/vrf/setup-envs/README.md b/core/scripts/common/vrf/setup-envs/README.md index 9aa76ffbbb7..372e7358441 100644 --- a/core/scripts/common/vrf/setup-envs/README.md +++ b/core/scripts/common/vrf/setup-envs/README.md @@ -15,10 +15,12 @@ export ETH_CHAIN_ID= export ACCOUNT_KEY= ``` 5. execute from `core/scripts/common/vrf/setup-envs` folder - * `--vrf-version` - "v2" or "v2plus" + * `--vrf-version` - "v2" or "v2plus" + +#### VRF V2 ``` go run . \ ---vrf-version="v2plus" \ +--vrf-version="v2" \ --vrf-primary-node-url=http://localhost:6610 \ --vrf-primary-creds-file \ --vrf-backup-node-url=http://localhost:6611 \ @@ -36,9 +38,48 @@ go run . \ --subscription-balance="1e19" \ --subscription-balance-native="1e18" \ --batch-fulfillment-enabled="true" \ +--batch-fulfillment-gas-multiplier=1.1 \ +--estimate-gas-multiplier=1.1 \ +--poll-period="5s" \ +--request-timeout="30m0s" \ +--reverts-pipeline-enabled="true" \ --min-confs=3 \ --register-vrf-key-against-address= +in order to call oracleWithdraw from this address> \ +--deploy-vrfv2-owner="true" \ +--use-test-coordinator="true" +``` +#### VRF V2 Plus +* does not need to register VRF key against address +* does not need to deploy VRFV2Owner contract +* does not need to use test coordinator + +VRF V2 Plus example: +``` +go run . \ +--vrf-version="v2plus" \ +--vrf-primary-node-url=http://localhost:6610 \ +--vrf-primary-creds-file \ +--vrf-backup-node-url=http://localhost:6611 \ +--vrf-bk-creds-file \ +--bhs-node-url=http://localhost:6612 \ +--bhs-creds-file \ +--bhs-backup-node-url=http://localhost:6613 \ +--bhs-bk-creds-file \ +--bhf-node-url=http://localhost:6614 \ +--bhf-creds-file \ +--num-eth-keys=1 \ +--num-vrf-keys=1 \ +--sending-key-funding-amount="1e17" \ +--deploy-contracts-and-create-jobs="true" \ +--subscription-balance="1e19" \ +--subscription-balance-native="1e18" \ +--batch-fulfillment-enabled="true" \ +--batch-fulfillment-gas-multiplier=1.1 \ +--estimate-gas-multiplier=1.1 \ +--poll-period="5s" \ +--request-timeout="30m0s" \ +--min-confs=3 ``` Optional parameters - will not be deployed if specified @@ -71,7 +112,7 @@ go run . \ --sending-key-funding-amount="1e17" \ --deploy-contracts-and-create-jobs="false" ``` -Then update corresponding deployment scripts with the new ETH addresses, specifying max gas price for each key +Then update corresponding deployment scripts in infra-k8s repo with the new ETH addresses, specifying max gas price for each key e.g.: ``` @@ -98,6 +139,7 @@ go run . \ --batch-fulfillment-enabled="true" \ --min-confs=3 \ --register-vrf-key-against-address="" \ +--deploy-vrfv2-owner="true" \ --link-address "" \ --link-eth-feed "" ``` diff --git a/core/scripts/common/vrf/setup-envs/main.go b/core/scripts/common/vrf/setup-envs/main.go index 94662aa1831..57e4817d804 100644 --- a/core/scripts/common/vrf/setup-envs/main.go +++ b/core/scripts/common/vrf/setup-envs/main.go @@ -12,6 +12,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/shopspring/decimal" + "github.com/urfave/cli" + helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/constants" "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/model" @@ -21,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" - "github.com/urfave/cli" ) func newApp(remoteNodeURL string, writer io.Writer) (*clcmd.Shell, *cli.App) { @@ -49,7 +50,6 @@ func newApp(remoteNodeURL string, writer io.Writer) (*clcmd.Shell, *cli.App) { var ( checkMarkEmoji = "✅" xEmoji = "❌" - infoEmoji = "ℹ️" ) func main() { @@ -70,7 +70,12 @@ func main() { numEthKeys := flag.Int("num-eth-keys", 5, "Number of eth keys to create") maxGasPriceGwei := flag.Int("max-gas-price-gwei", -1, "Max gas price gwei of the eth keys") numVRFKeys := flag.Int("num-vrf-keys", 1, "Number of vrf keys to create") - batchFulfillmentEnabled := flag.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether to enable batch fulfillment on Cl node") + batchFulfillmentEnabled := flag.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether send randomness fulfillments in batches inside one tx from CL node") + batchFulfillmentGasMultiplier := flag.Float64("batch-fulfillment-gas-multiplier", 1.1, "") + estimateGasMultiplier := flag.Float64("estimate-gas-multiplier", 1.1, "") + pollPeriod := flag.String("poll-period", "300ms", "") + requestTimeout := flag.String("request-timeout", "30m0s", "") + revertsPipelineEnabled := flag.Bool("reverts-pipeline-enabled", true, "") vrfVersion := flag.String("vrf-version", "v2", "VRF version to use") deployContractsAndCreateJobs := flag.Bool("deploy-contracts-and-create-jobs", false, "whether to deploy contracts and create jobs") @@ -87,6 +92,8 @@ func main() { batchCoordinatorAddressString := flag.String("batch-coordinator-address", "", "address Batch VRF Coordinator contract") registerVRFKeyAgainstAddress := flag.String("register-vrf-key-against-address", "", "VRF Key registration against address - "+ "from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments") + deployVRFOwner := flag.Bool("deploy-vrfv2-owner", true, "whether to deploy VRF owner contracts") + useTestCoordinator := flag.Bool("use-test-coordinator", true, "whether to use test coordinator contract or use the normal one") e := helpers.SetupEnv(false) flag.Parse() @@ -140,7 +147,7 @@ func main() { output := &bytes.Buffer{} for key, node := range nodesMap { - + node := node client, app := connectToNode(&node.URL, output, node.CredsFile) ethKeys := createETHKeysIfNeeded(client, app, output, numEthKeys, &node.URL, maxGasPriceGwei) if key == model.VRFPrimaryNodeName { @@ -203,14 +210,25 @@ func main() { FeeConfig: feeConfigV2, } + coordinatorJobSpecConfig := model.CoordinatorJobSpecConfig{ + BatchFulfillmentEnabled: *batchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *batchFulfillmentGasMultiplier, + EstimateGasMultiplier: *estimateGasMultiplier, + PollPeriod: *pollPeriod, + RequestTimeout: *requestTimeout, + RevertsPipelineEnabled: *revertsPipelineEnabled, + } + jobSpecs = v2scripts.VRFV2DeployUniverse( e, subscriptionBalanceJuels, vrfKeyRegistrationConfig, contractAddresses, coordinatorConfigV2, - *batchFulfillmentEnabled, nodesMap, + *deployVRFOwner, + coordinatorJobSpecConfig, + *useTestCoordinator, ) case "v2plus": feeConfigV2Plus := vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ @@ -226,6 +244,14 @@ func main() { FeeConfig: feeConfigV2Plus, } + coordinatorJobSpecConfig := model.CoordinatorJobSpecConfig{ + BatchFulfillmentEnabled: *batchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *batchFulfillmentGasMultiplier, + EstimateGasMultiplier: *estimateGasMultiplier, + PollPeriod: *pollPeriod, + RequestTimeout: *requestTimeout, + } + jobSpecs = v2plusscripts.VRFV2PlusDeployUniverse( e, subscriptionBalanceJuels, @@ -233,12 +259,13 @@ func main() { vrfKeyRegistrationConfig, contractAddresses, coordinatorConfigV2Plus, - *batchFulfillmentEnabled, nodesMap, + coordinatorJobSpecConfig, ) } for key, node := range nodesMap { + node := node client, app := connectToNode(&node.URL, output, node.CredsFile) //GET ALL JOBS @@ -315,7 +342,7 @@ func getVRFKeys(client *clcmd.Shell, app *cli.App, output *bytes.Buffer) []prese } func createJob(jobSpec string, client *clcmd.Shell, app *cli.App, output *bytes.Buffer) { - if err := os.WriteFile("job-spec.toml", []byte(jobSpec), 0666); err != nil { + if err := os.WriteFile("job-spec.toml", []byte(jobSpec), 0666); err != nil { //nolint:gosec helpers.PanicErr(err) } job := presenters.JobResource{} @@ -329,7 +356,7 @@ func createJob(jobSpec string, client *clcmd.Shell, app *cli.App, output *bytes. } func exportVRFKey(client *clcmd.Shell, app *cli.App, vrfKey presenters.VRFKeyResource, output *bytes.Buffer) { - if err := os.WriteFile("vrf-key-password.txt", []byte("twochains"), 0666); err != nil { + if err := os.WriteFile("vrf-key-password.txt", []byte("twochains"), 0666); err != nil { //nolint:gosec helpers.PanicErr(err) } flagSet := flag.NewFlagSet("blah", flag.ExitOnError) @@ -343,7 +370,7 @@ func exportVRFKey(client *clcmd.Shell, app *cli.App, vrfKey presenters.VRFKeyRes } func importVRFKey(client *clcmd.Shell, app *cli.App, output *bytes.Buffer) { - if err := os.WriteFile("vrf-key-password.txt", []byte("twochains"), 0666); err != nil { + if err := os.WriteFile("vrf-key-password.txt", []byte("twochains"), 0666); err != nil { //nolint:gosec helpers.PanicErr(err) } flagSet := flag.NewFlagSet("blah", flag.ExitOnError) @@ -462,12 +489,8 @@ func createVRFKeyIfNeeded(client *clcmd.Shell, app *cli.App, output *bytes.Buffe }(), ", ")) } fmt.Println() - for _, vrfKey := range vrfKeys { - allVRFKeys = append(allVRFKeys, vrfKey) - } - for _, nk := range newKeys { - allVRFKeys = append(allVRFKeys, nk) - } + allVRFKeys = append(allVRFKeys, vrfKeys...) + allVRFKeys = append(allVRFKeys, newKeys...) return allVRFKeys } @@ -503,6 +526,7 @@ func createETHKeysIfNeeded(client *clcmd.Shell, app *cli.App, output *bytes.Buff var newKey presenters.ETHKeyResource flagSet := flag.NewFlagSet("blah", flag.ExitOnError) + flagSet.String("evm-chain-id", os.Getenv("ETH_CHAIN_ID"), "chain id") if *maxGasPriceGwei > 0 { helpers.PanicErr(flagSet.Set("max-gas-price-gwei", fmt.Sprintf("%d", *maxGasPriceGwei))) } @@ -522,11 +546,7 @@ func createETHKeysIfNeeded(client *clcmd.Shell, app *cli.App, output *bytes.Buff } output.Reset() fmt.Println() - for _, ethKey := range ethKeys { - allETHKeysNode = append(allETHKeysNode, ethKey) - } - for _, nk := range newKeys { - allETHKeysNode = append(allETHKeysNode, nk) - } + allETHKeysNode = append(allETHKeysNode, ethKeys...) + allETHKeysNode = append(allETHKeysNode, newKeys...) return allETHKeysNode } diff --git a/core/scripts/functions/src/delete_jobs.go b/core/scripts/functions/src/delete_jobs.go index 632a239a62b..4fac1a4a772 100644 --- a/core/scripts/functions/src/delete_jobs.go +++ b/core/scripts/functions/src/delete_jobs.go @@ -62,7 +62,7 @@ func (g *deleteJobs) Run(args []string) { output.Reset() fileFs := flag.NewFlagSet("test", flag.ExitOnError) - client.ListJobs(cli.NewContext(app, fileFs, nil)) + err = client.ListJobs(cli.NewContext(app, fileFs, nil)) helpers.PanicErr(err) var parsed []JobSpec @@ -73,7 +73,8 @@ func (g *deleteJobs) Run(args []string) { if jobSpec.BootstrapSpec.ContractID == *contractAddress || jobSpec.OffChainReporting2OracleSpec.ContractID == *contractAddress { fmt.Println("Deleting job ID:", jobSpec.Id, "name:", jobSpec.Name) set := flag.NewFlagSet("test", flag.ExitOnError) - set.Parse([]string{jobSpec.Id}) + err = set.Parse([]string{jobSpec.Id}) + helpers.PanicErr(err) err = client.DeleteJob(cli.NewContext(app, set, nil)) helpers.PanicErr(err) } diff --git a/core/scripts/functions/src/deploy_jobspecs_cmd.go b/core/scripts/functions/src/deploy_jobspecs_cmd.go index 0039aaa4601..e892370cc22 100644 --- a/core/scripts/functions/src/deploy_jobspecs_cmd.go +++ b/core/scripts/functions/src/deploy_jobspecs_cmd.go @@ -27,18 +27,18 @@ func (g *deployJobSpecs) Name() string { func (g *deployJobSpecs) Run(args []string) { fs := flag.NewFlagSet(g.Name(), flag.ContinueOnError) nodesFile := fs.String("nodes", "", "a file containing nodes urls, logins and passwords") - err := fs.Parse(args) - if err != nil || nodesFile == nil || *nodesFile == "" { + + if err := fs.Parse(args); err != nil || nodesFile == nil || *nodesFile == "" { fs.Usage() os.Exit(1) } nodes := mustReadNodesList(*nodesFile) - for _, node := range nodes { + for _, n := range nodes { output := &bytes.Buffer{} - client, app := newApp(node, output) + client, app := newApp(n, output) - fmt.Println("Logging in:", node.url) + fmt.Println("Logging in:", n.url) loginFs := flag.NewFlagSet("test", flag.ContinueOnError) loginFs.Bool("bypass-version-check", true, "") loginCtx := cli.NewContext(app, loginFs, nil) @@ -46,18 +46,19 @@ func (g *deployJobSpecs) Run(args []string) { helpers.PanicErr(err) output.Reset() - tomlPath := filepath.Join(artefactsDir, node.url.Host+".toml") + tomlPath := filepath.Join(artefactsDir, n.url.Host+".toml") tomlPath, err = filepath.Abs(tomlPath) if err != nil { helpers.PanicErr(err) } fmt.Println("Deploying jobspec:", tomlPath) - if _, err := os.Stat(tomlPath); err != nil { + if _, err = os.Stat(tomlPath); err != nil { helpers.PanicErr(errors.New("toml file does not exist")) } fileFs := flag.NewFlagSet("test", flag.ExitOnError) - fileFs.Parse([]string{tomlPath}) + err = fileFs.Parse([]string{tomlPath}) + helpers.PanicErr(err) err = client.CreateJob(cli.NewContext(app, fileFs, nil)) helpers.PanicErr(err) output.Reset() diff --git a/core/scripts/functions/src/fetching.go b/core/scripts/functions/src/fetching.go index 0b22a93252d..2e0841b49de 100644 --- a/core/scripts/functions/src/fetching.go +++ b/core/scripts/functions/src/fetching.go @@ -11,7 +11,7 @@ import ( "github.com/urfave/cli" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -24,11 +24,11 @@ type ocr2Bundle struct { } func mustFetchNodesKeys(chainID int64, nodes []*node) (nca []NodeKeys) { - for _, node := range nodes { + for _, n := range nodes { output := &bytes.Buffer{} - client, app := newApp(node, output) + client, app := newApp(n, output) - fmt.Println("Logging in:", node.url) + fmt.Println("Logging in:", n.url) loginFs := flag.NewFlagSet("test", flag.ContinueOnError) loginFs.Bool("bypass-version-check", true, "") loginCtx := cli.NewContext(app, loginFs, nil) @@ -68,7 +68,7 @@ func mustFetchNodesKeys(chainID int64, nodes []*node) (nca []NodeKeys) { if ocr2BundleIndex == -1 { helpers.PanicErr(errors.New("node must have EVM OCR2 bundle")) } - ocr2Bundle := ocr2Bundles[ocr2BundleIndex] + ocr2Bndl := ocr2Bundles[ocr2BundleIndex] output.Reset() err = client.ListCSAKeys(&cli.Context{ @@ -84,10 +84,10 @@ func mustFetchNodesKeys(chainID int64, nodes []*node) (nca []NodeKeys) { nc := NodeKeys{ EthAddress: ethAddress, P2PPeerID: peerID, - OCR2BundleID: ocr2Bundle.ID, - OCR2ConfigPublicKey: strings.TrimPrefix(ocr2Bundle.ConfigPublicKey, "ocr2cfg_evm_"), - OCR2OnchainPublicKey: strings.TrimPrefix(ocr2Bundle.OnchainPublicKey, "ocr2on_evm_"), - OCR2OffchainPublicKey: strings.TrimPrefix(ocr2Bundle.OffchainPublicKey, "ocr2off_evm_"), + OCR2BundleID: ocr2Bndl.ID, + OCR2ConfigPublicKey: strings.TrimPrefix(ocr2Bndl.ConfigPublicKey, "ocr2cfg_evm_"), + OCR2OnchainPublicKey: strings.TrimPrefix(ocr2Bndl.OnchainPublicKey, "ocr2on_evm_"), + OCR2OffchainPublicKey: strings.TrimPrefix(ocr2Bndl.OffchainPublicKey, "ocr2off_evm_"), CSAPublicKey: csaPubKey, } @@ -114,7 +114,7 @@ func findEvmOCR2Bundle(ocr2Bundles []ocr2Bundle) int { func findFirstGoodEthKeyAddress(chainID int64, ethKeys []presenters.ETHKeyResource) (string, error) { for _, ethKey := range ethKeys { - if ethKey.EVMChainID.Equal(utils.NewBigI(chainID)) && !ethKey.Disabled { + if ethKey.EVMChainID.Equal(ubig.NewI(chainID)) && !ethKey.Disabled { if ethKey.EthBalance.IsZero() { fmt.Println("WARN: selected ETH address has zero balance", ethKey.Address) } diff --git a/core/scripts/functions/src/generate_ocr2_config_cmd.go b/core/scripts/functions/src/generate_ocr2_config_cmd.go index 1cfddf4413c..7ac3b68d11d 100644 --- a/core/scripts/functions/src/generate_ocr2_config_cmd.go +++ b/core/scripts/functions/src/generate_ocr2_config_cmd.go @@ -134,8 +134,7 @@ func (g *generateOCR2Config) Run(args []string) { keysFile := fs.String("keys", "", "a file containing nodes public keys") configFile := fs.String("config", "", "a file containing JSON config") chainID := fs.Int64("chainid", 80001, "chain id") - err := fs.Parse(args) - if err != nil || (*nodesFile == "" && *keysFile == "") || *configFile == "" || chainID == nil { + if err := fs.Parse(args); err != nil || (*nodesFile == "" && *keysFile == "") || *configFile == "" || chainID == nil { fs.Usage() os.Exit(1) } diff --git a/core/scripts/gateway/client/send_request.go b/core/scripts/gateway/client/send_request.go index 8ab4e8bce79..eeb85ff0dcb 100644 --- a/core/scripts/gateway/client/send_request.go +++ b/core/scripts/gateway/client/send_request.go @@ -52,7 +52,6 @@ func main() { var s4SetPayload []byte if *methodName == functions.MethodSecretsSet { - var err error s4SetPayload, err = os.ReadFile(*s4SetPayloadFile) if err != nil { fmt.Println("error reading S4 payload file", err) @@ -70,23 +69,21 @@ func main() { Payload: s4SetPayload, Expiration: time.Now().UnixMilli() + *s4SetExpirationPeriod, } - signature, err := envelope.Sign(key) - if err != nil { - fmt.Println("error signing S4 envelope", err) + signature, err2 := envelope.Sign(key) + if err2 != nil { + fmt.Println("error signing S4 envelope", err2) return } - s4SetPayload := functions.SecretsSetRequest{ + payloadJSON, err2 = json.Marshal(functions.SecretsSetRequest{ SlotID: envelope.SlotID, Version: envelope.Version, Expiration: envelope.Expiration, Payload: s4SetPayload, Signature: signature, - } - - payloadJSON, err = json.Marshal(s4SetPayload) - if err != nil { - fmt.Println("error marshaling S4 payload", err) + }) + if err2 != nil { + fmt.Println("error marshaling S4 payload", err2) return } } @@ -122,27 +119,27 @@ func main() { client := &http.Client{} sendRequest := func() { - req, err := createRequest() - if err != nil { - fmt.Println("error creating a request", err) + req, err2 := createRequest() + if err2 != nil { + fmt.Println("error creating a request", err2) return } - resp, err := client.Do(req) - if err != nil { - fmt.Println("error sending a request", err) + resp, err2 := client.Do(req) + if err2 != nil { + fmt.Println("error sending a request", err2) return } defer resp.Body.Close() - body, err := io.ReadAll(resp.Body) - if err != nil { - fmt.Println("error sending a request", err) + body, err2 := io.ReadAll(resp.Body) + if err2 != nil { + fmt.Println("error sending a request", err2) return } var prettyJSON bytes.Buffer - if err := json.Indent(&prettyJSON, body, "", " "); err != nil { + if err2 = json.Indent(&prettyJSON, body, "", " "); err2 != nil { fmt.Println(string(body)) } else { fmt.Println(prettyJSON.String()) diff --git a/core/scripts/gateway/connector/run_connector.go b/core/scripts/gateway/connector/run_connector.go index 248162ef822..c6ad187461c 100644 --- a/core/scripts/gateway/connector/run_connector.go +++ b/core/scripts/gateway/connector/run_connector.go @@ -31,7 +31,10 @@ type client struct { func (h *client) HandleGatewayMessage(ctx context.Context, gatewayId string, msg *api.Message) { h.lggr.Infof("received message from gateway %s. Echoing back.", gatewayId) - h.connector.SendToGateway(context.Background(), gatewayId, msg) + err := h.connector.SendToGateway(ctx, gatewayId, msg) + if err != nil { + h.lggr.Errorw("failed to send to gateway", "id", gatewayId, "err", err) + } } func (h *client) Sign(data ...[]byte) ([]byte, error) { @@ -70,8 +73,16 @@ func main() { client.connector = connector ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt) - connector.Start(ctx) + err = connector.Start(ctx) + if err != nil { + fmt.Println("error staring connector:", err) + return + } <-ctx.Done() - connector.Close() + err = connector.Close() + if err != nil { + fmt.Println("error closing connector:", err) + return + } } diff --git a/core/scripts/gateway/run_gateway.go b/core/scripts/gateway/run_gateway.go index 1f0230bb8ad..5dbcd02bf56 100644 --- a/core/scripts/gateway/run_gateway.go +++ b/core/scripts/gateway/run_gateway.go @@ -48,7 +48,7 @@ func main() { lggr, _ := logger.NewLogger() - handlerFactory := gateway.NewHandlerFactory(nil, lggr) + handlerFactory := gateway.NewHandlerFactory(nil, nil, nil, lggr) gw, err := gateway.NewGatewayFromConfig(&cfg, handlerFactory, lggr) if err != nil { fmt.Println("error creating Gateway object:", err) @@ -56,8 +56,16 @@ func main() { } ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt) - gw.Start(ctx) + err = gw.Start(ctx) + if err != nil { + fmt.Println("error staring gateway:", err) + return + } <-ctx.Done() - gw.Close() + err = gw.Close() + if err != nil { + fmt.Println("error closing gateway:", err) + return + } } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index c7af0541c12..6a126d81aeb 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -6,11 +6,9 @@ go 1.21.3 replace github.com/smartcontractkit/chainlink/v2 => ../../ require ( - github.com/ava-labs/coreth v0.12.1 - github.com/avast/retry-go v3.0.0+incompatible github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.4.0 - github.com/ethereum/go-ethereum v1.12.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/jmoiron/sqlx v1.3.5 @@ -18,13 +16,13 @@ require ( github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f github.com/montanaflynn/stats v0.7.1 github.com/olekukonko/tablewriter v0.0.5 - github.com/pelletier/go-toml/v2 v2.1.0 - github.com/pkg/errors v0.9.1 + github.com/pelletier/go-toml/v2 v2.1.1 github.com/shopspring/decimal v1.3.1 - github.com/smartcontractkit/chainlink-automation v1.0.1 + github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240124161023-948579cbaffa github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 + github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.15.0 github.com/stretchr/testify v1.8.4 @@ -49,34 +47,37 @@ require ( github.com/CosmWasm/wasmd v0.40.1 // indirect github.com/CosmWasm/wasmvm v1.2.4 // indirect github.com/DataDog/zstd v1.5.2 // indirect - github.com/Depado/ginprom v1.7.11 // indirect + github.com/Depado/ginprom v1.8.0 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/VictoriaMetrics/fastcache v1.10.0 // indirect + github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect - github.com/ava-labs/avalanchego v1.10.1 // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // 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/btcsuite/btcd v0.23.4 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/bytedance/sonic v1.9.1 // indirect + github.com/btcsuite/btcd/btcutil v1.1.3 // 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 github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect + github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect github.com/cockroachdb/redact v1.1.3 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft v0.37.2 // indirect github.com/cometbft/cometbft-db v0.7.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/cosmos-sdk v0.47.4 // indirect @@ -87,11 +88,11 @@ require ( github.com/cosmos/ics23/go v0.9.1-0.20221207100636-b1abd8678aab // indirect github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect + github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/deckarep/golang-set v1.8.0 // indirect github.com/deckarep/golang-set/v2 v2.3.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 // indirect @@ -103,8 +104,8 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect github.com/esote/minmaxheap v1.0.0 // indirect + github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/fatih/color v1.16.0 // indirect - github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect 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 @@ -112,44 +113,43 @@ require ( github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // 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 github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/getsentry/sentry-go v0.19.0 // indirect - github.com/gin-contrib/cors v1.4.0 // indirect + github.com/gin-contrib/cors v1.5.0 // indirect github.com/gin-contrib/expvar v0.0.1 // indirect github.com/gin-contrib/sessions v0.0.5 // indirect github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-ldap/ldap/v3 v3.4.5 // indirect + github.com/go-ldap/ldap/v3 v3.4.6 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/webauthn v0.9.1 // indirect - github.com/go-webauthn/x v0.1.4 // indirect + github.com/go-playground/validator/v10 v10.15.5 // indirect + github.com/go-webauthn/webauthn v0.9.4 // indirect + github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang-jwt/jwt/v5 v5.1.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect + github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/sessions v1.2.2 // indirect @@ -166,27 +166,20 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/consul/sdk v0.14.1 // indirect + github.com/hashicorp/go-envparse v0.1.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect - github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.2 // indirect + github.com/holiman/uint256 v1.2.4 // indirect github.com/huandu/skiplist v1.2.0 // indirect - github.com/huin/goupnp v1.0.3 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/ipfs/go-cid v0.0.7 // indirect - github.com/ipfs/go-datastore v0.4.5 // indirect - github.com/ipfs/go-ipfs-util v0.0.2 // indirect - github.com/ipfs/go-ipns v0.0.2 // indirect - github.com/ipfs/go-log v1.0.4 // indirect - github.com/ipfs/go-log/v2 v2.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.14.1 // indirect github.com/jackc/pgio v1.0.0 // indirect @@ -196,58 +189,18 @@ require ( github.com/jackc/pgtype v1.14.0 // indirect github.com/jackc/pgx/v4 v4.18.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/jbenet/goprocess v0.1.4 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.2 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect - github.com/koron/go-ssdp v0.0.2 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/libp2p/go-addr-util v0.0.2 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-conn-security-multistream v0.2.0 // indirect - github.com/libp2p/go-eventbus v0.2.1 // indirect - github.com/libp2p/go-flow-metrics v0.0.3 // indirect - github.com/libp2p/go-libp2p v0.13.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 // indirect - github.com/libp2p/go-libp2p-autonat v0.4.0 // indirect - github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect - github.com/libp2p/go-libp2p-circuit v0.4.0 // indirect - github.com/libp2p/go-libp2p-core v0.8.5 // indirect - github.com/libp2p/go-libp2p-discovery v0.5.0 // indirect - github.com/libp2p/go-libp2p-kad-dht v0.11.1 // indirect - github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect - github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect - github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect - github.com/libp2p/go-libp2p-nat v0.0.6 // indirect - github.com/libp2p/go-libp2p-noise v0.1.2 // indirect - github.com/libp2p/go-libp2p-peerstore v0.2.7 // indirect - github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect - github.com/libp2p/go-libp2p-record v0.1.3 // indirect - github.com/libp2p/go-libp2p-swarm v0.4.0 // indirect - github.com/libp2p/go-libp2p-tls v0.1.3 // indirect - github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 // indirect - github.com/libp2p/go-libp2p-yamux v0.5.1 // indirect - github.com/libp2p/go-mplex v0.3.0 // indirect - github.com/libp2p/go-msgio v0.0.6 // indirect - github.com/libp2p/go-nat v0.0.5 // indirect - github.com/libp2p/go-netroute v0.1.4 // indirect - github.com/libp2p/go-openssl v0.0.7 // indirect - github.com/libp2p/go-reuseport v0.0.2 // indirect - github.com/libp2p/go-reuseport-transport v0.0.4 // indirect - github.com/libp2p/go-sockaddr v0.1.0 // indirect - github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect - github.com/libp2p/go-tcp-transport v0.2.1 // indirect - github.com/libp2p/go-ws-transport v0.4.0 // indirect - github.com/libp2p/go-yamux/v2 v2.0.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -255,26 +208,15 @@ require ( github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect - github.com/minio/sha256-simd v0.1.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect - github.com/multiformats/go-multiaddr v0.3.3 // indirect - github.com/multiformats/go-multiaddr-dns v0.2.0 // indirect - github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multiaddr-net v0.2.0 // indirect - github.com/multiformats/go-multibase v0.0.3 // indirect - github.com/multiformats/go-multihash v0.0.14 // indirect - github.com/multiformats/go-multistream v0.2.0 // indirect - github.com/multiformats/go-varint v0.0.6 // indirect github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -290,10 +232,9 @@ require ( github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/prometheus/prometheus v0.48.0 // indirect + github.com/prometheus/prometheus v0.48.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/rjeczalik/notify v0.9.3 // indirect 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 @@ -301,25 +242,24 @@ require ( github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v3 v3.23.10 // indirect + github.com/shirou/gopsutil/v3 v3.23.11 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect - github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 // indirect + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 // 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/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect - github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.9.3 // indirect - github.com/spf13/cast v1.5.1 // 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/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 github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tendermint/go-amino v0.16.0 // indirect @@ -333,12 +273,10 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/ulule/limiter/v3 v3.11.2 // indirect github.com/unrolled/secure v1.13.0 // indirect github.com/valyala/fastjson v1.4.1 // indirect - github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect - github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // 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 @@ -346,6 +284,7 @@ require ( go.dedis.ch/fixbuf v1.0.3 // indirect go.etcd.io/bbolt v1.3.7 // indirect go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/otel v1.21.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect @@ -358,7 +297,7 @@ require ( go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/arch v0.6.0 // indirect - golang.org/x/crypto v0.16.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.19.0 // indirect @@ -377,19 +316,15 @@ require ( gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/guregu/null.v4 v4.0.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect - gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect pgregory.net/rapid v0.5.5 // indirect + rsc.io/tmplfunc v0.0.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) replace ( - // Fix go mod tidy issue for ambiguous imports from go-ethereum - // See https://github.com/ugorji/go/issues/279 - github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1 - // replicating the replace directive on cosmos SDK github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 7cea79eb76e..86c6bc84e53 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -75,14 +75,12 @@ github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo8 github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= -github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= @@ -100,12 +98,11 @@ github.com/CosmWasm/wasmvm v1.2.4/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/Depado/ginprom v1.7.11 h1:qOhxW/NJZkNkkG4TQrzAZklX8SUTjTfLA73zIUNIpww= -github.com/Depado/ginprom v1.7.11/go.mod h1:49mxL3NTQwDrhpDbY4V1mAIB3us9B+b2hP1+ph+Sla8= +github.com/Depado/ginprom v1.8.0 h1:zaaibRLNI1dMiiuj1MKzatm8qrcHzikMlCc1anqOdyo= +github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0FU0UKgg= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= @@ -117,8 +114,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= -github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= +github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -148,12 +145,6 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/ava-labs/avalanchego v1.10.1 h1:lBeamJ1iNq+p2oKg2nAs+A65m8vhSDjkiTDbwzQW7kY= -github.com/ava-labs/avalanchego v1.10.1/go.mod h1:ZvSXWlbkUKlbk3BsWx29a+8eVHe/WBsOxh55BSGoeRk= -github.com/ava-labs/coreth v0.12.1 h1:EWSkFGHGVUxmu1pnSK/2pdcxaAVHbGspHqO3Ag+i7sA= -github.com/ava-labs/coreth v0.12.1/go.mod h1:/5x54QlIKjlPebkdzTA5ic9wXdejbWOnQosztkv9jxo= -github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= -github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -173,21 +164,33 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= -github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= +github.com/btcsuite/btcd v0.23.0 h1:V2/ZgjfDFIygAX3ZapeigkVBoVUtOJKSwrhZdlpSvaA= +github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= +github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= +github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= +github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3 h1:SDlJ7bAm4ewvrmZtR0DaiYbQGdKPeaaIm7bM+qRhFeU= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= @@ -195,8 +198,9 @@ github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZ github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= +github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= @@ -207,12 +211,14 @@ github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= @@ -232,17 +238,20 @@ github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b80 github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/apd/v3 v3.1.0/go.mod h1:6qgPBMXjATAdD/VefbRP9NoSLKjbB4LCoA7gN4LpHs4= -github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= @@ -252,6 +261,10 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -259,7 +272,6 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -291,6 +303,10 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= +github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8= github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -304,19 +320,17 @@ github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuA github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e h1:5jVSh2l/ho6ajWhSPNN84eHEdq3dp0T7+f6r3Tc6hsk= github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e/go.mod h1:IJgIiGUARc4aOr4bOQ85klmjsShkEEfiRc6q/yBSfo8= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= -github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= -github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g= github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= @@ -325,18 +339,13 @@ github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFM github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT/t/lKtH99JQmKIb0v9WL3VaYkJ36CfHlVECI= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 h1:CuJS05R9jmNlUK8GOxrEELPbfXm0EuGh/30LjkjN5vo= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70/go.mod h1:EoK/8RFbMEteaCaz89uessDTnCWjbbcr+DXcBh4el5o= -github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= -github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -373,8 +382,10 @@ github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7 github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGCrqSJ5FZk= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= -github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= +github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= +github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.13.8 h1:1od+thJel3tM52ZUNQwvpYOeRHlbkVFZ5S8fhi0Lgsg= +github.com/ethereum/go-ethereum v1.13.8/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= @@ -392,12 +403,10 @@ github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBd github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= @@ -419,14 +428,16 @@ github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89 github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM= github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= github.com/getsentry/sentry-go v0.19.0 h1:BcCH3CN5tXt5aML+gwmbFwVptLLQA+eT866fCO9wVOM= github.com/getsentry/sentry-go v0.19.0/go.mod h1:y3+lGEFEFexZtpbG1GUE2WD/f9zGyKYwpEqryTOC/nE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= -github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= +github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk= +github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI= github.com/gin-contrib/expvar v0.0.1 h1:IuU5ArEgihz50vG8Onrwz22kJr7Mcvgv9xSSpfU5g+w= github.com/gin-contrib/expvar v0.0.1/go.mod h1:8o2CznfQi1JjktORdHr2/abg3wSV6OCnXh0yGypvvVw= github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE= @@ -440,8 +451,8 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/ github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= -github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -453,6 +464,8 @@ github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= @@ -460,8 +473,8 @@ github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEai github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= -github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= +github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= +github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -485,19 +498,17 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= +github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-webauthn/webauthn v0.9.1 h1:KuZjvUX9JTuFjB2n7kZhM6n76BClLUFbFM8SLKnrXpo= -github.com/go-webauthn/webauthn v0.9.1/go.mod h1:m315kRGbUljOytw8b9FGWG9QzErjI5v02pNFCF3lwpI= -github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= -github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= +github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g= +github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw= +github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0= +github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -519,8 +530,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= -github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -559,7 +570,6 @@ 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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/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= @@ -593,10 +603,6 @@ github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -613,16 +619,17 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ= @@ -676,21 +683,19 @@ github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= -github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= -github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY= +github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= @@ -700,9 +705,6 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= @@ -711,8 +713,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= +github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -720,7 +722,6 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -733,21 +734,19 @@ github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce h1:7UnVY3T/ZnHUrfv github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU= github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= -github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e h1:pIYdhNkDh+YENVNi3gto8n9hAmRxKxoar0iE6BLucjw= -github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT0oKJ38PylVfqohClLr3CvDC+Qcg+lhU= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.2 h1:TXKcSGc2WaxPD2+bmzAsVthL4+pEN0YwXcL5qED83vk= -github.com/holiman/uint256 v1.2.2/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw= github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= -github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -760,49 +759,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= -github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= -github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= -github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= -github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.5 h1:cwOUcGMLdLPWgu3SlrCckCMznaGADbPqE0r8h768/Dg= -github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= -github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= -github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= -github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= -github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= -github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= -github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= -github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= -github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= -github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= -github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= -github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= -github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs= -github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= -github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= -github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= -github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= -github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= -github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= -github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0= -github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -862,20 +818,9 @@ github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= -github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= -github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= -github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= -github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= -github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= -github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= -github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= -github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= -github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= @@ -905,7 +850,6 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= @@ -925,17 +869,14 @@ github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.2 h1:fL3wAoyT6hXHQlORyXUW4Q23kkQpJRgEAYcZB5BR71o= -github.com/koron/go-ssdp v0.0.2/go.mod h1:XoLfkAiA2KeZsYh4DbHxD7h3nR2AZNqVQOa+LJuqPYs= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -960,211 +901,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= -github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= -github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= -github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= -github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= -github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= -github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= -github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= -github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= -github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= -github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= -github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= -github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= -github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= -github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= -github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= -github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= -github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s= -github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 h1:2H/P+forDWBHije1WULwPfGduByUmC4fthndHVRpYNU= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= -github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= -github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= -github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= -github.com/libp2p/go-libp2p-autonat v0.4.0 h1:3y8XQbpr+ssX8QfZUHekjHCYK64sj6/4hnf/awD4+Ug= -github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= -github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= -github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= -github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= -github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= -github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= -github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= -github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= -github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= -github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= -github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= -github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= -github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= -github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= -github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= -github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= -github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= -github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= -github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= -github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= -github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= -github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= -github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= -github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc= -github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= -github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= -github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= -github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= -github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= -github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= -github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= -github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= -github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= -github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= -github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= -github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= -github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= -github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= -github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= -github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= -github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= -github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= -github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= -github.com/libp2p/go-libp2p-noise v0.1.2 h1:IH9GRihQJTx56obm+GnpdPX4KeVIlvpXrP6xnJ0wxWk= -github.com/libp2p/go-libp2p-noise v0.1.2/go.mod h1:9B10b7ueo7TIxZHHcjcDCo5Hd6kfKT2m77by82SFRfE= -github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= -github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= -github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= -github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= -github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= -github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= -github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= -github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= -github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= -github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= -github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= -github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= -github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= -github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= -github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= -github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= -github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= -github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= -github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= -github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= -github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA= -github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= -github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= -github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= -github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= -github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= -github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= -github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= -github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= -github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s= -github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= -github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= -github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= -github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= -github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= -github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= -github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= -github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0= -github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= -github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= -github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= -github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= -github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= -github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= -github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= -github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= -github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= -github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= -github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.4 h1:47V0+hJfYaqj1WO0A+cDkRc9xr9qKiK7i8zaoGv8Mmo= -github.com/libp2p/go-netroute v0.1.4/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= -github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= -github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= -github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= -github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= -github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= -github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= -github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= -github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0= -github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= -github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= -github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= -github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= -github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= -github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= -github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= -github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= -github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= -github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= -github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= -github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= -github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU= -github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= @@ -1172,7 +910,6 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= @@ -1189,7 +926,6 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -1211,25 +947,13 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -1245,6 +969,9 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1261,66 +988,10 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P 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= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= -github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= -github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= -github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= -github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= -github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= -github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= -github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= -github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= -github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= -github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= -github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= -github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= -github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= -github.com/multiformats/go-multistream v0.2.0 h1:6AuNmQVKUkRnddw2YiDjt5Elit40SFxMJkVnhmETXtU= -github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= @@ -1340,19 +1011,16 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= @@ -1364,7 +1032,6 @@ github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/ github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40= github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= @@ -1383,8 +1050,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= @@ -1430,8 +1097,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.48.0 h1:yrBloImGQ7je4h8M10ujGh4R6oxYQJQKlMuETwNskGk= -github.com/prometheus/prometheus v0.48.0/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= +github.com/prometheus/prometheus v0.48.1 h1:CTszphSNTXkuCG6O0IfpKdHcJkvvnAAE1GbELKS+NFk= +github.com/prometheus/prometheus v0.48.1/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= @@ -1446,8 +1113,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= -github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -1464,8 +1129,8 @@ github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= -github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= +github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= +github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -1486,8 +1151,8 @@ github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08O github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= -github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= +github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= +github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1502,26 +1167,28 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= -github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 h1:qau0/AHvPwMR3p6gWsFWC4qVfEtSEALtBetTOpHA2IU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 h1:xkejUBZhcBpBrTSfxc91Iwzadrb6SXw8ks69bHIQ9Ww= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429/go.mod h1:wJmVvDf4XSjsahWtfUq3wvIAYEAuhr7oxmxYnEL/LGQ= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240124161023-948579cbaffa h1:9g7e1C3295ALDK8Gs42fIKSSJfI+H1RoBmivGWTvIZo= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240124161023-948579cbaffa/go.mod h1:05rRF84QKlIOF5LfTBPkHdw4UpBI2G3zxRcuZ65bPjk= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 h1:NALwENz6vQ972DuD9AZjqRjyNSxH9ptNapizQGLI+2s= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0/go.mod h1:NcVAT/GETDBvIoAej5K6OYqAtDOkF6vO5pYw/hLuYVU= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= +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.20240122152632-38444d2ad8ba h1:6rnQrD8NaLfLOPHszW1hbpviqpU8011gzdZk6wKP1xY= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba/go.mod h1:OZfzyayUdwsVBqxvbEMqwUntQT8HbFbgyqoudvwfVN0= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 h1:KwB0H2P/gxJgt823Ku1fTcFLDKMj6zsP3wbQGlBOm4U= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007/go.mod h1:EbZAlb/2K6mKr26u3+3cLBe/caJaqCHw786On94C43g= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= 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-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= -github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 h1:3y9WsXkZ5lxFrmfH7DQHs/q308lylKId5l/3VC0QAdM= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1/go.mod h1:kC0qmVPUaVkFqGiZMNhmRmjdphuUmeyLEdlWFOQzFWI= 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= @@ -1530,11 +1197,7 @@ github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= 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/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -1542,8 +1205,8 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= @@ -1559,7 +1222,6 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= 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/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1584,7 +1246,9 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= @@ -1623,8 +1287,8 @@ github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= @@ -1637,8 +1301,8 @@ github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFs github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= @@ -1649,15 +1313,6 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= -github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= -github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= -github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= -github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= -github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= 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/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1714,8 +1369,12 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 h1:mMv2jG58h6ZI5t5S9QCVGdzCmAsTakMa3oxVgpSD44g= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1/go.mod h1:oqRuNKG0upTaDPbLVCG8AD0G2ETrfDtmh7jViy7ox6M= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= +go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= +go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= @@ -1737,7 +1396,6 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -1754,8 +1412,6 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 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.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= 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.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -1763,30 +1419,20 @@ 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= golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -1799,9 +1445,9 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y 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.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1847,14 +1493,12 @@ golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1882,8 +1526,8 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -1901,7 +1545,7 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su 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= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1935,24 +1579,19 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1961,7 +1600,6 @@ golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1980,9 +1618,10 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2009,11 +1648,9 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2023,7 +1660,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -2031,7 +1668,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2044,7 +1682,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2054,7 +1693,6 @@ golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -2077,7 +1715,6 @@ golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -2117,7 +1754,6 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= @@ -2155,8 +1791,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= -google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= +google.golang.org/api v0.149.0 h1:b2CqT6kG+zqJIVKRQ3ELJVLN1PwHZ6DJ3dW8yl82rgY= +google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2230,7 +1866,6 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= @@ -2281,17 +1916,11 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= -gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -2340,13 +1969,16 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= -nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/core/scripts/ocr2vrf/main.go b/core/scripts/ocr2vrf/main.go index 532fbd3f22c..e7da4589951 100644 --- a/core/scripts/ocr2vrf/main.go +++ b/core/scripts/ocr2vrf/main.go @@ -364,7 +364,7 @@ func main() { *consumerAddress, uint16(*numWords), decimal.RequireFromString(*subID).BigInt(), - big.NewInt(int64(*confDelay)), + big.NewInt(*confDelay), uint32(*callbackGasLimit), nil, // test consumer doesn't use any args ) @@ -389,7 +389,7 @@ func main() { *consumerAddress, uint16(*numWords), decimal.RequireFromString(*subID).BigInt(), - big.NewInt(int64(*confDelay)), + big.NewInt(*confDelay), uint32(*callbackGasLimit), nil, // test consumer doesn't use any args, big.NewInt(*batchSize), @@ -411,7 +411,7 @@ func main() { *consumerAddress, uint16(*numWords), decimal.RequireFromString(*subID).BigInt(), - big.NewInt(int64(*confDelay)), + big.NewInt(*confDelay), uint32(*callbackGasLimit), nil, // test consumer doesn't use any args, big.NewInt(*batchSize), diff --git a/core/scripts/ocr2vrf/setup_ocr2vrf.go b/core/scripts/ocr2vrf/setup_ocr2vrf.go index ab43dc0180f..1094b823b4e 100644 --- a/core/scripts/ocr2vrf/setup_ocr2vrf.go +++ b/core/scripts/ocr2vrf/setup_ocr2vrf.go @@ -232,9 +232,7 @@ func setupOCR2VRFNodes(e helpers.Environment) { transmitters[i+1] = f.String() } } else { - for _, t := range transmitters[1:] { - nodesToFund = append(nodesToFund, t) - } + nodesToFund = append(nodesToFund, transmitters[1:]...) } var payees []common.Address diff --git a/core/scripts/ocr2vrf/util.go b/core/scripts/ocr2vrf/util.go index 4ec78472e50..e57f349f1fd 100644 --- a/core/scripts/ocr2vrf/util.go +++ b/core/scripts/ocr2vrf/util.go @@ -27,6 +27,7 @@ import ( "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/cmd" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" @@ -35,7 +36,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_coordinator" - "github.com/smartcontractkit/chainlink/v2/core/utils" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" ) @@ -306,14 +306,6 @@ func findSubscriptionID(e helpers.Environment, vrfCoordinatorAddr string) *big.I return subscriptionIterator.Event.SubId } -func registerMigratableCoordinator(e helpers.Environment, coordinatorAddress, migratableCoordinatorAddress string) { - coordinator := newVRFCoordinator(common.HexToAddress(coordinatorAddress), e.Ec) - - tx, err := coordinator.RegisterMigratableCoordinator(e.Owner, common.HexToAddress(migratableCoordinatorAddress)) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - func addConsumer(e helpers.Environment, vrfCoordinatorAddr, consumerAddr string, subId *big.Int) { coordinator := newVRFCoordinator(common.HexToAddress(vrfCoordinatorAddr), e.Ec) @@ -330,34 +322,6 @@ func setPayees(e helpers.Environment, vrfBeaconAddr string, transmitters, payees helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) } -func setBeaconBilling(e helpers.Environment, vrfBeaconAddr string, maximumGasPrice, reasonableGasPrice, observationPayment, - transmissionPayment, accountingGas uint64) { - beacon := newVRFBeacon(common.HexToAddress(vrfBeaconAddr), e.Ec) - - tx, err := beacon.SetBilling(e.Owner, maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, big.NewInt(0).SetUint64(accountingGas)) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - -func setCoordinatorBilling(e helpers.Environment, vrfCoordinatorAddr string, useReasonableGasPrice bool, unusedGasPenaltyPercent uint8, - stalenessSeconds, redeemableRequestGasOverhead, callbackRequestGasOverhead, premiumPercentage, reasonableGasPriceStalenessBlocks uint32, - fallbackWeiPerUnitLink *big.Int) { - coordinator := newVRFCoordinator(common.HexToAddress(vrfCoordinatorAddr), e.Ec) - - tx, err := coordinator.SetCoordinatorConfig(e.Owner, vrf_coordinator.VRFBeaconTypesCoordinatorConfig{ - UseReasonableGasPrice: useReasonableGasPrice, - UnusedGasPenaltyPercent: unusedGasPenaltyPercent, - StalenessSeconds: stalenessSeconds, - RedeemableRequestGasOverhead: redeemableRequestGasOverhead, - CallbackRequestGasOverhead: callbackRequestGasOverhead, - PremiumPercentage: uint8(premiumPercentage), - ReasonableGasPriceStalenessBlocks: reasonableGasPriceStalenessBlocks, - FallbackWeiPerUnitLink: fallbackWeiPerUnitLink, - }) - helpers.PanicErr(err) - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID) -} - func eoaFundSubscription(e helpers.Environment, coordinatorAddress, linkAddress string, amount, subID *big.Int) { linkToken, err := link_token_interface.NewLinkToken(common.HexToAddress(linkAddress), e.Ec) helpers.PanicErr(err) diff --git a/core/scripts/vrfv1/main.go b/core/scripts/vrfv1/main.go index 11af7a0efb2..a281a922a32 100644 --- a/core/scripts/vrfv1/main.go +++ b/core/scripts/vrfv1/main.go @@ -15,6 +15,7 @@ import ( "github.com/shopspring/decimal" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" + evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" linktoken "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" @@ -203,7 +204,7 @@ func main() { } link, err := linktoken.NewLinkToken(common.HexToAddress(*linkAddr), e.Ec) helpers.PanicErr(err) - data, err := utils.ABIEncode(`[{"type":"bytes32"}]`, common.HexToHash(*keyHash)) + data, err := evmutils.ABIEncode(`[{"type":"bytes32"}]`, common.HexToHash(*keyHash)) helpers.PanicErr(err) tx, err := link.TransferAndCall(e.Owner, common.HexToAddress(*consumerAddr), payment, data) helpers.PanicErr(err) diff --git a/core/scripts/vrfv2/genvrfnum/main.go b/core/scripts/vrfv2/genvrfnum/main.go index cdd120167f7..606ac7f3443 100644 --- a/core/scripts/vrfv2/genvrfnum/main.go +++ b/core/scripts/vrfv2/genvrfnum/main.go @@ -16,6 +16,7 @@ import ( "github.com/shopspring/decimal" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" + evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" @@ -227,7 +228,7 @@ func main() { } func preseed(keyHash common.Hash, sender common.Address, subID, nonce uint64) [32]byte { - encoded, err := utils.ABIEncode( + encoded, err := evmutils.ABIEncode( `[{"type":"bytes32"}, {"type":"address"}, {"type":"uint64"}, {"type", "uint64"}]`, keyHash, sender, diff --git a/core/scripts/vrfv2/testnet/main.go b/core/scripts/vrfv2/testnet/main.go index 5856256504b..34070c90d8a 100644 --- a/core/scripts/vrfv2/testnet/main.go +++ b/core/scripts/vrfv2/testnet/main.go @@ -10,6 +10,7 @@ import ( "math/big" "os" "strings" + "sync" "github.com/smartcontractkit/chainlink/core/scripts/vrfv2/testnet/v2scripts" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner_test_consumer" @@ -26,6 +27,7 @@ import ( helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" 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/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" @@ -720,14 +722,19 @@ func main() { case "eoa-vrf-owner-test-consumer-deploy": loadTestConsumerDeployCmd := flag.NewFlagSet("eoa-vrf-owner-test-consumer-deploy", flag.ExitOnError) consumerCoordinator := loadTestConsumerDeployCmd.String("coordinator-address", "", "coordinator address") - helpers.ParseArgs(loadTestConsumerDeployCmd, os.Args[2:], "coordinator-address") + consumerLinkAddress := loadTestConsumerDeployCmd.String("link-address", "", "link-address") + + helpers.ParseArgs(loadTestConsumerDeployCmd, os.Args[2:], "coordinator-address", "link-address") + _, tx, _, err := vrf_owner_test_consumer.DeployVRFV2OwnerTestConsumer( e.Owner, e.Ec, common.HexToAddress(*consumerCoordinator), + common.HexToAddress(*consumerLinkAddress), ) helpers.PanicErr(err) helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) + case "eoa-create-sub": createSubCmd := flag.NewFlagSet("eoa-create-sub", flag.ExitOnError) coordinatorAddress := createSubCmd.String("coordinator-address", "", "coordinator address") @@ -743,7 +750,7 @@ func main() { helpers.ParseArgs(addSubConsCmd, os.Args[2:], "coordinator-address", "sub-id", "consumer-address") coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(common.HexToAddress(*coordinatorAddress), e.Ec) helpers.PanicErr(err) - v2scripts.EoaAddConsumerToSub(e, *coordinator, uint64(*subID), *consumerAddress) + v2scripts.EoaAddConsumerToSub(e, *coordinator, *subID, *consumerAddress) case "eoa-create-fund-authorize-sub": // Lets just treat the owner key as the EOA controlling the sub cfaSubCmd := flag.NewFlagSet("eoa-create-fund-authorize-sub", flag.ExitOnError) @@ -773,7 +780,7 @@ func main() { bal, err := linkToken.BalanceOf(nil, e.Owner.From) helpers.PanicErr(err) fmt.Println("OWNER BALANCE", bal, e.Owner.From.String(), amount.String()) - b, err := utils.ABIEncode(`[{"type":"uint64"}]`, created.SubId) + b, err := evmutils.ABIEncode(`[{"type":"uint64"}]`, created.SubId) helpers.PanicErr(err) e.Owner.GasLimit = 500000 tx, err := linkToken.TransferAndCall(e.Owner, coordinator.Address(), amount, b) @@ -852,57 +859,103 @@ func main() { keyHash := request.String("key-hash", "", "key hash") cbGasLimit := request.Uint("cb-gas-limit", 100_000, "request callback gas limit") numWords := request.Uint("num-words", 1, "num words to request") - requests := request.Uint("requests", 10, "number of randomness requests to make per run") + requests := request.Uint("requests", 1, "number of randomness requests to make per run") runs := request.Uint("runs", 1, "number of runs to do. total randomness requests will be (requests * runs).") + subFundingAmountJuels := request.String("sub-funding-amount-juels", "0", "amount of Juels to fund subscription with") + vrfOwnerAddress := request.String("vrf-owner-address", "", "vrf owner address") + linkAddress := request.String("link-address", "", "link-address") + helpers.ParseArgs(request, os.Args[2:], "consumer-address", "key-hash") keyHashBytes := common.HexToHash(*keyHash) + link, err := link_token_interface.NewLinkToken(common.HexToAddress(*linkAddress), e.Ec) + helpers.PanicErr(err) + + linkTransferTX, err := link.Transfer(e.Owner, common.HexToAddress(*consumerAddress), decimal.RequireFromString(*subFundingAmountJuels).BigInt()) + helpers.PanicErr(err) + helpers.ConfirmTXMined(context.Background(), e.Ec, linkTransferTX, e.ChainID, "transfer", *subFundingAmountJuels, "juels to", *consumerAddress) + + consumerBalanceJuels, err := link.BalanceOf(nil, common.HexToAddress(*consumerAddress)) + helpers.PanicErr(err) + fmt.Println("Consumer Balance:", consumerBalanceJuels.String(), "juels") + consumer, err := vrf_owner_test_consumer.NewVRFV2OwnerTestConsumer( common.HexToAddress(*consumerAddress), e.Ec) helpers.PanicErr(err) var txes []*types.Transaction for i := 0; i < int(*runs); i++ { - tx, err := consumer.RequestRandomWords( + requestRandTX, errRequestRandomWords := consumer.RequestRandomWords( e.Owner, uint16(*requestConfirmations), keyHashBytes, uint32(*cbGasLimit), uint32(*numWords), uint16(*requests), + decimal.RequireFromString(*subFundingAmountJuels).BigInt(), ) - helpers.PanicErr(err) - fmt.Printf("TX %d: %s\n", i+1, helpers.ExplorerLink(e.ChainID, tx.Hash())) - txes = append(txes, tx) + helpers.PanicErr(errRequestRandomWords) + fmt.Printf("TX %d: %s\n", i+1, helpers.ExplorerLink(e.ChainID, requestRandTX.Hash())) + txes = append(txes, requestRandTX) } - fmt.Println("Total number of requests sent:", (*requests)*(*runs)) + + coordinatorAddress, err := consumer.COORDINATOR(nil) + helpers.PanicErr(err) + coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(coordinatorAddress, e.Ec) + helpers.PanicErr(err) + + coordinatorOwnerAddress, err := coordinator.Owner(nil) + helpers.PanicErr(err) + + fmt.Println("Actual Coordinator Owner Address:", coordinatorOwnerAddress.String()) + fmt.Println("Provided VRF Owner Address:", *vrfOwnerAddress) + if coordinatorOwnerAddress.String() != *vrfOwnerAddress { + panic("Actual Coordinator Owner and provided Coordinator Owner Addresses does not match") + } + + var subId uint64 + var wg sync.WaitGroup + + wg.Add(1) + + go func() { + subCreatedChan := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated) + subCreatedSubscription, errw := coordinator.WatchSubscriptionCreated(nil, subCreatedChan, nil) + helpers.PanicErr(errw) + defer subCreatedSubscription.Unsubscribe() + subscriptionCreatedEvent := <-subCreatedChan + subId = subscriptionCreatedEvent.SubId + fmt.Println("VRF Owner Test Consumer's Sub ID:", subId) + defer wg.Done() + }() + + wg.Wait() + + totalNumberOfRequests := (*requests) * (*runs) + fmt.Println("Total number of requests sent:", totalNumberOfRequests) fmt.Println("fetching receipts for all transactions") + + var receipt *types.Receipt for i, tx := range txes { - helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, fmt.Sprintf("load test %d", i+1)) + receipt = helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, fmt.Sprintf("load test %d", i+1)) } + blockNumber := receipt.BlockNumber.Uint64() + fmt.Println("subId", subId) + subFundedIterator, err := coordinator.FilterSubscriptionFunded(&bind.FilterOpts{End: &blockNumber}, []uint64{subId}) + helpers.PanicErr(err) + + if !subFundedIterator.Next() { + panic("Sub Funded Event not found") + } + + fmt.Println("Sub Funded, sub ID:", subFundedIterator.Event.SubId, ", Old Balance:", subFundedIterator.Event.OldBalance, ", New Balance:", subFundedIterator.Event.NewBalance) case "eoa-vrf-owner-test-read-metrics": request := flag.NewFlagSet("eoa-load-test-read-metrics", flag.ExitOnError) consumerAddress := request.String("consumer-address", "", "consumer address") helpers.ParseArgs(request, os.Args[2:], "consumer-address") - consumer, err := vrf_owner_test_consumer.NewVRFV2OwnerTestConsumer( - common.HexToAddress(*consumerAddress), - e.Ec) - helpers.PanicErr(err) - responseCount, err := consumer.SResponseCount(nil) - helpers.PanicErr(err) - fmt.Println("Response Count: ", responseCount) - requestCount, err := consumer.SRequestCount(nil) - helpers.PanicErr(err) - fmt.Println("Request Count: ", requestCount) - averageFulfillmentInMillions, err := consumer.SAverageFulfillmentInMillions(nil) - helpers.PanicErr(err) - fmt.Println("Average Fulfillment In Millions: ", averageFulfillmentInMillions) - slowestFulfillment, err := consumer.SSlowestFulfillment(nil) - helpers.PanicErr(err) - fmt.Println("Slowest Fulfillment: ", slowestFulfillment) - fastestFulfillment, err := consumer.SFastestFulfillment(nil) - helpers.PanicErr(err) - fmt.Println("Fastest Fulfillment: ", fastestFulfillment) + metrics := getVRFOwnerTestConsumerMetrics(*consumerAddress, e) + printLoadTestMetrics(metrics) + case "eoa-vrf-owner-test-reset-metrics": request := flag.NewFlagSet("eoa-vrf-owner-test-reset-metrics", flag.ExitOnError) consumerAddress := request.String("consumer-address", "", "consumer address") @@ -1088,9 +1141,8 @@ func main() { return true } else if strings.Contains(err.Error(), "execution reverted") { return false - } else { - panic(err) } + panic(err) } result := helpers.BinarySearch(assets.Ether(int64(*start*2)).ToInt(), big.NewInt(0), isWithdrawable) @@ -1352,3 +1404,45 @@ func main() { panic("unrecognized subcommand: " + os.Args[1]) } } + +func getVRFOwnerTestConsumerMetrics(consumerAddress string, e helpers.Environment) LoadTestMetrics { + consumer, err := vrf_owner_test_consumer.NewVRFV2OwnerTestConsumer( + common.HexToAddress(consumerAddress), + e.Ec) + helpers.PanicErr(err) + responseCount, err := consumer.SResponseCount(nil) + helpers.PanicErr(err) + requestCount, err := consumer.SRequestCount(nil) + helpers.PanicErr(err) + averageFulfillmentInMillions, err := consumer.SAverageFulfillmentInMillions(nil) + helpers.PanicErr(err) + slowestFulfillment, err := consumer.SSlowestFulfillment(nil) + helpers.PanicErr(err) + fastestFulfillment, err := consumer.SFastestFulfillment(nil) + helpers.PanicErr(err) + + metrics := LoadTestMetrics{ + ResponseCount: responseCount, + RequestCount: requestCount, + AverageFulfillmentInMillions: averageFulfillmentInMillions, + SlowestFulfillment: slowestFulfillment, + FastestFulfillment: fastestFulfillment, + } + return metrics +} + +func printLoadTestMetrics(metrics LoadTestMetrics) { + fmt.Println("Response Count: ", metrics.ResponseCount) + fmt.Println("Request Count: ", metrics.RequestCount) + fmt.Println("Average Fulfillment In Millions: ", metrics.AverageFulfillmentInMillions) + fmt.Println("Slowest Fulfillment: ", metrics.SlowestFulfillment) + fmt.Println("Fastest Fulfillment: ", metrics.FastestFulfillment) +} + +type LoadTestMetrics struct { + ResponseCount *big.Int + RequestCount *big.Int + AverageFulfillmentInMillions *big.Int + SlowestFulfillment *big.Int + FastestFulfillment *big.Int +} diff --git a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go index 4a1c1fcec41..1397274656c 100644 --- a/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go +++ b/core/scripts/vrfv2/testnet/v2scripts/super_scripts.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/core/scripts/common/vrf/util" evmtypes "github.com/ethereum/go-ethereum/core/types" + helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" @@ -51,8 +52,14 @@ func DeployUniverseViaCLI(e helpers.Environment) { nodeSendingKeyFundingAmount := deployCmd.String("sending-key-funding-amount", constants.NodeSendingKeyFundingAmount, "CL node sending key funding amount") batchFulfillmentEnabled := deployCmd.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether send randomness fulfillments in batches inside one tx from CL node") + batchFulfillmentGasMultiplier := deployCmd.Float64("batch-fulfillment-gas-multiplier", 1.1, "") + estimateGasMultiplier := deployCmd.Float64("estimate-gas-multiplier", 1.1, "") + pollPeriod := deployCmd.String("poll-period", "300ms", "") + requestTimeout := deployCmd.String("request-timeout", "30m0s", "") + revertsPipelineEnabled := deployCmd.Bool("reverts-pipeline-enabled", true, "") - deployVRFOwner := deployCmd.Bool("deploy-vrf-owner", false, "whether to deploy VRF owner contracts") + deployVRFOwner := deployCmd.Bool("deploy-vrf-owner", true, "whether to deploy VRF owner contracts") + useTestCoordinator := deployCmd.Bool("use-test-coordinator", true, "whether to use test coordinator") // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", constants.FallbackWeiPerUnitLink.String(), "fallback wei/link ratio") @@ -136,15 +143,25 @@ func DeployUniverseViaCLI(e helpers.Environment) { RegisterAgainstAddress: *registerVRFKeyAgainstAddress, } + coordinatorJobSpecConfig := model.CoordinatorJobSpecConfig{ + BatchFulfillmentEnabled: *batchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *batchFulfillmentGasMultiplier, + EstimateGasMultiplier: *estimateGasMultiplier, + PollPeriod: *pollPeriod, + RequestTimeout: *requestTimeout, + RevertsPipelineEnabled: *revertsPipelineEnabled, + } + VRFV2DeployUniverse( e, subscriptionBalanceJuels, vrfKeyRegistrationConfig, contractAddresses, coordinatorConfig, - *batchFulfillmentEnabled, nodesMap, *deployVRFOwner, + coordinatorJobSpecConfig, + *useTestCoordinator, ) vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] @@ -160,9 +177,10 @@ func VRFV2DeployUniverse( vrfKeyRegistrationConfig model.VRFKeyRegistrationConfig, contractAddresses model.ContractAddresses, coordinatorConfig CoordinatorConfigV2, - batchFulfillmentEnabled bool, nodesMap map[string]model.Node, deployVRFOwner bool, + coordinatorJobSpecConfig model.CoordinatorJobSpecConfig, + useTestCoordinator bool, ) model.JobSpecs { var compressedPkHex string var keyHash common.Hash @@ -211,9 +229,16 @@ func VRFV2DeployUniverse( contractAddresses.BatchBHSAddress = DeployBatchBHS(e, contractAddresses.BhsContractAddress) } - if contractAddresses.CoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { - fmt.Println("\nDeploying Coordinator...") - contractAddresses.CoordinatorAddress = DeployCoordinator(e, contractAddresses.LinkAddress, contractAddresses.BhsContractAddress.String(), contractAddresses.LinkEthAddress) + if useTestCoordinator { + if contractAddresses.CoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { + fmt.Println("\nDeploying Test Coordinator...") + contractAddresses.CoordinatorAddress = DeployTestCoordinator(e, contractAddresses.LinkAddress, contractAddresses.BhsContractAddress.String(), contractAddresses.LinkEthAddress) + } + } else { + if contractAddresses.CoordinatorAddress.String() == "0x0000000000000000000000000000000000000000" { + fmt.Println("\nDeploying Coordinator...") + contractAddresses.CoordinatorAddress = DeployCoordinator(e, contractAddresses.LinkAddress, contractAddresses.BhsContractAddress.String(), contractAddresses.LinkEthAddress) + } } coordinator, err := vrf_coordinator_v2.NewVRFCoordinatorV2(contractAddresses.CoordinatorAddress, e.Ec) @@ -297,7 +322,7 @@ func VRFV2DeployUniverse( tx, err := vrfOwner.SetAuthorizedSenders(e.Owner, authorizedSendersSlice) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "vrf owner set authorized senders") - fmt.Printf("\nTransfering ownership of coordinator: %v, VRF Owner %v\n", contractAddresses.CoordinatorAddress, vrfOwnerAddress.String()) + fmt.Printf("\nTransferring ownership of coordinator: %v, VRF Owner %v\n", contractAddresses.CoordinatorAddress, vrfOwnerAddress.String()) tx, err = coordinator.TransferOwnership(e.Owner, vrfOwnerAddress) helpers.PanicErr(err) helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "transfer ownership to", vrfOwnerAddress.String()) @@ -309,20 +334,24 @@ func VRFV2DeployUniverse( formattedVrfPrimaryJobSpec := fmt.Sprintf( jobs.VRFV2JobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress - batchFulfillmentEnabled, //batchFulfillmentEnabled - compressedPkHex, //publicKey - coordinatorConfig.MinConfs, //minIncomingConfirmations - e.ChainID, //evmChainID + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + coordinatorJobSpecConfig.BatchFulfillmentEnabled, //batchFulfillmentEnabled + coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, //batchFulfillmentGasMultiplier + coordinatorJobSpecConfig.RevertsPipelineEnabled, //revertsPipelineEnabled + compressedPkHex, //publicKey + coordinatorConfig.MinConfs, //minIncomingConfirmations + e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses + coordinatorJobSpecConfig.PollPeriod, //pollPeriod + coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, + coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address - } else { - return common.HexToAddress("0x0").String() } + return common.HexToAddress("0x0").String() }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, @@ -336,20 +365,24 @@ func VRFV2DeployUniverse( formattedVrfBackupJobSpec := fmt.Sprintf( jobs.VRFV2JobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress - batchFulfillmentEnabled, //batchFulfillmentEnabled - compressedPkHex, //publicKey - 100, //minIncomingConfirmations - e.ChainID, //evmChainID + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + coordinatorJobSpecConfig.BatchFulfillmentEnabled, //batchFulfillmentEnabled + coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, //batchFulfillmentGasMultiplier + coordinatorJobSpecConfig.RevertsPipelineEnabled, //revertsPipelineEnabled + compressedPkHex, //publicKey + 100, //minIncomingConfirmations + e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses + coordinatorJobSpecConfig.PollPeriod, //pollPeriod + coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, + coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address - } else { - return common.HexToAddress("0x0").String() } + return common.HexToAddress("0x0").String() }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, diff --git a/core/scripts/vrfv2/testnet/v2scripts/util.go b/core/scripts/vrfv2/testnet/v2scripts/util.go index 94e381378bb..325ced2ab21 100644 --- a/core/scripts/vrfv2/testnet/v2scripts/util.go +++ b/core/scripts/vrfv2/testnet/v2scripts/util.go @@ -7,6 +7,8 @@ import ( "fmt" "math/big" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_test_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" "github.com/ethereum/go-ethereum/common" @@ -14,15 +16,14 @@ import ( "github.com/ethereum/go-ethereum/crypto" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_external_sub_owner_example" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper_consumer_example" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func DeployBHS(e helpers.Environment) (blockhashStoreAddress common.Address) { @@ -53,6 +54,22 @@ func DeployCoordinator( return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) } +func DeployTestCoordinator( + e helpers.Environment, + linkAddress string, + bhsAddress string, + linkEthAddress string, +) (coordinatorAddress common.Address) { + _, tx, _, err := vrf_coordinator_test_v2.DeployVRFCoordinatorTestV2( + e.Owner, + e.Ec, + common.HexToAddress(linkAddress), + common.HexToAddress(bhsAddress), + common.HexToAddress(linkEthAddress)) + helpers.PanicErr(err) + return helpers.ConfirmContractDeployed(context.Background(), e.Ec, tx, e.ChainID) +} + func DeployBatchCoordinatorV2(e helpers.Environment, coordinatorAddress common.Address) (batchCoordinatorAddress common.Address) { _, tx, _, err := batch_vrf_coordinator_v2.DeployBatchVRFCoordinatorV2(e.Owner, e.Ec, coordinatorAddress) helpers.PanicErr(err) diff --git a/core/scripts/vrfv2plus/testnet/main.go b/core/scripts/vrfv2plus/testnet/main.go index 6b1ef585a5a..320576055b5 100644 --- a/core/scripts/vrfv2plus/testnet/main.go +++ b/core/scripts/vrfv2plus/testnet/main.go @@ -31,6 +31,7 @@ import ( helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" 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/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2plus" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" @@ -563,7 +564,6 @@ func main() { coordinatorRegisterKey := flag.NewFlagSet("coordinator-register-key", flag.ExitOnError) registerKeyAddress := coordinatorRegisterKey.String("address", "", "coordinator address") registerKeyUncompressedPubKey := coordinatorRegisterKey.String("pubkey", "", "uncompressed pubkey") - registerKeyOracleAddress := coordinatorRegisterKey.String("oracle-address", "", "oracle address") helpers.ParseArgs(coordinatorRegisterKey, os.Args[2:], "address", "pubkey", "oracle-address") coordinator, err := vrf_coordinator_v2_5.NewVRFCoordinatorV25(common.HexToAddress(*registerKeyAddress), e.Ec) helpers.PanicErr(err) @@ -573,7 +573,7 @@ func main() { *registerKeyUncompressedPubKey = strings.Replace(*registerKeyUncompressedPubKey, "0x", "04", 1) } - v2plusscripts.RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey, *registerKeyOracleAddress) + v2plusscripts.RegisterCoordinatorProvingKey(e, *coordinator, *registerKeyUncompressedPubKey) case "coordinator-deregister-key": coordinatorDeregisterKey := flag.NewFlagSet("coordinator-deregister-key", flag.ExitOnError) deregisterKeyAddress := coordinatorDeregisterKey.String("address", "", "coordinator address") @@ -784,7 +784,7 @@ func main() { bal, err := linkToken.BalanceOf(nil, e.Owner.From) helpers.PanicErr(err) fmt.Println("OWNER BALANCE", bal, e.Owner.From.String(), amount.String()) - b, err := utils.ABIEncode(`[{"type":"uint64"}]`, created.SubId) + b, err := evmutils.ABIEncode(`[{"type":"uint64"}]`, created.SubId) helpers.PanicErr(err) e.Owner.GasLimit = 500000 tx, err := linkToken.TransferAndCall(e.Owner, coordinator.Address(), amount, b) @@ -1046,9 +1046,8 @@ func main() { return true } else if strings.Contains(err.Error(), "execution reverted") { return false - } else { - panic(err) } + panic(err) } result := helpers.BinarySearch(assets.Ether(int64(*start*2)).ToInt(), big.NewInt(0), isWithdrawable) @@ -1071,7 +1070,6 @@ func main() { coordinatorReregisterKey := flag.NewFlagSet("coordinator-register-key", flag.ExitOnError) coordinatorAddress := coordinatorReregisterKey.String("coordinator-address", "", "coordinator address") uncompressedPubKey := coordinatorReregisterKey.String("pubkey", "", "uncompressed pubkey") - newOracleAddress := coordinatorReregisterKey.String("new-oracle-address", "", "oracle address") skipDeregister := coordinatorReregisterKey.Bool("skip-deregister", false, "if true, key will not be deregistered") helpers.ParseArgs(coordinatorReregisterKey, os.Args[2:], "coordinator-address", "pubkey", "new-oracle-address") @@ -1097,7 +1095,6 @@ func main() { // Use a higher gas price for the register call e.Owner.GasPrice.Mul(e.Owner.GasPrice, big.NewInt(2)) registerTx, err := coordinator.RegisterProvingKey(e.Owner, - common.HexToAddress(*newOracleAddress), [2]*big.Int{pk.X, pk.Y}) helpers.PanicErr(err) fmt.Println("Register transaction", helpers.ExplorerLink(e.ChainID, registerTx.Hash())) diff --git a/core/scripts/vrfv2plus/testnet/proofs.go b/core/scripts/vrfv2plus/testnet/proofs.go index 126ac2d6c5a..306d237caf4 100644 --- a/core/scripts/vrfv2plus/testnet/proofs.go +++ b/core/scripts/vrfv2plus/testnet/proofs.go @@ -11,13 +11,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/shopspring/decimal" + helpers "github.com/smartcontractkit/chainlink/core/scripts/common" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/extraargs" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" ) -var vrfProofTemplate string = `{ +var vrfProofTemplate = `{ pk: [ %s, %s @@ -42,7 +43,7 @@ var vrfProofTemplate string = `{ } ` -var rcTemplate string = `{ +var rcTemplate = `{ blockNum: %d, subId: %d, callbackGasLimit: %d, diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go index 50584d885a2..09c93ff879b 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/super_scripts.go @@ -196,15 +196,15 @@ func SmokeTestVRF(e helpers.Environment) { x, y := secp256k1.Coordinates(point) fmt.Println("proving key points x:", x, ", y:", y) fmt.Println("proving key points from unmarshal:", pk.X, pk.Y) - tx, err := coordinator.RegisterProvingKey(e.Owner, e.Owner.From, [2]*big.Int{x, y}) + tx, err := coordinator.RegisterProvingKey(e.Owner, [2]*big.Int{x, y}) helpers.PanicErr(err) registerReceipt := helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "register proving key on", coordinatorAddress.String()) var provingKeyRegisteredLog *vrf_coordinator_v2_5.VRFCoordinatorV25ProvingKeyRegistered for _, log := range registerReceipt.Logs { if log.Address == coordinatorAddress { - var err error - provingKeyRegisteredLog, err = coordinator.ParseProvingKeyRegistered(*log) - if err != nil { + var err2 error + provingKeyRegisteredLog, err2 = coordinator.ParseProvingKeyRegistered(*log) + if err2 != nil { continue } } @@ -214,9 +214,8 @@ func SmokeTestVRF(e helpers.Environment) { } if !bytes.Equal(provingKeyRegisteredLog.KeyHash[:], keyHash[:]) { panic(fmt.Sprintf("unexpected key hash registered %s, expected %s", hexutil.Encode(provingKeyRegisteredLog.KeyHash[:]), hexutil.Encode(keyHash[:]))) - } else { - fmt.Println("key hash registered:", hexutil.Encode(provingKeyRegisteredLog.KeyHash[:])) } + fmt.Println("key hash registered:", hexutil.Encode(provingKeyRegisteredLog.KeyHash[:])) fmt.Println("\nProving key registered, getting proving key hashes from deployed contract...") _, _, provingKeyHashes, configErr := coordinator.GetRequestConfig(nil) @@ -268,6 +267,7 @@ func SmokeTestVRF(e helpers.Environment) { consumer, err := vrf_v2plus_sub_owner.NewVRFV2PlusExternalSubOwnerExample(consumerAddress, e.Ec) helpers.PanicErr(err) tx, err = consumer.RequestRandomWords(e.Owner, subID, 100_000, 3, 3, provingKeyRegisteredLog.KeyHash, false) + helpers.PanicErr(err) receipt := helpers.ConfirmTXMined(context.Background(), e.Ec, tx, e.ChainID, "request random words from", consumerAddress.String()) fmt.Println("request blockhash:", receipt.BlockHash) @@ -275,9 +275,9 @@ func SmokeTestVRF(e helpers.Environment) { var rwrLog *vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsRequested for _, log := range receipt.Logs { if log.Address == coordinatorAddress { - var err error - rwrLog, err = coordinator.ParseRandomWordsRequested(*log) - if err != nil { + var err2 error + rwrLog, err2 = coordinator.ParseRandomWordsRequested(*log) + if err2 != nil { continue } } @@ -396,13 +396,13 @@ func SmokeTestBHS(e helpers.Environment) { if seReceipt.Status != 1 { fmt.Println("storeEarliest failed") os.Exit(1) - } else { - fmt.Println("storeEarliest succeeded, checking BH is there") - bh, err := bhs.GetBlockhash(nil, seReceipt.BlockNumber.Sub(seReceipt.BlockNumber, big.NewInt(256))) - helpers.PanicErr(err) - fmt.Println("blockhash stored by storeEarliest:", hexutil.Encode(bh[:])) - anchorBlockNumber = seReceipt.BlockNumber } + fmt.Println("storeEarliest succeeded, checking BH is there") + bh, err := bhs.GetBlockhash(nil, seReceipt.BlockNumber.Sub(seReceipt.BlockNumber, big.NewInt(256))) + helpers.PanicErr(err) + fmt.Println("blockhash stored by storeEarliest:", hexutil.Encode(bh[:])) + anchorBlockNumber = seReceipt.BlockNumber + if anchorBlockNumber == nil { panic("no anchor block number") } @@ -417,12 +417,11 @@ func SmokeTestBHS(e helpers.Environment) { if sReceipt.Status != 1 { fmt.Println("store failed") os.Exit(1) - } else { - fmt.Println("store succeeded, checking BH is there") - bh, err := bhs.GetBlockhash(nil, toStore) - helpers.PanicErr(err) - fmt.Println("blockhash stored by store:", hexutil.Encode(bh[:])) } + fmt.Println("store succeeded, checking BH is there") + bh, err = bhs.GetBlockhash(nil, toStore) + helpers.PanicErr(err) + fmt.Println("blockhash stored by store:", hexutil.Encode(bh[:])) fmt.Println("\nexecuting storeVerifyHeader") headers, _, err := helpers.GetRlpHeaders(e, []*big.Int{anchorBlockNumber}, false) @@ -435,12 +434,11 @@ func SmokeTestBHS(e helpers.Environment) { if svhReceipt.Status != 1 { fmt.Println("storeVerifyHeader failed") os.Exit(1) - } else { - fmt.Println("storeVerifyHeader succeeded, checking BH is there") - bh, err := bhs.GetBlockhash(nil, toStore) - helpers.PanicErr(err) - fmt.Println("blockhash stored by storeVerifyHeader:", hexutil.Encode(bh[:])) } + fmt.Println("storeVerifyHeader succeeded, checking BH is there") + bh, err = bhs.GetBlockhash(nil, toStore) + helpers.PanicErr(err) + fmt.Println("blockhash stored by storeVerifyHeader:", hexutil.Encode(bh[:])) } func sendTx(e helpers.Environment, to common.Address, data []byte) (*types.Receipt, common.Hash) { @@ -478,12 +476,14 @@ func DeployUniverseViaCLI(e helpers.Environment) { subscriptionBalanceNativeWeiString := deployCmd.String("subscription-balance-native", "1e18", "amount to fund subscription with native token (Wei)") batchFulfillmentEnabled := deployCmd.Bool("batch-fulfillment-enabled", constants.BatchFulfillmentEnabled, "whether send randomness fulfillments in batches inside one tx from CL node") + batchFulfillmentGasMultiplier := deployCmd.Float64("batch-fulfillment-gas-multiplier", 1.1, "") + estimateGasMultiplier := deployCmd.Float64("estimate-gas-multiplier", 1.1, "") + pollPeriod := deployCmd.String("poll-period", "300ms", "") + requestTimeout := deployCmd.String("request-timeout", "30m0s", "") // optional flags fallbackWeiPerUnitLinkString := deployCmd.String("fallback-wei-per-unit-link", "6e16", "fallback wei/link ratio") registerVRFKeyUncompressedPubKey := deployCmd.String("uncompressed-pub-key", "", "uncompressed public key") - registerVRFKeyAgainstAddress := deployCmd.String("register-vrf-key-against-address", "", "VRF Key registration against address - "+ - "from this address you can perform `coordinator.oracleWithdraw` to withdraw earned funds from rand request fulfilments") vrfPrimaryNodeSendingKeysString := deployCmd.String("vrf-primary-node-sending-keys", "", "VRF Primary Node sending keys") minConfs := deployCmd.Int("min-confs", constants.MinConfs, "min confs") @@ -501,7 +501,6 @@ func DeployUniverseViaCLI(e helpers.Environment) { fallbackWeiPerUnitLink := decimal.RequireFromString(*fallbackWeiPerUnitLinkString).BigInt() subscriptionBalanceJuels := decimal.RequireFromString(*subscriptionBalanceJuelsString).BigInt() subscriptionBalanceNativeWei := decimal.RequireFromString(*subscriptionBalanceNativeWeiString).BigInt() - fundingAmount := decimal.RequireFromString(*nodeSendingKeyFundingAmount).BigInt() feeConfig := vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ FulfillmentFlatFeeLinkPPM: uint32(*flatFeeLinkPPM), @@ -515,10 +514,7 @@ func DeployUniverseViaCLI(e helpers.Environment) { nodesMap := make(map[string]model.Node) - fundingAmount, ok := new(big.Int).SetString(*nodeSendingKeyFundingAmount, 10) - if !ok { - panic(fmt.Sprintf("failed to parse node sending key funding amount '%s'", *nodeSendingKeyFundingAmount)) - } + fundingAmount := decimal.RequireFromString(*nodeSendingKeyFundingAmount).BigInt() nodesMap[model.VRFPrimaryNodeName] = model.Node{ SendingKeys: util.MapToSendingKeyArr(vrfPrimaryNodeSendingKeys), SendingKeyFundingAmount: fundingAmount, @@ -549,7 +545,14 @@ func DeployUniverseViaCLI(e helpers.Environment) { vrfKeyRegistrationConfig := model.VRFKeyRegistrationConfig{ VRFKeyUncompressedPubKey: *registerVRFKeyUncompressedPubKey, - RegisterAgainstAddress: *registerVRFKeyAgainstAddress, + } + + coordinatorJobSpecConfig := model.CoordinatorJobSpecConfig{ + BatchFulfillmentEnabled: *batchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: *batchFulfillmentGasMultiplier, + EstimateGasMultiplier: *estimateGasMultiplier, + PollPeriod: *pollPeriod, + RequestTimeout: *requestTimeout, } VRFV2PlusDeployUniverse( @@ -559,8 +562,8 @@ func DeployUniverseViaCLI(e helpers.Environment) { vrfKeyRegistrationConfig, contractAddresses, coordinatorConfig, - *batchFulfillmentEnabled, nodesMap, + coordinatorJobSpecConfig, ) vrfPrimaryNode := nodesMap[model.VRFPrimaryNodeName] @@ -576,8 +579,8 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, vrfKeyRegistrationConfig model.VRFKeyRegistrationConfig, contractAddresses model.ContractAddresses, coordinatorConfig CoordinatorConfigV2Plus, - batchFulfillmentEnabled bool, nodesMap map[string]model.Node, + coordinatorJobSpecConfig model.CoordinatorJobSpecConfig, ) model.JobSpecs { var compressedPkHex string var keyHash common.Hash @@ -659,7 +662,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, //NOTE - register proving key against EOA account, and not against Oracle's sending address in other to be able // easily withdraw funds from Coordinator contract back to EOA account - RegisterCoordinatorProvingKey(e, *coordinator, vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey, vrfKeyRegistrationConfig.RegisterAgainstAddress) + RegisterCoordinatorProvingKey(e, *coordinator, vrfKeyRegistrationConfig.VRFKeyUncompressedPubKey) fmt.Println("\nProving key registered, getting proving key hashes from deployed contract...") _, _, provingKeyHashes, configErr := coordinator.GetRequestConfig(nil) @@ -701,20 +704,24 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, formattedVrfV2PlusPrimaryJobSpec := fmt.Sprintf( jobs.VRFV2PlusJobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress - batchFulfillmentEnabled, //batchFulfillmentEnabled - compressedPkHex, //publicKey - coordinatorConfig.MinConfs, //minIncomingConfirmations - e.ChainID, //evmChainID + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + coordinatorJobSpecConfig.BatchFulfillmentEnabled, //batchFulfillmentEnabled + coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, //batchFulfillmentGasMultiplier + strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses + compressedPkHex, //publicKey + coordinatorConfig.MinConfs, //minIncomingConfirmations + e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFPrimaryNodeName].SendingKeys), "\",\""), //fromAddresses + coordinatorJobSpecConfig.PollPeriod, //pollPeriod + coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, + coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address - } else { - return common.HexToAddress("0x0").String() } + return common.HexToAddress("0x0").String() }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, @@ -722,27 +729,30 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, formattedVrfV2PlusBackupJobSpec := fmt.Sprintf( jobs.VRFV2PlusJobFormatted, - contractAddresses.CoordinatorAddress, //coordinatorAddress - contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress - batchFulfillmentEnabled, //batchFulfillmentEnabled - compressedPkHex, //publicKey - 100, //minIncomingConfirmations - e.ChainID, //evmChainID + contractAddresses.CoordinatorAddress, //coordinatorAddress + contractAddresses.BatchCoordinatorAddress, //batchCoordinatorAddress + coordinatorJobSpecConfig.BatchFulfillmentEnabled, //batchFulfillmentEnabled + coordinatorJobSpecConfig.BatchFulfillmentGasMultiplier, //batchFulfillmentGasMultiplier + compressedPkHex, //publicKey + 100, //minIncomingConfirmations + e.ChainID, //evmChainID strings.Join(util.MapToAddressArr(nodesMap[model.VRFBackupNodeName].SendingKeys), "\",\""), //fromAddresses + coordinatorJobSpecConfig.PollPeriod, //pollPeriod + coordinatorJobSpecConfig.RequestTimeout, //requestTimeout contractAddresses.CoordinatorAddress, + coordinatorJobSpecConfig.EstimateGasMultiplier, //estimateGasMultiplier func() string { if keys := nodesMap[model.VRFPrimaryNodeName].SendingKeys; len(keys) > 0 { return keys[0].Address - } else { - return common.HexToAddress("0x0").String() } + return common.HexToAddress("0x0").String() }(), contractAddresses.CoordinatorAddress, contractAddresses.CoordinatorAddress, ) formattedBHSJobSpec := fmt.Sprintf( - jobs.BHSJobFormatted, + jobs.BHSPlusJobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress 30, //waitBlocks 200, //lookbackBlocks @@ -752,7 +762,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, ) formattedBHSBackupJobSpec := fmt.Sprintf( - jobs.BHSJobFormatted, + jobs.BHSPlusJobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress 100, //waitBlocks 200, //lookbackBlocks @@ -762,7 +772,7 @@ func VRFV2PlusDeployUniverse(e helpers.Environment, ) formattedBHFJobSpec := fmt.Sprintf( - jobs.BHFJobFormatted, + jobs.BHFPlusJobFormatted, contractAddresses.CoordinatorAddress, //coordinatorAddress contractAddresses.BhsContractAddress, //bhs adreess contractAddresses.BatchBHSAddress, //batchBHS diff --git a/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go index ebe881a9951..7b38dc7b391 100644 --- a/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go +++ b/core/scripts/vrfv2plus/testnet/v2plusscripts/util.go @@ -4,14 +4,16 @@ import ( "context" "encoding/hex" "fmt" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" "math/big" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" helpers "github.com/smartcontractkit/chainlink/core/scripts/common" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2plus" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" @@ -20,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_sub_owner" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_consumer_example" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func DeployBHS(e helpers.Environment) (blockhashStoreAddress common.Address) { @@ -175,13 +176,12 @@ func SetCoordinatorConfig( } func RegisterCoordinatorProvingKey(e helpers.Environment, - coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, uncompressed string, oracleAddress string) { + coordinator vrf_coordinator_v2_5.VRFCoordinatorV25, uncompressed string) { pubBytes, err := hex.DecodeString(uncompressed) helpers.PanicErr(err) pk, err := crypto.UnmarshalPubkey(pubBytes) helpers.PanicErr(err) tx, err := coordinator.RegisterProvingKey(e.Owner, - common.HexToAddress(oracleAddress), [2]*big.Int{pk.X, pk.Y}) helpers.PanicErr(err) helpers.ConfirmTXMined( @@ -190,7 +190,6 @@ func RegisterCoordinatorProvingKey(e helpers.Environment, tx, e.ChainID, fmt.Sprintf("Uncompressed public key: %s,", uncompressed), - fmt.Sprintf("Oracle address: %s,", oracleAddress), ) } diff --git a/core/services/blockhashstore/common.go b/core/services/blockhashstore/common.go index 677016253fb..a19a3b868f7 100644 --- a/core/services/blockhashstore/common.go +++ b/core/services/blockhashstore/common.go @@ -59,7 +59,7 @@ func GetUnfulfilledBlocksAndRequests( blockToRequests := make(map[uint64]map[string]struct{}) requestIDToBlock := make(map[string]uint64) - reqs, err := coordinator.Requests(ctx, uint64(fromBlock), uint64(toBlock)) + reqs, err := coordinator.Requests(ctx, fromBlock, toBlock) if err != nil { lggr.Errorw("Failed to fetch VRF requests", "err", err) @@ -73,7 +73,7 @@ func GetUnfulfilledBlocksAndRequests( requestIDToBlock[req.ID] = req.Block } - fuls, err := coordinator.Fulfillments(ctx, uint64(fromBlock)) + fuls, err := coordinator.Fulfillments(ctx, fromBlock) if err != nil { lggr.Errorw("Failed to fetch VRF fulfillments", "err", err) diff --git a/core/services/blockhashstore/delegate_test.go b/core/services/blockhashstore/delegate_test.go index 0096ac5ca9e..6fffcfdd493 100644 --- a/core/services/blockhashstore/delegate_test.go +++ b/core/services/blockhashstore/delegate_test.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -26,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestDelegate_JobType(t *testing.T) { @@ -90,7 +90,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { defaultWaitBlocks := (int32)(testData.legacyChains.Slice()[0].Config().EVM().FinalityDepth()) t.Run("happy", func(t *testing.T) { - spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{WaitBlocks: defaultWaitBlocks, EVMChainID: (*utils.Big)(testutils.FixtureChainID)}} + spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{WaitBlocks: defaultWaitBlocks, EVMChainID: (*big.Big)(testutils.FixtureChainID)}} services, err := delegate.ServicesForSpec(spec) require.NoError(t, err) @@ -107,7 +107,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { CoordinatorV1Address: &coordinatorV1, CoordinatorV2Address: &coordinatorV2, CoordinatorV2PlusAddress: &coordinatorV2Plus, - EVMChainID: (*utils.Big)(testutils.FixtureChainID), + EVMChainID: (*big.Big)(testutils.FixtureChainID), }} services, err := delegate.ServicesForSpec(spec) @@ -123,7 +123,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { t.Run("wrong EVMChainID", func(t *testing.T) { spec := job.Job{BlockhashStoreSpec: &job.BlockhashStoreSpec{ - EVMChainID: utils.NewBigI(123), + EVMChainID: big.NewI(123), }} _, err := delegate.ServicesForSpec(spec) assert.Error(t, err) @@ -152,7 +152,7 @@ func TestDelegate_StartStop(t *testing.T) { WaitBlocks: defaultWaitBlocks, PollPeriod: time.Second, RunTimeout: testutils.WaitTimeout(t), - EVMChainID: (*utils.Big)(testutils.FixtureChainID), + EVMChainID: (*big.Big)(testutils.FixtureChainID), }} services, err := delegate.ServicesForSpec(spec) diff --git a/core/services/blockhashstore/feeder_test.go b/core/services/blockhashstore/feeder_test.go index 8d9ed48c4bf..ad039798408 100644 --- a/core/services/blockhashstore/feeder_test.go +++ b/core/services/blockhashstore/feeder_test.go @@ -14,9 +14,10 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" + mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" bhsmocks "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore/mocks" diff --git a/core/services/blockhashstore/mocks/bhs.go b/core/services/blockhashstore/mocks/bhs.go index 51ddca46a0d..a69016c8026 100644 --- a/core/services/blockhashstore/mocks/bhs.go +++ b/core/services/blockhashstore/mocks/bhs.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type BHS struct { func (_m *BHS) IsStored(ctx context.Context, blockNum uint64) (bool, error) { ret := _m.Called(ctx, blockNum) + if len(ret) == 0 { + panic("no return value specified for IsStored") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, uint64) (bool, error)); ok { @@ -43,6 +47,10 @@ func (_m *BHS) IsStored(ctx context.Context, blockNum uint64) (bool, error) { func (_m *BHS) IsTrusted() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsTrusted") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -57,6 +65,10 @@ func (_m *BHS) IsTrusted() bool { func (_m *BHS) Store(ctx context.Context, blockNum uint64) error { ret := _m.Called(ctx, blockNum) + if len(ret) == 0 { + panic("no return value specified for Store") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, uint64) error); ok { r0 = rf(ctx, blockNum) @@ -71,6 +83,10 @@ func (_m *BHS) Store(ctx context.Context, blockNum uint64) error { func (_m *BHS) StoreEarliest(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for StoreEarliest") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -85,6 +101,10 @@ func (_m *BHS) StoreEarliest(ctx context.Context) error { func (_m *BHS) StoreTrusted(ctx context.Context, blockNums []uint64, blockhashes []common.Hash, recentBlock uint64, recentBlockhash common.Hash) error { ret := _m.Called(ctx, blockNums, blockhashes, recentBlock, recentBlockhash) + if len(ret) == 0 { + panic("no return value specified for StoreTrusted") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, []uint64, []common.Hash, uint64, common.Hash) error); ok { r0 = rf(ctx, blockNums, blockhashes, recentBlock, recentBlockhash) diff --git a/core/services/blockhashstore/mocks/timer.go b/core/services/blockhashstore/mocks/timer.go index c116163a3df..4236bdf8d92 100644 --- a/core/services/blockhashstore/mocks/timer.go +++ b/core/services/blockhashstore/mocks/timer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type Timer struct { func (_m *Timer) After(d time.Duration) <-chan time.Time { ret := _m.Called(d) + if len(ret) == 0 { + panic("no return value specified for After") + } + var r0 <-chan time.Time if rf, ok := ret.Get(0).(func(time.Duration) <-chan time.Time); ok { r0 = rf(d) diff --git a/core/services/blockhashstore/validate.go b/core/services/blockhashstore/validate.go index 82b813a37f4..62f90d326eb 100644 --- a/core/services/blockhashstore/validate.go +++ b/core/services/blockhashstore/validate.go @@ -7,8 +7,8 @@ import ( "github.com/pelletier/go-toml" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var EmptyAddress = utils.ZeroAddress.Hex() diff --git a/core/services/blockhashstore/validate_test.go b/core/services/blockhashstore/validate_test.go index 0b7110a7528..48487bb5489 100644 --- a/core/services/blockhashstore/validate_test.go +++ b/core/services/blockhashstore/validate_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestValidate(t *testing.T) { @@ -49,7 +49,7 @@ fromAddresses = ["0x469aA2CD13e037DC5236320783dCfd0e641c0559"]`, os.BlockhashStoreSpec.BlockhashStoreAddress) require.Equal(t, 23*time.Second, os.BlockhashStoreSpec.PollPeriod) require.Equal(t, 7*time.Second, os.BlockhashStoreSpec.RunTimeout) - require.Equal(t, utils.NewBigI(4), os.BlockhashStoreSpec.EVMChainID) + require.Equal(t, big.NewI(4), os.BlockhashStoreSpec.EVMChainID) require.Equal(t, fromAddresses, os.BlockhashStoreSpec.FromAddresses) }, diff --git a/core/services/blockheaderfeeder/block_header_feeder.go b/core/services/blockheaderfeeder/block_header_feeder.go index 93799b8b419..a5bcb003613 100644 --- a/core/services/blockheaderfeeder/block_header_feeder.go +++ b/core/services/blockheaderfeeder/block_header_feeder.go @@ -120,7 +120,7 @@ func (f *BlockHeaderFeeder) Run(ctx context.Context) error { lggr.Debugw("found lowest block number without blockhash", "minBlockNumber", minBlockNumber) - earliestStoredBlockNumber, err := f.findEarliestBlockNumberWithBlockhash(ctx, lggr, minBlockNumber.Uint64()+1, uint64(toBlock)) + earliestStoredBlockNumber, err := f.findEarliestBlockNumberWithBlockhash(ctx, lggr, minBlockNumber.Uint64()+1, toBlock) if err != nil { return errors.Wrap(err, "finding earliest blocknumber with blockhash") } diff --git a/core/services/blockheaderfeeder/validate_test.go b/core/services/blockheaderfeeder/validate_test.go index c58058d1620..cdab0322a40 100644 --- a/core/services/blockheaderfeeder/validate_test.go +++ b/core/services/blockheaderfeeder/validate_test.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestValidate(t *testing.T) { @@ -59,7 +59,7 @@ storeBlockhashesBatchSize = 10 os.BlockHeaderFeederSpec.BatchBlockhashStoreAddress) require.Equal(t, 23*time.Second, os.BlockHeaderFeederSpec.PollPeriod) require.Equal(t, 7*time.Second, os.BlockHeaderFeederSpec.RunTimeout) - require.Equal(t, utils.NewBigI(4), os.BlockHeaderFeederSpec.EVMChainID) + require.Equal(t, big.NewI(4), os.BlockHeaderFeederSpec.EVMChainID) require.Equal(t, fromAddresses, os.BlockHeaderFeederSpec.FromAddresses) require.Equal(t, uint16(20), @@ -86,7 +86,7 @@ fromAddresses = ["0x469aA2CD13e037DC5236320783dCfd0e641c0559"] require.Equal(t, int32(256), os.BlockHeaderFeederSpec.WaitBlocks) require.Equal(t, 15*time.Second, os.BlockHeaderFeederSpec.PollPeriod) require.Equal(t, 30*time.Second, os.BlockHeaderFeederSpec.RunTimeout) - require.Equal(t, utils.NewBigI(4), os.BlockHeaderFeederSpec.EVMChainID) + require.Equal(t, big.NewI(4), os.BlockHeaderFeederSpec.EVMChainID) require.Equal(t, fromAddresses, os.BlockHeaderFeederSpec.FromAddresses) require.Equal(t, uint16(100), diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 5c204d693e9..a9f9c22df52 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -20,12 +20,15 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/build" "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/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" @@ -50,13 +53,13 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/promreporter" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" + "github.com/smartcontractkit/chainlink/v2/core/services/streams" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/core/services/vrf" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/sessions/ldapauth" "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -114,7 +117,6 @@ type Application interface { // in the services package, but the Store has its own package. type ChainlinkApplication struct { relayers *CoreRelayerChainInteroperators - EventBroadcaster pg.EventBroadcaster jobORM job.ORM jobSpawner job.Spawner pipelineORM pipeline.ORM @@ -128,7 +130,7 @@ type ChainlinkApplication struct { Config GeneralConfig KeyStore keystore.Master ExternalInitiatorManager webhook.ExternalInitiatorManager - SessionReaper utils.SleeperTask + SessionReaper *utils.SleeperTask shutdownOnce sync.Once srvcs []services.ServiceCtx HealthChecker services.Checker @@ -148,8 +150,7 @@ type ChainlinkApplication struct { type ApplicationOpts struct { Config GeneralConfig Logger logger.Logger - EventBroadcaster pg.EventBroadcaster - MailMon *utils.MailboxMonitor + MailMon *mailbox.Monitor SqlxDB *sqlx.DB KeyStore keystore.Master RelayerChainInteroperators *CoreRelayerChainInteroperators @@ -176,7 +177,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { db := opts.SqlxDB cfg := opts.Config relayerChainInterops := opts.RelayerChainInteroperators - eventBroadcaster := opts.EventBroadcaster mailMon := opts.MailMon externalInitiatorManager := opts.ExternalInitiatorManager globalLogger := logger.Sugared(opts.Logger) @@ -240,7 +240,9 @@ func NewApplication(opts ApplicationOpts) (Application, error) { } // pool must be started before all relayers and stopped after them - srvcs = append(srvcs, opts.MercuryPool) + if opts.MercuryPool != nil { + srvcs = append(srvcs, opts.MercuryPool) + } // EVM chains are used all over the place. This will need to change for fully EVM extraction // TODO: BCF-2510, BCF-2511 @@ -250,7 +252,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { return nil, fmt.Errorf("no evm chains found") } - srvcs = append(srvcs, eventBroadcaster, mailMon) + srvcs = append(srvcs, mailMon) srvcs = append(srvcs, relayerChainInterops.Services()...) promReporter := promreporter.NewPromReporter(db.DB, legacyEVMChains, globalLogger) srvcs = append(srvcs, promReporter) @@ -263,7 +265,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { // localDB auth or remote LDAP auth authMethod := cfg.WebServer().AuthenticationMethod() var authenticationProvider sessions.AuthenticationProvider - var sessionReaper utils.SleeperTask + var sessionReaper *utils.SleeperTask switch sessions.AuthenticationProviderName(authMethod) { case sessions.LDAPAuth: @@ -289,6 +291,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { pipelineRunner = pipeline.NewRunner(pipelineORM, bridgeORM, cfg.JobPipeline(), cfg.WebServer(), legacyEVMChains, keyStore.Eth(), keyStore.VRF(), globalLogger, restrictedHTTPClient, unrestrictedHTTPClient) jobORM = job.NewORM(db, pipelineORM, bridgeORM, keyStore, globalLogger, cfg.Database()) txmORM = txmgr.NewTxStore(db, globalLogger, cfg.Database()) + streamRegistry = streams.NewRegistry(globalLogger, pipelineRunner) ) for _, chain := range legacyEVMChains.Slice() { @@ -340,7 +343,14 @@ func NewApplication(opts ApplicationOpts) (Application, error) { job.Gateway: gateway.NewDelegate( legacyEVMChains, keyStore.Eth(), + db, + cfg.Database(), globalLogger), + job.Stream: streams.NewDelegate( + globalLogger, + streamRegistry, + pipelineRunner, + cfg.JobPipeline()), } webhookJobRunner = delegates[job.Webhook].(*webhook.Delegate).WebhookJobRunner() ) @@ -410,7 +420,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { keyStore.Eth(), opts.RelayerChainInteroperators, mailMon, - eventBroadcaster, ) delegates[job.Bootstrap] = ocrbootstrap.NewDelegateBootstrap( db, @@ -475,7 +484,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { return &ChainlinkApplication{ relayers: opts.RelayerChainInteroperators, - EventBroadcaster: eventBroadcaster, jobORM: jobORM, jobSpawner: jobSpawner, pipelineRunner: pipelineRunner, @@ -737,14 +745,14 @@ func (app *ChainlinkApplication) RunJobV2( Data: bytes.Join([][]byte{ jb.VRFSpec.PublicKey.MustHash().Bytes(), // key hash common.BigToHash(big.NewInt(42)).Bytes(), // seed - utils.NewHash().Bytes(), // sender - utils.NewHash().Bytes(), // fee - utils.NewHash().Bytes()}, // requestID + evmutils.NewHash().Bytes(), // sender + evmutils.NewHash().Bytes(), // fee + evmutils.NewHash().Bytes()}, // requestID []byte{}), Topics: []common.Hash{{}, jb.ExternalIDEncodeBytesToTopic()}, // jobID BYTES - TxHash: utils.NewHash(), + TxHash: evmutils.NewHash(), BlockNumber: 10, - BlockHash: utils.NewHash(), + BlockHash: evmutils.NewHash(), } vars = map[string]interface{}{ "jobSpec": map[string]interface{}{ @@ -804,10 +812,6 @@ func (app *ChainlinkApplication) GetRelayers() RelayerChainInteroperators { return app.relayers } -func (app *ChainlinkApplication) GetEventBroadcaster() pg.EventBroadcaster { - return app.EventBroadcaster -} - func (app *ChainlinkApplication) GetSqlxDB() *sqlx.DB { return app.sqlxDB } diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 5d8b1019e8c..6cd2732ece8 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -28,9 +28,9 @@ import ( // When adding a new field: // - consider including a unit suffix with the field name // - TOML is limited to int64/float64, so fields requiring greater range/precision must use non-standard types -// implementing encoding.TextMarshaler/TextUnmarshaler, like utils.Big and decimal.Decimal +// implementing encoding.TextMarshaler/TextUnmarshaler, like big.Big and decimal.Decimal // - std lib types that don't implement encoding.TextMarshaler/TextUnmarshaler (time.Duration, url.URL, big.Int) won't -// work as expected, and require wrapper types. See models.Duration, models.URL, utils.Big. +// work as expected, and require wrapper types. See commonconfig.Duration, commonconfig.URL, big.Big. type Config struct { toml.Core @@ -76,42 +76,7 @@ func (c *Config) valueWarnings() (err error) { // deprecationWarnings returns an error if the Config contains deprecated fields. // This is typically used before defaults have been applied, with input from the user. func (c *Config) deprecationWarnings() (err error) { - if c.P2P.V1 != (toml.P2PV1{}) { - err = multierr.Append(err, config.ErrDeprecated{Name: "P2P.V1"}) - var err2 error - if c.P2P.V1.AnnounceIP != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "AnnounceIP"}) - } - if c.P2P.V1.AnnouncePort != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "AnnouncePort"}) - } - if c.P2P.V1.BootstrapCheckInterval != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "BootstrapCheckInterval"}) - } - if c.P2P.V1.DefaultBootstrapPeers != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DefaultBootstrapPeers"}) - } - if c.P2P.V1.DHTAnnouncementCounterUserPrefix != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DHTAnnouncementCounterUserPrefix"}) - } - if c.P2P.V1.DHTLookupInterval != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "DHTLookupInterval"}) - } - if c.P2P.V1.ListenIP != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "ListenIP"}) - } - if c.P2P.V1.ListenPort != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "ListenPort"}) - } - if c.P2P.V1.NewStreamTimeout != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "NewStreamTimeout"}) - } - if c.P2P.V1.PeerstoreWriteInterval != nil { - err2 = multierr.Append(err2, config.ErrDeprecated{Name: "PeerstoreWriteInterval"}) - } - err2 = config.NamedMultiErrorList(err2, "P2P.V1") - err = multierr.Append(err, err2) - } + // none return } diff --git a/core/services/chainlink/config_audit_logger.go b/core/services/chainlink/config_audit_logger.go index 1593f3887fb..5d8c00f771d 100644 --- a/core/services/chainlink/config_audit_logger.go +++ b/core/services/chainlink/config_audit_logger.go @@ -1,6 +1,7 @@ package chainlink import ( + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/store/models" @@ -14,7 +15,7 @@ func (a auditLoggerConfig) Enabled() bool { return *a.c.Enabled } -func (a auditLoggerConfig) ForwardToUrl() (models.URL, error) { +func (a auditLoggerConfig) ForwardToUrl() (commonconfig.URL, error) { return *a.c.ForwardToUrl, nil } diff --git a/core/services/chainlink/config_auto_pprof.go b/core/services/chainlink/config_auto_pprof.go index 8cc5f2dd3e8..48ec7749b79 100644 --- a/core/services/chainlink/config_auto_pprof.go +++ b/core/services/chainlink/config_auto_pprof.go @@ -3,9 +3,9 @@ package chainlink import ( "path/filepath" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -28,12 +28,12 @@ func (a *autoPprofConfig) CPUProfileRate() int { return int(*a.c.CPUProfileRate) } -func (a *autoPprofConfig) GatherDuration() models.Duration { - return models.MustMakeDuration(a.c.GatherDuration.Duration()) +func (a *autoPprofConfig) GatherDuration() commonconfig.Duration { + return *commonconfig.MustNewDuration(a.c.GatherDuration.Duration()) } -func (a *autoPprofConfig) GatherTraceDuration() models.Duration { - return models.MustMakeDuration(a.c.GatherTraceDuration.Duration()) +func (a *autoPprofConfig) GatherTraceDuration() commonconfig.Duration { + return *commonconfig.MustNewDuration(a.c.GatherTraceDuration.Duration()) } func (a *autoPprofConfig) GoroutineThreshold() int { @@ -56,7 +56,7 @@ func (a *autoPprofConfig) MutexProfileFraction() int { return int(*a.c.MutexProfileFraction) } -func (a *autoPprofConfig) PollInterval() models.Duration { +func (a *autoPprofConfig) PollInterval() commonconfig.Duration { return *a.c.PollInterval } diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index c7d9cc6ce5d..97243926973 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -13,12 +13,11 @@ import ( "go.uber.org/multierr" "go.uber.org/zap/zapcore" - ocrnetworking "github.com/smartcontractkit/libocr/networking" - coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" starknet "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/config" coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" @@ -28,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" - configutils "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) // generalConfig is a wrapper to adapt Config to the config.GeneralConfig interface. @@ -99,7 +97,7 @@ func (o *GeneralConfigOpts) Setup(configFiles []string, secretsFiles []string) e // parseConfig sets Config from the given TOML string, overriding any existing duplicate Config fields. func (o *GeneralConfigOpts) parseConfig(config string) error { var c Config - if err2 := configutils.DecodeTOML(strings.NewReader(config), &c); err2 != nil { + if err2 := commonconfig.DecodeTOML(strings.NewReader(config), &c); err2 != nil { return fmt.Errorf("failed to decode config TOML: %w", err2) } @@ -113,7 +111,7 @@ func (o *GeneralConfigOpts) parseConfig(config string) error { // parseSecrets sets Secrets from the given TOML string. Errors on overrides func (o *GeneralConfigOpts) parseSecrets(secrets string) error { var s Secrets - if err2 := configutils.DecodeTOML(strings.NewReader(secrets), &s); err2 != nil { + if err2 := commonconfig.DecodeTOML(strings.NewReader(secrets), &s); err2 != nil { return fmt.Errorf("failed to decode secrets TOML: %w", err2) } @@ -359,12 +357,12 @@ func (g *generalConfig) AutoPprofCPUProfileRate() int { return int(*g.c.AutoPprof.CPUProfileRate) } -func (g *generalConfig) AutoPprofGatherDuration() models.Duration { - return models.MustMakeDuration(g.c.AutoPprof.GatherDuration.Duration()) +func (g *generalConfig) AutoPprofGatherDuration() commonconfig.Duration { + return *commonconfig.MustNewDuration(g.c.AutoPprof.GatherDuration.Duration()) } -func (g *generalConfig) AutoPprofGatherTraceDuration() models.Duration { - return models.MustMakeDuration(g.c.AutoPprof.GatherTraceDuration.Duration()) +func (g *generalConfig) AutoPprofGatherTraceDuration() commonconfig.Duration { + return *commonconfig.MustNewDuration(g.c.AutoPprof.GatherTraceDuration.Duration()) } func (g *generalConfig) AutoPprofGoroutineThreshold() int { @@ -387,7 +385,7 @@ func (g *generalConfig) AutoPprofMutexProfileFraction() int { return int(*g.c.AutoPprof.MutexProfileFraction) } -func (g *generalConfig) AutoPprofPollInterval() models.Duration { +func (g *generalConfig) AutoPprofPollInterval() commonconfig.Duration { return *g.c.AutoPprof.PollInterval } @@ -443,14 +441,6 @@ func (g *generalConfig) P2P() config.P2P { return &p2p{c: g.c.P2P} } -func (g *generalConfig) P2PNetworkingStack() (n ocrnetworking.NetworkingStack) { - return g.c.P2P.NetworkStack() -} - -func (g *generalConfig) P2PNetworkingStackRaw() string { - return g.c.P2P.NetworkStack().String() -} - func (g *generalConfig) P2PPeerID() p2pkey.PeerID { return *g.c.P2P.PeerID } diff --git a/core/services/chainlink/config_general_test.go b/core/services/chainlink/config_general_test.go index c122f8f968c..444f34abcbb 100644 --- a/core/services/chainlink/config_general_test.go +++ b/core/services/chainlink/config_general_test.go @@ -14,9 +14,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) func TestTOMLGeneralConfig_Defaults(t *testing.T) { diff --git a/core/services/chainlink/config_job_pipeline.go b/core/services/chainlink/config_job_pipeline.go index 1586cbb3574..95106b84199 100644 --- a/core/services/chainlink/config_job_pipeline.go +++ b/core/services/chainlink/config_job_pipeline.go @@ -3,9 +3,9 @@ package chainlink import ( "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) var _ config.JobPipeline = (*jobPipelineConfig)(nil) @@ -18,7 +18,7 @@ func (j *jobPipelineConfig) DefaultHTTPLimit() int64 { return int64(*j.c.HTTPRequest.MaxSize) } -func (j *jobPipelineConfig) DefaultHTTPTimeout() models.Duration { +func (j *jobPipelineConfig) DefaultHTTPTimeout() commonconfig.Duration { return *j.c.HTTPRequest.DefaultTimeout } diff --git a/core/services/chainlink/config_job_pipeline_test.go b/core/services/chainlink/config_job_pipeline_test.go index 58c94067f25..9a865569eb3 100644 --- a/core/services/chainlink/config_job_pipeline_test.go +++ b/core/services/chainlink/config_job_pipeline_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -21,7 +21,7 @@ func TestJobPipelineConfigTest(t *testing.T) { jp := cfg.JobPipeline() assert.Equal(t, int64(100*utils.MB), jp.DefaultHTTPLimit()) - d, err := models.MakeDuration(1 * time.Minute) + d, err := commonconfig.NewDuration(1 * time.Minute) require.NoError(t, err) assert.Equal(t, d, jp.DefaultHTTPTimeout()) assert.Equal(t, 1*time.Hour, jp.MaxRunDuration()) diff --git a/core/services/chainlink/config_mercury.go b/core/services/chainlink/config_mercury.go index 61e48d340e4..27303a68899 100644 --- a/core/services/chainlink/config_mercury.go +++ b/core/services/chainlink/config_mercury.go @@ -3,9 +3,10 @@ package chainlink import ( "time" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" ) var _ config.MercuryCache = (*mercuryCacheConfig)(nil) @@ -24,14 +25,22 @@ func (m *mercuryCacheConfig) LatestReportDeadline() time.Duration { return m.c.LatestReportDeadline.Duration() } +type mercuryTLSConfig struct { + c toml.MercuryTLS +} + +func (m *mercuryTLSConfig) CertFile() string { + return *m.c.CertFile +} + type mercuryConfig struct { c toml.Mercury s toml.MercurySecrets } -func (m *mercuryConfig) Credentials(credName string) *models.MercuryCredentials { +func (m *mercuryConfig) Credentials(credName string) *types.MercuryCredentials { if mc, ok := m.s.Credentials[credName]; ok { - c := &models.MercuryCredentials{ + c := &types.MercuryCredentials{ URL: mc.URL.URL().String(), Password: string(*mc.Password), Username: string(*mc.Username), @@ -47,3 +56,7 @@ func (m *mercuryConfig) Credentials(credName string) *models.MercuryCredentials func (m *mercuryConfig) Cache() config.MercuryCache { return &mercuryCacheConfig{c: m.c.Cache} } + +func (m *mercuryConfig) TLS() config.MercuryTLS { + return &mercuryTLSConfig{c: m.c.TLS} +} diff --git a/core/services/chainlink/config_mercury_test.go b/core/services/chainlink/config_mercury_test.go index 58019a91557..1ae8dc0ba2e 100644 --- a/core/services/chainlink/config_mercury_test.go +++ b/core/services/chainlink/config_mercury_test.go @@ -3,10 +3,12 @@ package chainlink import ( "testing" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink/v2/core/config/toml" ) const ( @@ -31,6 +33,18 @@ func TestMercuryConfig(t *testing.T) { require.NoError(t, err) m := cfg.Mercury() - assert.Equal(t, &models.MercuryCredentials{URL: "https://chain1.link", Username: "username1", Password: "password1"}, m.Credentials("cred1")) - assert.Equal(t, &models.MercuryCredentials{URL: "https://chain2.link", Username: "username2", Password: "password2"}, m.Credentials("cred2")) + assert.Equal(t, &types.MercuryCredentials{URL: "https://chain1.link", Username: "username1", Password: "password1"}, m.Credentials("cred1")) + assert.Equal(t, &types.MercuryCredentials{URL: "https://chain2.link", Username: "username2", Password: "password2"}, m.Credentials("cred2")) +} + +func TestMercuryTLS(t *testing.T) { + certPath := "/path/to/cert.pem" + transmission := toml.Mercury{ + TLS: toml.MercuryTLS{ + CertFile: &certPath, + }, + } + cfg := mercuryConfig{c: transmission} + + assert.Equal(t, certPath, cfg.TLS().CertFile()) } diff --git a/core/services/chainlink/config_p2p.go b/core/services/chainlink/config_p2p.go index 35b80cc5f79..4197358b148 100644 --- a/core/services/chainlink/config_p2p.go +++ b/core/services/chainlink/config_p2p.go @@ -1,16 +1,12 @@ package chainlink import ( - "net" - "time" - - "github.com/smartcontractkit/libocr/commontypes" - ocrnetworking "github.com/smartcontractkit/libocr/networking" - + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + + "github.com/smartcontractkit/libocr/commontypes" ) type p2p struct { @@ -18,11 +14,7 @@ type p2p struct { } func (p *p2p) Enabled() bool { - return p.V1().Enabled() || p.V2().Enabled() -} - -func (p *p2p) NetworkStack() (n ocrnetworking.NetworkingStack) { - return p.c.NetworkStack() + return p.V2().Enabled() } func (p *p2p) PeerID() p2pkey.PeerID { @@ -45,63 +37,6 @@ func (p *p2p) V2() config.V2 { return &p2pv2{p.c.V2} } -func (p *p2p) V1() config.V1 { - return &p2pv1{p.c.V1} -} - -type p2pv1 struct { - c toml.P2PV1 -} - -func (v *p2pv1) Enabled() bool { - return *v.c.Enabled -} - -func (v *p2pv1) AnnounceIP() net.IP { - return *v.c.AnnounceIP -} - -func (v *p2pv1) AnnouncePort() uint16 { - return *v.c.AnnouncePort -} - -func (v *p2pv1) DefaultBootstrapPeers() ([]string, error) { - p := *v.c.DefaultBootstrapPeers - if p == nil { - p = []string{} - } - return p, nil -} - -func (v *p2pv1) DHTAnnouncementCounterUserPrefix() uint32 { - return *v.c.DHTAnnouncementCounterUserPrefix -} - -func (v *p2pv1) ListenIP() net.IP { - return *v.c.ListenIP -} - -func (v *p2pv1) ListenPort() uint16 { - p := *v.c.ListenPort - return p -} - -func (v *p2pv1) NewStreamTimeout() time.Duration { - return v.c.NewStreamTimeout.Duration() -} - -func (v *p2pv1) BootstrapCheckInterval() time.Duration { - return v.c.BootstrapCheckInterval.Duration() -} - -func (v *p2pv1) DHTLookupInterval() int { - return int(*v.c.DHTLookupInterval) -} - -func (v *p2pv1) PeerstoreWriteInterval() time.Duration { - return v.c.PeerstoreWriteInterval.Duration() -} - type p2pv2 struct { c toml.P2PV2 } @@ -124,19 +59,19 @@ func (v *p2pv2) DefaultBootstrappers() (locators []commontypes.BootstrapperLocat return nil } -func (v *p2pv2) DeltaDial() models.Duration { +func (v *p2pv2) DeltaDial() commonconfig.Duration { if d := v.c.DeltaDial; d != nil { return *d } - return models.Duration{} + return commonconfig.Duration{} } -func (v *p2pv2) DeltaReconcile() models.Duration { +func (v *p2pv2) DeltaReconcile() commonconfig.Duration { if d := v.c.DeltaReconcile; d != nil { return *d } - return models.Duration{} + return commonconfig.Duration{} } func (v *p2pv2) ListenAddresses() []string { diff --git a/core/services/chainlink/config_p2p_test.go b/core/services/chainlink/config_p2p_test.go index 21ce8f17e48..c23f3296ef8 100644 --- a/core/services/chainlink/config_p2p_test.go +++ b/core/services/chainlink/config_p2p_test.go @@ -23,21 +23,6 @@ func TestP2PConfig(t *testing.T) { assert.Equal(t, 17, p2p.OutgoingMessageBufferSize()) assert.True(t, p2p.TraceLogging()) - v1 := p2p.V1() - assert.True(t, v1.Enabled()) - assert.Equal(t, "1.2.3.4", v1.AnnounceIP().String()) - assert.Equal(t, uint16(1234), v1.AnnouncePort()) - assert.Equal(t, time.Minute, v1.BootstrapCheckInterval()) - p, err := v1.DefaultBootstrapPeers() - require.NoError(t, err) - assert.Equal(t, []string{"foo", "bar", "should", "these", "be", "typed"}, p) - assert.Equal(t, uint32(4321), v1.DHTAnnouncementCounterUserPrefix()) - assert.Equal(t, 9, v1.DHTLookupInterval()) - assert.Equal(t, "4.3.2.1", v1.ListenIP().String()) - assert.Equal(t, uint16(9), v1.ListenPort()) - assert.Equal(t, time.Second, v1.NewStreamTimeout()) - assert.Equal(t, time.Minute, v1.PeerstoreWriteInterval()) - v2 := p2p.V2() assert.False(t, v2.Enabled()) assert.Equal(t, []string{"a", "b", "c"}, v2.AnnounceAddresses()) diff --git a/core/services/chainlink/config_telemetry_ingress.go b/core/services/chainlink/config_telemetry_ingress.go index 5126833134e..3ad721ad303 100644 --- a/core/services/chainlink/config_telemetry_ingress.go +++ b/core/services/chainlink/config_telemetry_ingress.go @@ -46,16 +46,6 @@ func (t *telemetryIngressConfig) UseBatchSend() bool { return *t.c.UseBatchSend } -// Deprecated: Use TelemetryIngressEndpoint.ServerPubKey, this field will be removed in future versions -func (t *telemetryIngressConfig) ServerPubKey() string { - return *t.c.ServerPubKey -} - -// Deprecated: Use TelemetryIngressEndpoint.URL instead, this field will be removed in future versions -func (t *telemetryIngressConfig) URL() *url.URL { - return t.c.URL.URL() -} - func (t *telemetryIngressConfig) Endpoints() []config.TelemetryIngressEndpoint { var endpoints []config.TelemetryIngressEndpoint for _, e := range t.c.Endpoints { diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 2966a896902..b16551912b2 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -3,6 +3,7 @@ package chainlink import ( _ "embed" "math" + "math/big" "net" "strings" "testing" @@ -17,7 +18,10 @@ import ( ocrcommontypes "github.com/smartcontractkit/libocr/commontypes" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/config" commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" @@ -26,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" legacy "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -34,7 +39,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/config" ) var ( @@ -63,7 +67,7 @@ var ( }, Database: toml.Database{ Listener: toml.DatabaseListener{ - FallbackPollInterval: models.MustNewDuration(2 * time.Minute), + FallbackPollInterval: commonconfig.MustNewDuration(2 * time.Minute), }, }, Log: toml.Log{ @@ -72,16 +76,16 @@ var ( }, JobPipeline: toml.JobPipeline{ HTTPRequest: toml.JobPipelineHTTPRequest{ - DefaultTimeout: models.MustNewDuration(30 * time.Second), + DefaultTimeout: commonconfig.MustNewDuration(30 * time.Second), }, }, OCR2: toml.OCR2{ Enabled: ptr(true), - DatabaseTimeout: models.MustNewDuration(20 * time.Second), + DatabaseTimeout: commonconfig.MustNewDuration(20 * time.Second), }, OCR: toml.OCR{ Enabled: ptr(true), - BlockchainTimeout: models.MustNewDuration(5 * time.Second), + BlockchainTimeout: commonconfig.MustNewDuration(5 * time.Second), }, P2P: toml.P2P{ IncomingMessageBufferSize: ptr[int64](999), @@ -95,7 +99,7 @@ var ( }, EVM: []*evmcfg.EVMConfig{ { - ChainID: utils.NewBigI(1), + ChainID: ubig.NewI(1), Chain: evmcfg.Chain{ FinalityDepth: ptr[uint32](26), FinalityTagEnabled: ptr[bool](false), @@ -112,7 +116,7 @@ var ( }, }}, { - ChainID: utils.NewBigI(42), + ChainID: ubig.NewI(42), Chain: evmcfg.Chain{ GasEstimator: evmcfg.GasEstimator{ PriceDefault: assets.NewWeiI(math.MaxInt64), @@ -125,7 +129,7 @@ var ( }, }}, { - ChainID: utils.NewBigI(137), + ChainID: ubig.NewI(137), Chain: evmcfg.Chain{ GasEstimator: evmcfg.GasEstimator{ Mode: ptr("FixedPrice"), @@ -191,10 +195,10 @@ var ( ) func TestConfig_Marshal(t *testing.T) { - zeroSeconds := models.MustMakeDuration(time.Second * 0) - second := models.MustMakeDuration(time.Second) - minute := models.MustMakeDuration(time.Minute) - hour := models.MustMakeDuration(time.Hour) + zeroSeconds := *commonconfig.MustNewDuration(time.Second * 0) + second := *commonconfig.MustNewDuration(time.Second) + minute := *commonconfig.MustNewDuration(time.Minute) + hour := *commonconfig.MustNewDuration(time.Hour) mustPeerID := func(s string) *p2pkey.PeerID { id, err := p2pkey.MakePeerID(s) require.NoError(t, err) @@ -216,7 +220,7 @@ func TestConfig_Marshal(t *testing.T) { Core: toml.Core{ InsecureFastScrypt: ptr(true), RootDir: ptr("test/root/dir"), - ShutdownGracePeriod: models.MustNewDuration(10 * time.Second), + ShutdownGracePeriod: commonconfig.MustNewDuration(10 * time.Second), Insecure: toml.Insecure{ DevWebServer: ptr(false), OCRDevelopmentMode: ptr(false), @@ -257,17 +261,17 @@ func TestConfig_Marshal(t *testing.T) { UICSAKeys: ptr(true), } full.Database = toml.Database{ - DefaultIdleInTxSessionTimeout: models.MustNewDuration(time.Minute), - DefaultLockTimeout: models.MustNewDuration(time.Hour), - DefaultQueryTimeout: models.MustNewDuration(time.Second), + DefaultIdleInTxSessionTimeout: commonconfig.MustNewDuration(time.Minute), + DefaultLockTimeout: commonconfig.MustNewDuration(time.Hour), + DefaultQueryTimeout: commonconfig.MustNewDuration(time.Second), LogQueries: ptr(true), MigrateOnStartup: ptr(true), MaxIdleConns: ptr[int64](7), MaxOpenConns: ptr[int64](13), Listener: toml.DatabaseListener{ - MaxReconnectDuration: models.MustNewDuration(time.Minute), - MinReconnectInterval: models.MustNewDuration(5 * time.Minute), - FallbackPollInterval: models.MustNewDuration(2 * time.Minute), + MaxReconnectDuration: commonconfig.MustNewDuration(time.Minute), + MinReconnectInterval: commonconfig.MustNewDuration(5 * time.Minute), + FallbackPollInterval: commonconfig.MustNewDuration(2 * time.Minute), }, Lock: toml.DatabaseLock{ Enabled: ptr(false), @@ -286,11 +290,9 @@ func TestConfig_Marshal(t *testing.T) { Logging: ptr(true), BufferSize: ptr[uint16](1234), MaxBatchSize: ptr[uint16](4321), - SendInterval: models.MustNewDuration(time.Minute), - SendTimeout: models.MustNewDuration(5 * time.Second), + SendInterval: commonconfig.MustNewDuration(time.Minute), + SendTimeout: commonconfig.MustNewDuration(5 * time.Second), UseBatchSend: ptr(true), - URL: ptr(models.URL{}), - ServerPubKey: ptr(""), Endpoints: []toml.TelemetryIngressEndpoint{{ Network: ptr("EVM"), ChainID: ptr("1"), @@ -314,14 +316,14 @@ func TestConfig_Marshal(t *testing.T) { AuthenticationMethod: ptr("local"), AllowOrigins: ptr("*"), BridgeResponseURL: mustURL("https://bridge.response"), - BridgeCacheTTL: models.MustNewDuration(10 * time.Second), - HTTPWriteTimeout: models.MustNewDuration(time.Minute), + BridgeCacheTTL: commonconfig.MustNewDuration(10 * time.Second), + HTTPWriteTimeout: commonconfig.MustNewDuration(time.Minute), HTTPPort: ptr[uint16](56), SecureCookies: ptr(true), - SessionTimeout: models.MustNewDuration(time.Hour), - SessionReaperExpiration: models.MustNewDuration(7 * 24 * time.Hour), + SessionTimeout: commonconfig.MustNewDuration(time.Hour), + SessionReaperExpiration: commonconfig.MustNewDuration(7 * 24 * time.Hour), HTTPMaxSize: ptr(utils.FileSize(uint64(32770))), - StartTimeout: models.MustNewDuration(15 * time.Second), + StartTimeout: commonconfig.MustNewDuration(15 * time.Second), ListenIP: mustIP("192.158.1.37"), MFA: toml.WebServerMFA{ RPID: ptr("test-rpid"), @@ -329,8 +331,8 @@ func TestConfig_Marshal(t *testing.T) { }, LDAP: toml.WebServerLDAP{ ServerTLS: ptr(true), - SessionTimeout: models.MustNewDuration(15 * time.Minute), - QueryTimeout: models.MustNewDuration(2 * time.Minute), + SessionTimeout: commonconfig.MustNewDuration(15 * time.Minute), + QueryTimeout: commonconfig.MustNewDuration(2 * time.Minute), BaseUserAttr: ptr("uid"), BaseDN: ptr("dc=custom,dc=example,dc=com"), UsersDN: ptr("ou=users"), @@ -342,15 +344,15 @@ func TestConfig_Marshal(t *testing.T) { RunUserGroupCN: ptr("NodeRunners"), ReadUserGroupCN: ptr("NodeReadOnly"), UserApiTokenEnabled: ptr(false), - UserAPITokenDuration: models.MustNewDuration(240 * time.Hour), - UpstreamSyncInterval: models.MustNewDuration(0 * time.Second), - UpstreamSyncRateLimit: models.MustNewDuration(2 * time.Minute), + UserAPITokenDuration: commonconfig.MustNewDuration(240 * time.Hour), + UpstreamSyncInterval: commonconfig.MustNewDuration(0 * time.Second), + UpstreamSyncRateLimit: commonconfig.MustNewDuration(2 * time.Minute), }, RateLimit: toml.WebServerRateLimit{ Authenticated: ptr[int64](42), - AuthenticatedPeriod: models.MustNewDuration(time.Second), + AuthenticatedPeriod: commonconfig.MustNewDuration(time.Second), Unauthenticated: ptr[int64](7), - UnauthenticatedPeriod: models.MustNewDuration(time.Minute), + UnauthenticatedPeriod: commonconfig.MustNewDuration(time.Minute), }, TLS: toml.WebServerTLS{ CertPath: ptr("tls/cert/path"), @@ -363,14 +365,14 @@ func TestConfig_Marshal(t *testing.T) { } full.JobPipeline = toml.JobPipeline{ ExternalInitiatorsEnabled: ptr(true), - MaxRunDuration: models.MustNewDuration(time.Hour), + MaxRunDuration: commonconfig.MustNewDuration(time.Hour), MaxSuccessfulRuns: ptr[uint64](123456), - ReaperInterval: models.MustNewDuration(4 * time.Hour), - ReaperThreshold: models.MustNewDuration(7 * 24 * time.Hour), + ReaperInterval: commonconfig.MustNewDuration(4 * time.Hour), + ReaperThreshold: commonconfig.MustNewDuration(7 * 24 * time.Hour), ResultWriteQueueDepth: ptr[uint32](10), HTTPRequest: toml.JobPipelineHTTPRequest{ MaxSize: ptr[utils.FileSize](100 * utils.MB), - DefaultTimeout: models.MustNewDuration(time.Minute), + DefaultTimeout: commonconfig.MustNewDuration(time.Minute), }, } full.FluxMonitor = toml.FluxMonitor{ @@ -380,11 +382,11 @@ func TestConfig_Marshal(t *testing.T) { full.OCR2 = toml.OCR2{ Enabled: ptr(true), ContractConfirmations: ptr[uint32](11), - BlockchainTimeout: models.MustNewDuration(3 * time.Second), - ContractPollInterval: models.MustNewDuration(time.Hour), - ContractSubscribeInterval: models.MustNewDuration(time.Minute), - ContractTransmitterTransmitTimeout: models.MustNewDuration(time.Minute), - DatabaseTimeout: models.MustNewDuration(8 * time.Second), + BlockchainTimeout: commonconfig.MustNewDuration(3 * time.Second), + ContractPollInterval: commonconfig.MustNewDuration(time.Hour), + ContractSubscribeInterval: commonconfig.MustNewDuration(time.Minute), + ContractTransmitterTransmitTimeout: commonconfig.MustNewDuration(time.Minute), + DatabaseTimeout: commonconfig.MustNewDuration(8 * time.Second), KeyBundleID: ptr(models.MustSha256HashFromHex("7a5f66bbe6594259325bf2b4f5b1a9c9")), CaptureEATelemetry: ptr(false), CaptureAutomationCustomTelemetry: ptr(true), @@ -394,10 +396,10 @@ func TestConfig_Marshal(t *testing.T) { } full.OCR = toml.OCR{ Enabled: ptr(true), - ObservationTimeout: models.MustNewDuration(11 * time.Second), - BlockchainTimeout: models.MustNewDuration(3 * time.Second), - ContractPollInterval: models.MustNewDuration(time.Hour), - ContractSubscribeInterval: models.MustNewDuration(time.Minute), + ObservationTimeout: commonconfig.MustNewDuration(11 * time.Second), + BlockchainTimeout: commonconfig.MustNewDuration(3 * time.Second), + ContractPollInterval: commonconfig.MustNewDuration(time.Hour), + ContractSubscribeInterval: commonconfig.MustNewDuration(time.Minute), DefaultTransactionQueueDepth: ptr[uint32](12), KeyBundleID: ptr(models.MustSha256HashFromHex("acdd42797a8b921b2910497badc50006")), SimulateTransactions: ptr(true), @@ -410,19 +412,6 @@ func TestConfig_Marshal(t *testing.T) { OutgoingMessageBufferSize: ptr[int64](17), PeerID: mustPeerID("12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw"), TraceLogging: ptr(true), - V1: toml.P2PV1{ - Enabled: ptr(true), - AnnounceIP: mustIP("1.2.3.4"), - AnnouncePort: ptr[uint16](1234), - BootstrapCheckInterval: models.MustNewDuration(time.Minute), - DefaultBootstrapPeers: &[]string{"foo", "bar", "should", "these", "be", "typed"}, - DHTAnnouncementCounterUserPrefix: ptr[uint32](4321), - DHTLookupInterval: ptr[int64](9), - ListenIP: mustIP("4.3.2.1"), - ListenPort: ptr[uint16](9), - NewStreamTimeout: models.MustNewDuration(time.Second), - PeerstoreWriteInterval: models.MustNewDuration(time.Minute), - }, V2: toml.P2PV2{ Enabled: ptr(false), AnnounceAddresses: &[]string{"a", "b", "c"}, @@ -430,8 +419,8 @@ func TestConfig_Marshal(t *testing.T) { {PeerID: "12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw", Addrs: []string{"foo:42", "bar:10"}}, {PeerID: "12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw", Addrs: []string{"test:99"}}, }, - DeltaDial: models.MustNewDuration(time.Minute), - DeltaReconcile: models.MustNewDuration(time.Second), + DeltaDial: commonconfig.MustNewDuration(time.Minute), + DeltaReconcile: commonconfig.MustNewDuration(time.Second), ListenAddresses: &[]string{"foo", "bar"}, }, } @@ -445,7 +434,7 @@ func TestConfig_Marshal(t *testing.T) { Registry: toml.KeeperRegistry{ CheckGasOverhead: ptr[uint32](90), PerformGasOverhead: ptr[uint32](math.MaxUint32), - SyncInterval: models.MustNewDuration(time.Hour), + SyncInterval: commonconfig.MustNewDuration(time.Hour), SyncUpkeepQueueSize: ptr[uint32](31), MaxPerformDataSize: ptr[uint32](5000), }, @@ -453,9 +442,9 @@ func TestConfig_Marshal(t *testing.T) { full.AutoPprof = toml.AutoPprof{ Enabled: ptr(true), ProfileRoot: ptr("prof/root"), - PollInterval: models.MustNewDuration(time.Minute), - GatherDuration: models.MustNewDuration(12 * time.Second), - GatherTraceDuration: models.MustNewDuration(13 * time.Second), + PollInterval: commonconfig.MustNewDuration(time.Minute), + GatherDuration: commonconfig.MustNewDuration(12 * time.Second), + GatherTraceDuration: commonconfig.MustNewDuration(13 * time.Second), MaxProfileSize: ptr[utils.FileSize](utils.GB), CPUProfileRate: ptr[int64](7), MemProfileRate: ptr[int64](9), @@ -476,7 +465,7 @@ func TestConfig_Marshal(t *testing.T) { } full.EVM = []*evmcfg.EVMConfig{ { - ChainID: utils.NewBigI(1), + ChainID: ubig.NewI(1), Enabled: ptr(false), Chain: evmcfg.Chain{ AutoCreateKey: ptr(false), @@ -505,7 +494,7 @@ func TestConfig_Marshal(t *testing.T) { TipCapDefault: assets.NewWeiI(2), TipCapMin: assets.NewWeiI(1), PriceDefault: assets.NewWeiI(math.MaxInt64), - PriceMax: assets.NewWei(utils.HexToBig("FFFFFFFFFFFF")), + PriceMax: assets.NewWei(mustHexToBig(t, "FFFFFFFFFFFF")), PriceMin: assets.NewWeiI(13), LimitJobType: evmcfg.GasLimitJobType{ @@ -531,7 +520,7 @@ func TestConfig_Marshal(t *testing.T) { { Key: mustAddress("0x2a3e23c6f242F5345320814aC8a1b4E58707D292"), GasEstimator: evmcfg.KeySpecificGasEstimator{ - PriceMax: assets.NewWei(utils.HexToBig("FFFFFFFFFFFFFFFFFFFFFFFF")), + PriceMax: assets.NewWei(mustHexToBig(t, "FFFFFFFFFFFFFFFFFFFFFFFF")), }, }, }, @@ -574,8 +563,8 @@ func TestConfig_Marshal(t *testing.T) { ContractConfirmations: ptr[uint16](11), ContractTransmitterTransmitTimeout: &minute, DatabaseTimeout: &second, - DeltaCOverride: models.MustNewDuration(time.Hour), - DeltaCJitterOverride: models.MustNewDuration(time.Second), + DeltaCOverride: commonconfig.MustNewDuration(time.Hour), + DeltaCJitterOverride: commonconfig.MustNewDuration(time.Second), ObservationGracePeriod: &second, }, OCR2: evmcfg.OCR2{ @@ -672,9 +661,12 @@ func TestConfig_Marshal(t *testing.T) { } full.Mercury = toml.Mercury{ Cache: toml.MercuryCache{ - LatestReportTTL: models.MustNewDuration(100 * time.Second), - MaxStaleAge: models.MustNewDuration(101 * time.Second), - LatestReportDeadline: models.MustNewDuration(102 * time.Second), + LatestReportTTL: commonconfig.MustNewDuration(100 * time.Second), + MaxStaleAge: commonconfig.MustNewDuration(101 * time.Second), + LatestReportDeadline: commonconfig.MustNewDuration(102 * time.Second), + }, + TLS: toml.MercuryTLS{ + CertFile: ptr("/path/to/cert.pem"), }, } @@ -750,8 +742,6 @@ MaxBatchSize = 4321 SendInterval = '1m0s' SendTimeout = '5s' UseBatchSend = true -URL = '' -ServerPubKey = '' [[TelemetryIngress.Endpoints]] Network = 'EVM' @@ -872,19 +862,6 @@ OutgoingMessageBufferSize = 17 PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true -[P2P.V1] -Enabled = true -AnnounceIP = '1.2.3.4' -AnnouncePort = 1234 -BootstrapCheckInterval = '1m0s' -DefaultBootstrapPeers = ['foo', 'bar', 'should', 'these', 'be', 'typed'] -DHTAnnouncementCounterUserPrefix = 4321 -DHTLookupInterval = 9 -ListenIP = '4.3.2.1' -ListenPort = 9 -NewStreamTimeout = '1s' -PeerstoreWriteInterval = '1m0s' - [P2P.V2] Enabled = false AnnounceAddresses = ['a', 'b', 'c'] @@ -1120,6 +1097,9 @@ URL = 'http://stark.node' LatestReportTTL = '1m40s' MaxStaleAge = '1m41s' LatestReportDeadline = '1m42s' + +[Mercury.TLS] +CertFile = '/path/to/cert.pem' `}, {"full", full, fullTOML}, {"multi-chain", multiChain, multiChainTOML}, @@ -1146,7 +1126,7 @@ func TestConfig_full(t *testing.T) { for c := range got.EVM { for n := range got.EVM[c].Nodes { if got.EVM[c].Nodes[n].WSURL == nil { - got.EVM[c].Nodes[n].WSURL = new(models.URL) + got.EVM[c].Nodes[n].WSURL = new(commonconfig.URL) } if got.EVM[c].Nodes[n].SendOnly == nil { got.EVM[c].Nodes[n].SendOnly = ptr(true) @@ -1157,17 +1137,6 @@ func TestConfig_full(t *testing.T) { } } - // Except for TelemetryIngress.ServerPubKey as this will be removed in the future - // and its only use is to signal to NOPs that these fields are no longer allowed - if got.TelemetryIngress.ServerPubKey == nil { - got.TelemetryIngress.ServerPubKey = ptr("") - } - // Except for TelemetryIngress.URL as this will be removed in the future - // and its only use is to signal to NOPs that these fields are no longer allowed - if got.TelemetryIngress.URL == nil { - got.TelemetryIngress.URL = new(models.URL) - } - cfgtest.AssertFieldsNotNil(t, got) } @@ -1212,7 +1181,7 @@ func TestConfig_Validate(t *testing.T) { - 1: 6 errors: - ChainType: invalid value (Foo): must not be set with this chain id - Nodes: missing: must have at least one node - - ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix, zksync or omitted + - ChainType: invalid value (Foo): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix, zksync, scroll or omitted - HeadTracker.HistoryDepth: invalid value (30): must be equal to or greater than FinalityDepth - GasEstimator: 2 errors: - FeeCapDefault: invalid value (101 wei): must be equal to PriceMax (99 wei) since you are using FixedPrice estimation with gas bumping disabled in EIP1559 mode - PriceMax will be used as the FeeCap for transactions instead of FeeCapDefault @@ -1221,7 +1190,7 @@ func TestConfig_Validate(t *testing.T) { - 2: 5 errors: - ChainType: invalid value (Arbitrum): only "optimismBedrock" can be used with this chain id - Nodes: missing: must have at least one node - - ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix, zksync or omitted + - ChainType: invalid value (Arbitrum): must be one of arbitrum, metis, xdai, optimismBedrock, celo, kroma, wemix, zksync, scroll or omitted - FinalityDepth: invalid value (0): must be greater than or equal to 1 - MinIncomingConfirmations: invalid value (0): must be greater than or equal to 1 - 3.Nodes: 5 errors: @@ -1278,8 +1247,8 @@ func TestConfig_Validate(t *testing.T) { } } -func mustURL(s string) *models.URL { - var u models.URL +func mustURL(s string) *commonconfig.URL { + var u commonconfig.URL if err := u.UnmarshalText([]byte(s)); err != nil { panic(err) } @@ -1320,19 +1289,7 @@ func Test_generalConfig_LogConfiguration(t *testing.T) { effective = "# Effective Configuration, with defaults applied:\n" warning = "# Configuration warning:\n" - deprecated = `2 errors: - - P2P.V1: is deprecated and will be removed in a future version - - P2P.V1: 10 errors: - - AnnounceIP: is deprecated and will be removed in a future version - - AnnouncePort: is deprecated and will be removed in a future version - - BootstrapCheckInterval: is deprecated and will be removed in a future version - - DefaultBootstrapPeers: is deprecated and will be removed in a future version - - DHTAnnouncementCounterUserPrefix: is deprecated and will be removed in a future version - - DHTLookupInterval: is deprecated and will be removed in a future version - - ListenIP: is deprecated and will be removed in a future version - - ListenPort: is deprecated and will be removed in a future version - - NewStreamTimeout: is deprecated and will be removed in a future version - - PeerstoreWriteInterval: is deprecated and will be removed in a future version` + deprecated = `` // none ) tests := []struct { name string @@ -1504,7 +1461,7 @@ func assertValidationError(t *testing.T, invalid interface{ Validate() error }, func TestConfig_setDefaults(t *testing.T) { var c Config - c.EVM = evmcfg.EVMConfigs{{ChainID: utils.NewBigI(99999133712345)}} + c.EVM = evmcfg.EVMConfigs{{ChainID: ubig.NewI(99999133712345)}} c.Cosmos = coscfg.TOMLConfigs{{ChainID: ptr("unknown cosmos chain")}} c.Solana = solana.TOMLConfigs{{ChainID: ptr("unknown solana chain")}} c.Starknet = stkcfg.TOMLConfigs{{ChainID: ptr("unknown starknet chain")}} @@ -1558,7 +1515,7 @@ func TestConfig_SetFrom(t *testing.T) { } } -func TestConfig_Warnings(t *testing.T) { +func TestConfig_warnings(t *testing.T) { tests := []struct { name string config Config @@ -1582,42 +1539,6 @@ func TestConfig_Warnings(t *testing.T) { }, expectedErrors: []string{"Tracing.TLSCertPath: invalid value (/path/to/cert.pem): must be empty when Tracing.Mode is 'unencrypted'"}, }, - { - name: "Deprecation warning - P2P.V1 fields set", - config: Config{ - Core: toml.Core{ - P2P: toml.P2P{ - V1: toml.P2PV1{ - Enabled: ptr(true), - }, - }, - }, - }, - expectedErrors: []string{ - "P2P.V1: is deprecated and will be removed in a future version", - }, - }, - { - name: "Value warning and deprecation warning", - config: Config{ - Core: toml.Core{ - P2P: toml.P2P{ - V1: toml.P2PV1{ - Enabled: ptr(true), - }, - }, - Tracing: toml.Tracing{ - Enabled: ptr(true), - Mode: ptr("unencrypted"), - TLSCertPath: ptr("/path/to/cert.pem"), - }, - }, - }, - expectedErrors: []string{ - "Tracing.TLSCertPath: invalid value (/path/to/cert.pem): must be empty when Tracing.Mode is 'unencrypted'", - "P2P.V1: is deprecated and will be removed in a future version", - }, - }, } for _, tt := range tests { @@ -1635,3 +1556,9 @@ func TestConfig_Warnings(t *testing.T) { } func ptr[T any](t T) *T { return &t } + +func mustHexToBig(t *testing.T, hx string) *big.Int { + n, err := hex.ParseBig(hx) + require.NoError(t, err) + return n +} diff --git a/core/services/chainlink/config_web_server.go b/core/services/chainlink/config_web_server.go index 06db398e2ea..473f70a4c9c 100644 --- a/core/services/chainlink/config_web_server.go +++ b/core/services/chainlink/config_web_server.go @@ -9,9 +9,9 @@ import ( "github.com/gin-contrib/sessions" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) var _ config.WebServer = (*webServerConfig)(nil) @@ -153,7 +153,7 @@ func (w *webServerConfig) HTTPPort() uint16 { return *w.c.HTTPPort } -func (w *webServerConfig) SessionReaperExpiration() models.Duration { +func (w *webServerConfig) SessionReaperExpiration() commonconfig.Duration { return *w.c.SessionReaperExpiration } @@ -170,8 +170,8 @@ func (w *webServerConfig) SessionOptions() sessions.Options { } } -func (w *webServerConfig) SessionTimeout() models.Duration { - return models.MustMakeDuration(w.c.SessionTimeout.Duration()) +func (w *webServerConfig) SessionTimeout() commonconfig.Duration { + return *commonconfig.MustNewDuration(w.c.SessionTimeout.Duration()) } func (w *webServerConfig) ListenIP() net.IP { @@ -211,7 +211,7 @@ func (l *ldapConfig) ServerTLS() bool { return *l.c.ServerTLS } -func (l *ldapConfig) SessionTimeout() models.Duration { +func (l *ldapConfig) SessionTimeout() commonconfig.Duration { return *l.c.SessionTimeout } @@ -219,7 +219,7 @@ func (l *ldapConfig) QueryTimeout() time.Duration { return l.c.QueryTimeout.Duration() } -func (l *ldapConfig) UserAPITokenDuration() models.Duration { +func (l *ldapConfig) UserAPITokenDuration() commonconfig.Duration { return *l.c.UserAPITokenDuration } @@ -300,16 +300,16 @@ func (l *ldapConfig) UserApiTokenEnabled() bool { return *l.c.UserApiTokenEnabled } -func (l *ldapConfig) UpstreamSyncInterval() models.Duration { +func (l *ldapConfig) UpstreamSyncInterval() commonconfig.Duration { if l.c.UpstreamSyncInterval == nil { - return models.Duration{} + return commonconfig.Duration{} } return *l.c.UpstreamSyncInterval } -func (l *ldapConfig) UpstreamSyncRateLimit() models.Duration { +func (l *ldapConfig) UpstreamSyncRateLimit() commonconfig.Duration { if l.c.UpstreamSyncRateLimit == nil { - return models.Duration{} + return commonconfig.Duration{} } return *l.c.UpstreamSyncRateLimit } diff --git a/core/services/chainlink/config_web_server_test.go b/core/services/chainlink/config_web_server_test.go index 92e8dde460a..946e0b0c12b 100644 --- a/core/services/chainlink/config_web_server_test.go +++ b/core/services/chainlink/config_web_server_test.go @@ -4,10 +4,10 @@ import ( "testing" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestWebServerConfig(t *testing.T) { @@ -24,8 +24,8 @@ func TestWebServerConfig(t *testing.T) { assert.Equal(t, 1*time.Minute, ws.HTTPWriteTimeout()) assert.Equal(t, uint16(56), ws.HTTPPort()) assert.True(t, ws.SecureCookies()) - assert.Equal(t, *models.MustNewDuration(1 * time.Hour), ws.SessionTimeout()) - assert.Equal(t, *models.MustNewDuration(168 * time.Hour), ws.SessionReaperExpiration()) + assert.Equal(t, *commonconfig.MustNewDuration(1 * time.Hour), ws.SessionTimeout()) + assert.Equal(t, *commonconfig.MustNewDuration(168 * time.Hour), ws.SessionReaperExpiration()) assert.Equal(t, int64(32770), ws.HTTPMaxSize()) assert.Equal(t, 15*time.Second, ws.StartTimeout()) tls := ws.TLS() diff --git a/core/services/chainlink/mocks/general_config.go b/core/services/chainlink/mocks/general_config.go index 98796e90053..1dd85875395 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -30,6 +30,10 @@ type GeneralConfig struct { func (_m *GeneralConfig) 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() @@ -46,6 +50,10 @@ func (_m *GeneralConfig) AppID() uuid.UUID { func (_m *GeneralConfig) AuditLogger() config.AuditLogger { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AuditLogger") + } + var r0 config.AuditLogger if rf, ok := ret.Get(0).(func() config.AuditLogger); ok { r0 = rf() @@ -62,6 +70,10 @@ func (_m *GeneralConfig) AuditLogger() config.AuditLogger { func (_m *GeneralConfig) AutoPprof() config.AutoPprof { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for AutoPprof") + } + var r0 config.AutoPprof if rf, ok := ret.Get(0).(func() config.AutoPprof); ok { r0 = rf() @@ -78,6 +90,10 @@ func (_m *GeneralConfig) AutoPprof() config.AutoPprof { func (_m *GeneralConfig) ConfigTOML() (string, string) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ConfigTOML") + } + var r0 string var r1 string if rf, ok := ret.Get(0).(func() (string, string)); ok { @@ -102,6 +118,10 @@ func (_m *GeneralConfig) ConfigTOML() (string, string) { func (_m *GeneralConfig) CosmosConfigs() cosmosconfig.TOMLConfigs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CosmosConfigs") + } + var r0 cosmosconfig.TOMLConfigs if rf, ok := ret.Get(0).(func() cosmosconfig.TOMLConfigs); ok { r0 = rf() @@ -118,6 +138,10 @@ func (_m *GeneralConfig) CosmosConfigs() cosmosconfig.TOMLConfigs { func (_m *GeneralConfig) 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() @@ -132,6 +156,10 @@ func (_m *GeneralConfig) CosmosEnabled() bool { func (_m *GeneralConfig) Database() config.Database { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Database") + } + var r0 config.Database if rf, ok := ret.Get(0).(func() config.Database); ok { r0 = rf() @@ -148,6 +176,10 @@ func (_m *GeneralConfig) Database() config.Database { func (_m *GeneralConfig) EVMConfigs() toml.EVMConfigs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for EVMConfigs") + } + var r0 toml.EVMConfigs if rf, ok := ret.Get(0).(func() toml.EVMConfigs); ok { r0 = rf() @@ -164,6 +196,10 @@ func (_m *GeneralConfig) EVMConfigs() toml.EVMConfigs { func (_m *GeneralConfig) 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() @@ -178,6 +214,10 @@ func (_m *GeneralConfig) EVMEnabled() bool { func (_m *GeneralConfig) 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() @@ -192,6 +232,10 @@ func (_m *GeneralConfig) EVMRPCEnabled() bool { func (_m *GeneralConfig) Feature() config.Feature { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Feature") + } + var r0 config.Feature if rf, ok := ret.Get(0).(func() config.Feature); ok { r0 = rf() @@ -208,6 +252,10 @@ func (_m *GeneralConfig) Feature() config.Feature { func (_m *GeneralConfig) FluxMonitor() config.FluxMonitor { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FluxMonitor") + } + var r0 config.FluxMonitor if rf, ok := ret.Get(0).(func() config.FluxMonitor); ok { r0 = rf() @@ -224,6 +272,10 @@ func (_m *GeneralConfig) FluxMonitor() config.FluxMonitor { func (_m *GeneralConfig) Insecure() config.Insecure { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Insecure") + } + var r0 config.Insecure if rf, ok := ret.Get(0).(func() config.Insecure); ok { r0 = rf() @@ -240,6 +292,10 @@ func (_m *GeneralConfig) Insecure() config.Insecure { func (_m *GeneralConfig) 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() @@ -254,6 +310,10 @@ func (_m *GeneralConfig) InsecureFastScrypt() bool { func (_m *GeneralConfig) JobPipeline() config.JobPipeline { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for JobPipeline") + } + var r0 config.JobPipeline if rf, ok := ret.Get(0).(func() config.JobPipeline); ok { r0 = rf() @@ -270,6 +330,10 @@ func (_m *GeneralConfig) JobPipeline() config.JobPipeline { func (_m *GeneralConfig) Keeper() config.Keeper { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Keeper") + } + var r0 config.Keeper if rf, ok := ret.Get(0).(func() config.Keeper); ok { r0 = rf() @@ -286,6 +350,10 @@ func (_m *GeneralConfig) Keeper() config.Keeper { func (_m *GeneralConfig) Log() config.Log { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Log") + } + var r0 config.Log if rf, ok := ret.Get(0).(func() config.Log); ok { r0 = rf() @@ -307,6 +375,10 @@ func (_m *GeneralConfig) LogConfiguration(log config.LogfFn, warn config.LogfFn) func (_m *GeneralConfig) Mercury() config.Mercury { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Mercury") + } + var r0 config.Mercury if rf, ok := ret.Get(0).(func() config.Mercury); ok { r0 = rf() @@ -323,6 +395,10 @@ func (_m *GeneralConfig) Mercury() config.Mercury { func (_m *GeneralConfig) OCR() config.OCR { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OCR") + } + var r0 config.OCR if rf, ok := ret.Get(0).(func() config.OCR); ok { r0 = rf() @@ -339,6 +415,10 @@ func (_m *GeneralConfig) OCR() config.OCR { func (_m *GeneralConfig) OCR2() config.OCR2 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OCR2") + } + var r0 config.OCR2 if rf, ok := ret.Get(0).(func() config.OCR2); ok { r0 = rf() @@ -355,6 +435,10 @@ func (_m *GeneralConfig) OCR2() config.OCR2 { func (_m *GeneralConfig) P2P() config.P2P { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for P2P") + } + var r0 config.P2P if rf, ok := ret.Get(0).(func() config.P2P); ok { r0 = rf() @@ -371,6 +455,10 @@ func (_m *GeneralConfig) P2P() config.P2P { func (_m *GeneralConfig) Password() config.Password { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Password") + } + var r0 config.Password if rf, ok := ret.Get(0).(func() config.Password); ok { r0 = rf() @@ -387,6 +475,10 @@ func (_m *GeneralConfig) Password() config.Password { func (_m *GeneralConfig) Prometheus() config.Prometheus { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Prometheus") + } + var r0 config.Prometheus if rf, ok := ret.Get(0).(func() config.Prometheus); ok { r0 = rf() @@ -403,6 +495,10 @@ func (_m *GeneralConfig) Prometheus() config.Prometheus { func (_m *GeneralConfig) Pyroscope() config.Pyroscope { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Pyroscope") + } + var r0 config.Pyroscope if rf, ok := ret.Get(0).(func() config.Pyroscope); ok { r0 = rf() @@ -419,6 +515,10 @@ func (_m *GeneralConfig) Pyroscope() config.Pyroscope { func (_m *GeneralConfig) 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() @@ -433,6 +533,10 @@ func (_m *GeneralConfig) RootDir() string { func (_m *GeneralConfig) Sentry() config.Sentry { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Sentry") + } + var r0 config.Sentry if rf, ok := ret.Get(0).(func() config.Sentry); ok { r0 = rf() @@ -449,6 +553,10 @@ func (_m *GeneralConfig) Sentry() config.Sentry { func (_m *GeneralConfig) 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) @@ -473,6 +581,10 @@ func (_m *GeneralConfig) SetPasswords(keystore *string, vrf *string) { func (_m *GeneralConfig) 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() @@ -487,6 +599,10 @@ func (_m *GeneralConfig) ShutdownGracePeriod() time.Duration { func (_m *GeneralConfig) SolanaConfigs() solana.TOMLConfigs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SolanaConfigs") + } + var r0 solana.TOMLConfigs if rf, ok := ret.Get(0).(func() solana.TOMLConfigs); ok { r0 = rf() @@ -503,6 +619,10 @@ func (_m *GeneralConfig) SolanaConfigs() solana.TOMLConfigs { func (_m *GeneralConfig) 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() @@ -517,6 +637,10 @@ func (_m *GeneralConfig) SolanaEnabled() bool { func (_m *GeneralConfig) 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() @@ -531,6 +655,10 @@ func (_m *GeneralConfig) StarkNetEnabled() bool { func (_m *GeneralConfig) StarknetConfigs() chainlinkconfig.TOMLConfigs { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StarknetConfigs") + } + var r0 chainlinkconfig.TOMLConfigs if rf, ok := ret.Get(0).(func() chainlinkconfig.TOMLConfigs); ok { r0 = rf() @@ -547,6 +675,10 @@ func (_m *GeneralConfig) StarknetConfigs() chainlinkconfig.TOMLConfigs { func (_m *GeneralConfig) TelemetryIngress() config.TelemetryIngress { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for TelemetryIngress") + } + var r0 config.TelemetryIngress if rf, ok := ret.Get(0).(func() config.TelemetryIngress); ok { r0 = rf() @@ -563,6 +695,10 @@ func (_m *GeneralConfig) TelemetryIngress() config.TelemetryIngress { func (_m *GeneralConfig) Threshold() config.Threshold { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Threshold") + } + var r0 config.Threshold if rf, ok := ret.Get(0).(func() config.Threshold); ok { r0 = rf() @@ -579,6 +715,10 @@ func (_m *GeneralConfig) Threshold() config.Threshold { func (_m *GeneralConfig) Tracing() config.Tracing { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Tracing") + } + var r0 config.Tracing if rf, ok := ret.Get(0).(func() config.Tracing); ok { r0 = rf() @@ -595,6 +735,10 @@ func (_m *GeneralConfig) Tracing() config.Tracing { func (_m *GeneralConfig) 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() @@ -609,6 +753,10 @@ func (_m *GeneralConfig) Validate() error { func (_m *GeneralConfig) 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() @@ -623,6 +771,10 @@ func (_m *GeneralConfig) ValidateDB() error { func (_m *GeneralConfig) WebServer() config.WebServer { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for WebServer") + } + var r0 config.WebServer if rf, ok := ret.Get(0).(func() config.WebServer); ok { r0 = rf() diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index 6a5445d9f21..ea1a9ec3746 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -9,32 +9,32 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - commoncfg "github.com/smartcontractkit/chainlink-common/pkg/config" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/loop" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + coscfg "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos/config" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" stkcfg "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/config" "github.com/smartcontractkit/chainlink-solana/pkg/solana" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "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/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/relay" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/plugins" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestCoreRelayerChainInteroperators(t *testing.T) { - evmChainID1, evmChainID2 := utils.NewBig(big.NewInt(1)), utils.NewBig(big.NewInt(2)) + evmChainID1, evmChainID2 := ubig.New(big.NewInt(1)), ubig.New(big.NewInt(2)) solanaChainID1, solanaChainID2 := "solana-id-1", "solana-id-2" starknetChainID1, starknetChainID2 := "starknet-id-1", "starknet-id-2" cosmosChainID1, cosmosChainID2 := "cosmos-id-1", "cosmos-id-2" @@ -44,22 +44,22 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { cfg := evmcfg.Defaults(evmChainID1) node1_1 := evmcfg.Node{ Name: ptr("Test node chain1:1"), - WSURL: models.MustParseURL("ws://localhost:8546"), - HTTPURL: models.MustParseURL("http://localhost:8546"), + WSURL: commonconfig.MustParseURL("ws://localhost:8546"), + HTTPURL: commonconfig.MustParseURL("http://localhost:8546"), SendOnly: ptr(false), Order: ptr(int32(15)), } node1_2 := evmcfg.Node{ Name: ptr("Test node chain1:2"), - WSURL: models.MustParseURL("ws://localhost:8547"), - HTTPURL: models.MustParseURL("http://localhost:8547"), + WSURL: commonconfig.MustParseURL("ws://localhost:8547"), + HTTPURL: commonconfig.MustParseURL("http://localhost:8547"), SendOnly: ptr(false), Order: ptr(int32(36)), } node2_1 := evmcfg.Node{ Name: ptr("Test node chain2:1"), - WSURL: models.MustParseURL("ws://localhost:8547"), - HTTPURL: models.MustParseURL("http://localhost:8547"), + WSURL: commonconfig.MustParseURL("ws://localhost:8547"), + HTTPURL: commonconfig.MustParseURL("http://localhost:8547"), SendOnly: ptr(false), Order: ptr(int32(11)), } @@ -69,7 +69,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: cfg, Nodes: evmcfg.EVMNodes{&node1_1, &node1_2}, } - id2 := utils.NewBig(big.NewInt(2)) + id2 := ubig.New(big.NewInt(2)) c.EVM = append(c.EVM, &evmcfg.EVMConfig{ ChainID: evmChainID2, Chain: evmcfg.Defaults(id2), @@ -84,7 +84,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{{ Name: ptr("solana chain 1 node 1"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8547").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8547").URL())), }}, }, &solana.TOMLConfig{ @@ -93,7 +93,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Chain: solcfg.Chain{}, Nodes: []*solcfg.Node{{ Name: ptr("solana chain 2 node 1"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8527").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8527").URL())), }}, }, } @@ -106,15 +106,15 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: []*stkcfg.Node{ { Name: ptr("starknet chain 1 node 1"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8547").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8547").URL())), }, { Name: ptr("starknet chain 1 node 2"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8548").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8548").URL())), }, { Name: ptr("starknet chain 1 node 3"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:8549").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:8549").URL())), }, }, }, @@ -125,7 +125,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: []*stkcfg.Node{ { Name: ptr("starknet chain 2 node 1"), - URL: ((*commoncfg.URL)(models.MustParseURL("http://localhost:3547").URL())), + URL: ((*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:3547").URL())), }, }, }, @@ -143,7 +143,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: coscfg.Nodes{ &coscfg.Node{ Name: ptr("cosmos chain 1 node 1"), - TendermintURL: (*commoncfg.URL)(models.MustParseURL("http://localhost:9548").URL()), + TendermintURL: (*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:9548").URL()), }, }, }, @@ -158,7 +158,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { Nodes: coscfg.Nodes{ &coscfg.Node{ Name: ptr("cosmos chain 2 node 1"), - TendermintURL: (*commoncfg.URL)(models.MustParseURL("http://localhost:9598").URL()), + TendermintURL: (*commonconfig.URL)(commonconfig.MustParseURL("http://localhost:9598").URL()), }, }, }, @@ -204,10 +204,9 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { initFuncs: []chainlink.CoreRelayerChainInitFunc{ chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &utils.MailboxMonitor{}, - DB: db, + AppConfig: cfg, + MailMon: &mailbox.Monitor{}, + DB: db, }, CSAETHKeystore: keyStore, }), @@ -215,8 +214,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedEVMChainCnt: 2, expectedEVMNodeCnt: 3, expectedEVMRelayerIds: []relay.ID{ - {Network: relay.EVM, ChainID: relay.ChainID(evmChainID1.String())}, - {Network: relay.EVM, ChainID: relay.ChainID(evmChainID2.String())}, + {Network: relay.EVM, ChainID: evmChainID1.String()}, + {Network: relay.EVM, ChainID: evmChainID2.String()}, }, expectedRelayerNetworks: map[relay.Network]struct{}{relay.EVM: {}}, }, @@ -231,8 +230,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedSolanaChainCnt: 2, expectedSolanaNodeCnt: 2, expectedSolanaRelayerIds: []relay.ID{ - {Network: relay.Solana, ChainID: relay.ChainID(solanaChainID1)}, - {Network: relay.Solana, ChainID: relay.ChainID(solanaChainID2)}, + {Network: relay.Solana, ChainID: solanaChainID1}, + {Network: relay.Solana, ChainID: solanaChainID2}, }, expectedRelayerNetworks: map[relay.Network]struct{}{relay.Solana: {}}, }, @@ -247,8 +246,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedStarknetChainCnt: 2, expectedStarknetNodeCnt: 4, expectedStarknetRelayerIds: []relay.ID{ - {Network: relay.StarkNet, ChainID: relay.ChainID(starknetChainID1)}, - {Network: relay.StarkNet, ChainID: relay.ChainID(starknetChainID2)}, + {Network: relay.StarkNet, ChainID: starknetChainID1}, + {Network: relay.StarkNet, ChainID: starknetChainID2}, }, expectedRelayerNetworks: map[relay.Network]struct{}{relay.StarkNet: {}}, }, @@ -265,8 +264,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedCosmosChainCnt: 2, expectedCosmosNodeCnt: 2, expectedCosmosRelayerIds: []relay.ID{ - {Network: relay.Cosmos, ChainID: relay.ChainID(cosmosChainID1)}, - {Network: relay.Cosmos, ChainID: relay.ChainID(cosmosChainID2)}, + {Network: relay.Cosmos, ChainID: cosmosChainID1}, + {Network: relay.Cosmos, ChainID: cosmosChainID2}, }, expectedRelayerNetworks: map[relay.Network]struct{}{relay.Cosmos: {}}, }, @@ -278,10 +277,10 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { TOMLConfigs: cfg.SolanaConfigs()}), chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ - AppConfig: cfg, - EventBroadcaster: pg.NewNullEventBroadcaster(), - MailMon: &utils.MailboxMonitor{}, - DB: db, + AppConfig: cfg, + + MailMon: &mailbox.Monitor{}, + DB: db, }, CSAETHKeystore: keyStore, }), @@ -298,29 +297,29 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { expectedEVMChainCnt: 2, expectedEVMNodeCnt: 3, expectedEVMRelayerIds: []relay.ID{ - {Network: relay.EVM, ChainID: relay.ChainID(evmChainID1.String())}, - {Network: relay.EVM, ChainID: relay.ChainID(evmChainID2.String())}, + {Network: relay.EVM, ChainID: evmChainID1.String()}, + {Network: relay.EVM, ChainID: evmChainID2.String()}, }, expectedSolanaChainCnt: 2, expectedSolanaNodeCnt: 2, expectedSolanaRelayerIds: []relay.ID{ - {Network: relay.Solana, ChainID: relay.ChainID(solanaChainID1)}, - {Network: relay.Solana, ChainID: relay.ChainID(solanaChainID2)}, + {Network: relay.Solana, ChainID: solanaChainID1}, + {Network: relay.Solana, ChainID: solanaChainID2}, }, expectedStarknetChainCnt: 2, expectedStarknetNodeCnt: 4, expectedStarknetRelayerIds: []relay.ID{ - {Network: relay.StarkNet, ChainID: relay.ChainID(starknetChainID1)}, - {Network: relay.StarkNet, ChainID: relay.ChainID(starknetChainID2)}, + {Network: relay.StarkNet, ChainID: starknetChainID1}, + {Network: relay.StarkNet, ChainID: starknetChainID2}, }, expectedCosmosChainCnt: 2, expectedCosmosNodeCnt: 2, expectedCosmosRelayerIds: []relay.ID{ - {Network: relay.Cosmos, ChainID: relay.ChainID(cosmosChainID1)}, - {Network: relay.Cosmos, ChainID: relay.ChainID(cosmosChainID2)}, + {Network: relay.Cosmos, ChainID: cosmosChainID1}, + {Network: relay.Cosmos, ChainID: cosmosChainID2}, }, expectedRelayerNetworks: map[relay.Network]struct{}{relay.EVM: {}, relay.Cosmos: {}, relay.Solana: {}, relay.StarkNet: {}}, diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 8b8749013fc..c42ca77dc39 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -5,9 +5,8 @@ import ( "errors" "fmt" - "github.com/pelletier/go-toml/v2" - "github.com/jmoiron/sqlx" + "github.com/pelletier/go-toml/v2" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos" @@ -46,9 +45,11 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m relayers := make(map[relay.ID]evmrelay.LoopRelayAdapter) + lggr := r.Logger.Named("EVM") + // override some common opts with the factory values. this seems weird... maybe other signatures should change, or this should take a different type... ccOpts := legacyevm.ChainRelayExtenderConfig{ - Logger: r.Logger.Named("EVM"), + Logger: lggr, KeyStore: config.CSAETHKeystore.Eth(), ChainOpts: config.ChainOpts, } @@ -66,13 +67,12 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m } relayerOpts := evmrelay.RelayerOpts{ - DB: ccOpts.DB, - QConfig: ccOpts.AppConfig.Database(), - CSAETHKeystore: config.CSAETHKeystore, - EventBroadcaster: ccOpts.EventBroadcaster, - MercuryPool: r.MercuryPool, + DB: ccOpts.DB, + QConfig: ccOpts.AppConfig.Database(), + CSAETHKeystore: config.CSAETHKeystore, + MercuryPool: r.MercuryPool, } - relayer, err2 := evmrelay.NewRelayer(r.Logger.Named("EVM").Named(relayID.ChainID), chain, relayerOpts) + relayer, err2 := evmrelay.NewRelayer(lggr.Named(relayID.ChainID), chain, relayerOpts) if err2 != nil { err = errors.Join(err, err2) continue @@ -116,7 +116,7 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.TOMLConf lggr := solLggr.Named(relayID.ChainID) - if cmdName := env.SolanaPluginCmd.Get(); cmdName != "" { + if cmdName := env.SolanaPlugin.Cmd.Get(); cmdName != "" { // setup the solana relayer to be a LOOP cfgTOML, err := toml.Marshal(struct { @@ -126,10 +126,14 @@ func (r *RelayerFactory) NewSolana(ks keystore.Solana, chainCfgs solana.TOMLConf if err != nil { return nil, fmt.Errorf("failed to marshal Solana configs: %w", err) } - + envVars, err := plugins.ParseEnvFile(env.SolanaPlugin.Env.Get()) + if err != nil { + return nil, fmt.Errorf("failed to parse Solana env file: %w", err) + } solCmdFn, err := plugins.NewCmdFactory(r.Register, plugins.CmdConfig{ ID: relayID.Name(), Cmd: cmdName, + Env: envVars, }) if err != nil { return nil, fmt.Errorf("failed to create Solana LOOP command: %w", err) @@ -187,7 +191,7 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOML lggr := starkLggr.Named(relayID.ChainID) - if cmdName := env.StarknetPluginCmd.Get(); cmdName != "" { + if cmdName := env.StarknetPlugin.Cmd.Get(); cmdName != "" { // setup the starknet relayer to be a LOOP cfgTOML, err := toml.Marshal(struct { Starknet config.TOMLConfig @@ -196,9 +200,14 @@ func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs config.TOML return nil, fmt.Errorf("failed to marshal StarkNet configs: %w", err) } + envVars, err := plugins.ParseEnvFile(env.StarknetPlugin.Env.Get()) + if err != nil { + return nil, fmt.Errorf("failed to parse Starknet env file: %w", err) + } starknetCmdFn, err := plugins.NewCmdFactory(r.Register, plugins.CmdConfig{ ID: relayID.Name(), Cmd: cmdName, + Env: envVars, }) if err != nil { return nil, fmt.Errorf("failed to create StarkNet LOOP command: %w", err) diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index 2531e7c281d..148f6b24ff5 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -40,8 +40,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false @@ -161,19 +159,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -240,3 +225,6 @@ TLSCertPath = '' LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' + +[Mercury.TLS] +CertFile = '' diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index 46d9dc2c239..bc1b124ccb6 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -40,8 +40,6 @@ MaxBatchSize = 4321 SendInterval = '1m0s' SendTimeout = '5s' UseBatchSend = true -URL = '' -ServerPubKey = '' [[TelemetryIngress.Endpoints]] Network = 'EVM' @@ -167,19 +165,6 @@ OutgoingMessageBufferSize = 17 PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true -[P2P.V1] -Enabled = true -AnnounceIP = '1.2.3.4' -AnnouncePort = 1234 -BootstrapCheckInterval = '1m0s' -DefaultBootstrapPeers = ['foo', 'bar', 'should', 'these', 'be', 'typed'] -DHTAnnouncementCounterUserPrefix = 4321 -DHTLookupInterval = 9 -ListenIP = '4.3.2.1' -ListenPort = 9 -NewStreamTimeout = '1s' -PeerstoreWriteInterval = '1m0s' - [P2P.V2] Enabled = false AnnounceAddresses = ['a', 'b', 'c'] @@ -251,6 +236,9 @@ LatestReportTTL = '1m40s' MaxStaleAge = '1m41s' LatestReportDeadline = '1m42s' +[Mercury.TLS] +CertFile = '/path/to/cert.pem' + [[EVM]] ChainID = '1' Enabled = false diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index 74d83035cd5..bd64ae04812 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -40,8 +40,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = true @@ -161,19 +159,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -241,6 +226,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/core/services/directrequest/delegate.go b/core/services/directrequest/delegate.go index a21029ea177..cfdf1eed116 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/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -21,7 +22,6 @@ import ( "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" ) type ( @@ -31,7 +31,7 @@ type ( pipelineORM pipeline.ORM chHeads chan *evmtypes.Head legacyChains legacyevm.LegacyChainContainer - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } Config interface { @@ -47,7 +47,7 @@ func NewDelegate( pipelineRunner pipeline.Runner, pipelineORM pipeline.ORM, legacyChains legacyevm.LegacyChainContainer, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, ) *Delegate { return &Delegate{ logger: logger.Named("DirectRequest"), @@ -101,8 +101,8 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { pipelineORM: d.pipelineORM, mailMon: d.mailMon, job: jb, - mbOracleRequests: utils.NewHighCapacityMailbox[log.Broadcast](), - mbOracleCancelRequests: utils.NewHighCapacityMailbox[log.Broadcast](), + mbOracleRequests: mailbox.NewHighCapacity[log.Broadcast](), + mbOracleCancelRequests: mailbox.NewHighCapacity[log.Broadcast](), minIncomingConfirmations: concreteSpec.MinIncomingConfirmations.Uint32, requesters: concreteSpec.Requesters, minContractPayment: concreteSpec.MinContractPayment, @@ -127,12 +127,12 @@ type listener struct { oracle operator_wrapper.OperatorInterface pipelineRunner pipeline.Runner pipelineORM pipeline.ORM - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor job job.Job runs sync.Map // map[string]services.StopChan shutdownWaitGroup sync.WaitGroup - mbOracleRequests *utils.Mailbox[log.Broadcast] - mbOracleCancelRequests *utils.Mailbox[log.Broadcast] + mbOracleRequests *mailbox.Mailbox[log.Broadcast] + mbOracleCancelRequests *mailbox.Mailbox[log.Broadcast] minIncomingConfirmations uint32 requesters models.AddressCollection minContractPayment *assets.Link @@ -238,7 +238,7 @@ func (l *listener) processCancelOracleRequests() { } } -func (l *listener) handleReceivedLogs(mailbox *utils.Mailbox[log.Broadcast]) { +func (l *listener) handleReceivedLogs(mailbox *mailbox.Mailbox[log.Broadcast]) { for { select { case <-l.chStop: diff --git a/core/services/directrequest/delegate_test.go b/core/services/directrequest/delegate_test.go index 56c28e57458..3b80ba2f915 100644 --- a/core/services/directrequest/delegate_test.go +++ b/core/services/directrequest/delegate_test.go @@ -14,9 +14,13 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -31,8 +35,6 @@ import ( "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" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestDelegate_ServicesForSpec(t *testing.T) { @@ -43,7 +45,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) relayerExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, Client: ethClient, MailMon: mailMon, KeyStore: keyStore.Eth()}) lggr := logger.TestLogger(t) @@ -57,7 +59,7 @@ func TestDelegate_ServicesForSpec(t *testing.T) { }) t.Run("Spec with DirectRequestSpec", func(t *testing.T) { - spec := job.Job{DirectRequestSpec: &job.DirectRequestSpec{EVMChainID: (*utils.Big)(testutils.FixtureChainID)}, PipelineSpec: &pipeline.Spec{}} + spec := job.Job{DirectRequestSpec: &job.DirectRequestSpec{EVMChainID: (*ubig.Big)(testutils.FixtureChainID)}, PipelineSpec: &pipeline.Spec{}} services, err := delegate.ServicesForSpec(spec) require.NoError(t, err) assert.Len(t, services, 1) @@ -80,7 +82,7 @@ func NewDirectRequestUniverseWithConfig(t *testing.T, cfg chainlink.GeneralConfi runner := pipeline_mocks.NewRunner(t) broadcaster.On("AddDependents", 1) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) diff --git a/core/services/directrequest/validate.go b/core/services/directrequest/validate.go index bc31f09b685..271e720660f 100644 --- a/core/services/directrequest/validate.go +++ b/core/services/directrequest/validate.go @@ -5,18 +5,18 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type DirectRequestToml struct { ContractAddress ethkey.EIP55Address `toml:"contractAddress"` Requesters models.AddressCollection `toml:"requesters"` MinContractPayment *assets.Link `toml:"minContractPaymentLinkJuels"` - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` MinIncomingConfirmations null.Uint32 `toml:"minIncomingConfirmations"` } diff --git a/core/services/feeds/config.go b/core/services/feeds/config.go index 605e70c24c9..141e4910960 100644 --- a/core/services/feeds/config.go +++ b/core/services/feeds/config.go @@ -3,11 +3,11 @@ package feeds import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) type JobConfig interface { - DefaultHTTPTimeout() models.Duration + DefaultHTTPTimeout() commonconfig.Duration } type InsecureConfig interface { diff --git a/core/services/feeds/mocks/config.go b/core/services/feeds/mocks/config.go deleted file mode 100644 index f2e4dcaa883..00000000000 --- a/core/services/feeds/mocks/config.go +++ /dev/null @@ -1,292 +0,0 @@ -// Code generated by mockery v2.22.1. DO NOT EDIT. - -package mocks - -import ( - time "time" - - models "github.com/smartcontractkit/chainlink/v2/core/store/models" - mock "github.com/stretchr/testify/mock" -) - -// Config is an autogenerated mock type for the Config type -type Config struct { - mock.Mock -} - -// DatabaseDefaultQueryTimeout provides a mock function with given fields: -func (_m *Config) DatabaseDefaultQueryTimeout() time.Duration { - ret := _m.Called() - - 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 -} - -// DefaultHTTPTimeout provides a mock function with given fields: -func (_m *Config) DefaultHTTPTimeout() models.Duration { - ret := _m.Called() - - var r0 models.Duration - if rf, ok := ret.Get(0).(func() models.Duration); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(models.Duration) - } - - return r0 -} - -// Dev provides a mock function with given fields: -func (_m *Config) Dev() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// FeatureOffchainReporting provides a mock function with given fields: -func (_m *Config) FeatureOffchainReporting() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// FeatureOffchainReporting2 provides a mock function with given fields: -func (_m *Config) FeatureOffchainReporting2() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// JobPipelineMaxSuccessfulRuns provides a mock function with given fields: -func (_m *Config) JobPipelineMaxSuccessfulRuns() uint64 { - ret := _m.Called() - - var r0 uint64 - if rf, ok := ret.Get(0).(func() uint64); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint64) - } - - return r0 -} - -// JobPipelineResultWriteQueueDepth provides a mock function with given fields: -func (_m *Config) JobPipelineResultWriteQueueDepth() uint64 { - ret := _m.Called() - - var r0 uint64 - if rf, ok := ret.Get(0).(func() uint64); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint64) - } - - return r0 -} - -// LogSQL provides a mock function with given fields: -func (_m *Config) LogSQL() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// OCR2BlockchainTimeout provides a mock function with given fields: -func (_m *Config) OCR2BlockchainTimeout() time.Duration { - ret := _m.Called() - - 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 -} - -// OCR2CaptureEATelemetry provides a mock function with given fields: -func (_m *Config) OCR2CaptureEATelemetry() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// OCR2ContractConfirmations provides a mock function with given fields: -func (_m *Config) OCR2ContractConfirmations() uint16 { - ret := _m.Called() - - var r0 uint16 - if rf, ok := ret.Get(0).(func() uint16); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(uint16) - } - - return r0 -} - -// OCR2ContractPollInterval provides a mock function with given fields: -func (_m *Config) OCR2ContractPollInterval() time.Duration { - ret := _m.Called() - - 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 -} - -// OCR2ContractSubscribeInterval provides a mock function with given fields: -func (_m *Config) OCR2ContractSubscribeInterval() time.Duration { - ret := _m.Called() - - 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 -} - -// OCR2ContractTransmitterTransmitTimeout provides a mock function with given fields: -func (_m *Config) OCR2ContractTransmitterTransmitTimeout() time.Duration { - ret := _m.Called() - - 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 -} - -// OCR2DatabaseTimeout provides a mock function with given fields: -func (_m *Config) OCR2DatabaseTimeout() time.Duration { - ret := _m.Called() - - 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 -} - -// OCR2KeyBundleID provides a mock function with given fields: -func (_m *Config) OCR2KeyBundleID() (string, error) { - ret := _m.Called() - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// OCR2TraceLogging provides a mock function with given fields: -func (_m *Config) OCR2TraceLogging() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// OCRDevelopmentMode provides a mock function with given fields: -func (_m *Config) OCRDevelopmentMode() bool { - ret := _m.Called() - - var r0 bool - if rf, ok := ret.Get(0).(func() bool); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -type mockConstructorTestingTNewConfig interface { - mock.TestingT - Cleanup(func()) -} - -// NewConfig creates a new instance of Config. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -func NewConfig(t mockConstructorTestingTNewConfig) *Config { - mock := &Config{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/feeds/mocks/connections_manager.go b/core/services/feeds/mocks/connections_manager.go index e72c98a987a..5bdc5087108 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ func (_m *ConnectionsManager) Connect(opts feeds.ConnectOpts) { func (_m *ConnectionsManager) Disconnect(id int64) error { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Disconnect") + } + var r0 error if rf, ok := ret.Get(0).(func(int64) error); ok { r0 = rf(id) @@ -42,6 +46,10 @@ func (_m *ConnectionsManager) Disconnect(id int64) error { func (_m *ConnectionsManager) GetClient(id int64) (proto.FeedsManagerClient, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetClient") + } + var r0 proto.FeedsManagerClient var r1 error if rf, ok := ret.Get(0).(func(int64) (proto.FeedsManagerClient, error)); ok { @@ -68,6 +76,10 @@ func (_m *ConnectionsManager) GetClient(id int64) (proto.FeedsManagerClient, err func (_m *ConnectionsManager) IsConnected(id int64) bool { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for IsConnected") + } + var r0 bool if rf, ok := ret.Get(0).(func(int64) bool); ok { r0 = rf(id) diff --git a/core/services/feeds/mocks/feeds_manager_client.go b/core/services/feeds/mocks/feeds_manager_client.go index 9d0037ceabc..f07200cc8fd 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type FeedsManagerClient struct { func (_m *FeedsManagerClient) ApprovedJob(ctx context.Context, in *proto.ApprovedJobRequest) (*proto.ApprovedJobResponse, error) { ret := _m.Called(ctx, in) + if len(ret) == 0 { + panic("no return value specified for ApprovedJob") + } + var r0 *proto.ApprovedJobResponse var r1 error if rf, ok := ret.Get(0).(func(context.Context, *proto.ApprovedJobRequest) (*proto.ApprovedJobResponse, error)); ok { @@ -44,6 +48,10 @@ func (_m *FeedsManagerClient) ApprovedJob(ctx context.Context, in *proto.Approve func (_m *FeedsManagerClient) CancelledJob(ctx context.Context, in *proto.CancelledJobRequest) (*proto.CancelledJobResponse, error) { ret := _m.Called(ctx, in) + if len(ret) == 0 { + panic("no return value specified for CancelledJob") + } + var r0 *proto.CancelledJobResponse var r1 error if rf, ok := ret.Get(0).(func(context.Context, *proto.CancelledJobRequest) (*proto.CancelledJobResponse, error)); ok { @@ -70,6 +78,10 @@ func (_m *FeedsManagerClient) CancelledJob(ctx context.Context, in *proto.Cancel func (_m *FeedsManagerClient) Healthcheck(ctx context.Context, in *proto.HealthcheckRequest) (*proto.HealthcheckResponse, error) { ret := _m.Called(ctx, in) + if len(ret) == 0 { + panic("no return value specified for Healthcheck") + } + var r0 *proto.HealthcheckResponse var r1 error if rf, ok := ret.Get(0).(func(context.Context, *proto.HealthcheckRequest) (*proto.HealthcheckResponse, error)); ok { @@ -96,6 +108,10 @@ func (_m *FeedsManagerClient) Healthcheck(ctx context.Context, in *proto.Healthc func (_m *FeedsManagerClient) RejectedJob(ctx context.Context, in *proto.RejectedJobRequest) (*proto.RejectedJobResponse, error) { ret := _m.Called(ctx, in) + if len(ret) == 0 { + panic("no return value specified for RejectedJob") + } + var r0 *proto.RejectedJobResponse var r1 error if rf, ok := ret.Get(0).(func(context.Context, *proto.RejectedJobRequest) (*proto.RejectedJobResponse, error)); ok { @@ -122,6 +138,10 @@ func (_m *FeedsManagerClient) RejectedJob(ctx context.Context, in *proto.Rejecte func (_m *FeedsManagerClient) UpdateNode(ctx context.Context, in *proto.UpdateNodeRequest) (*proto.UpdateNodeResponse, error) { ret := _m.Called(ctx, in) + if len(ret) == 0 { + panic("no return value specified for UpdateNode") + } + var r0 *proto.UpdateNodeResponse var r1 error if rf, ok := ret.Get(0).(func(context.Context, *proto.UpdateNodeRequest) (*proto.UpdateNodeResponse, error)); ok { diff --git a/core/services/feeds/mocks/orm.go b/core/services/feeds/mocks/orm.go index 09326ada518..73bc4c4d4a0 100644 --- a/core/services/feeds/mocks/orm.go +++ b/core/services/feeds/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -35,6 +35,10 @@ func (_m *ORM) ApproveSpec(id int64, externalJobID uuid.UUID, qopts ...pg.QOpt) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for ApproveSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, uuid.UUID, ...pg.QOpt) error); ok { r0 = rf(id, externalJobID, qopts...) @@ -93,6 +97,10 @@ func (_m *ORM) CancelSpec(id int64, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CancelSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) error); ok { r0 = rf(id, qopts...) @@ -143,6 +151,10 @@ func (_c *ORM_CancelSpec_Call) RunAndReturn(run func(int64, ...pg.QOpt) error) * func (_m *ORM) CountJobProposals() (int64, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountJobProposals") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func() (int64, error)); ok { @@ -194,6 +206,10 @@ func (_c *ORM_CountJobProposals_Call) RunAndReturn(run func() (int64, error)) *O func (_m *ORM) CountJobProposalsByStatus() (*feeds.JobProposalCounts, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountJobProposalsByStatus") + } + var r0 *feeds.JobProposalCounts var r1 error if rf, ok := ret.Get(0).(func() (*feeds.JobProposalCounts, error)); ok { @@ -247,6 +263,10 @@ func (_c *ORM_CountJobProposalsByStatus_Call) RunAndReturn(run func() (*feeds.Jo func (_m *ORM) CountManagers() (int64, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountManagers") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func() (int64, error)); ok { @@ -305,6 +325,10 @@ func (_m *ORM) CreateBatchChainConfig(cfgs []feeds.ChainConfig, qopts ...pg.QOpt _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateBatchChainConfig") + } + var r0 []int64 var r1 error if rf, ok := ret.Get(0).(func([]feeds.ChainConfig, ...pg.QOpt) ([]int64, error)); ok { @@ -374,6 +398,10 @@ func (_m *ORM) CreateChainConfig(cfg feeds.ChainConfig, qopts ...pg.QOpt) (int64 _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(feeds.ChainConfig, ...pg.QOpt) (int64, error)); ok { @@ -434,6 +462,10 @@ func (_c *ORM_CreateChainConfig_Call) RunAndReturn(run func(feeds.ChainConfig, . func (_m *ORM) CreateJobProposal(jp *feeds.JobProposal) (int64, error) { ret := _m.Called(jp) + if len(ret) == 0 { + panic("no return value specified for CreateJobProposal") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(*feeds.JobProposal) (int64, error)); ok { @@ -493,6 +525,10 @@ func (_m *ORM) CreateManager(ms *feeds.FeedsManager, qopts ...pg.QOpt) (int64, e _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateManager") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(*feeds.FeedsManager, ...pg.QOpt) (int64, error)); ok { @@ -560,6 +596,10 @@ func (_m *ORM) CreateSpec(spec feeds.JobProposalSpec, qopts ...pg.QOpt) (int64, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateSpec") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(feeds.JobProposalSpec, ...pg.QOpt) (int64, error)); ok { @@ -620,6 +660,10 @@ func (_c *ORM_CreateSpec_Call) RunAndReturn(run func(feeds.JobProposalSpec, ...p func (_m *ORM) DeleteChainConfig(id int64) (int64, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for DeleteChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(int64) (int64, error)); ok { @@ -679,6 +723,10 @@ func (_m *ORM) DeleteProposal(id int64, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for DeleteProposal") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) error); ok { r0 = rf(id, qopts...) @@ -736,6 +784,10 @@ func (_m *ORM) ExistsSpecByJobProposalIDAndVersion(jpID int64, version int32, qo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for ExistsSpecByJobProposalIDAndVersion") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(int64, int32, ...pg.QOpt) (bool, error)); ok { @@ -804,6 +856,10 @@ func (_m *ORM) GetApprovedSpec(jpID int64, qopts ...pg.QOpt) (*feeds.JobProposal _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetApprovedSpec") + } + var r0 *feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) (*feeds.JobProposalSpec, error)); ok { @@ -866,6 +922,10 @@ func (_c *ORM_GetApprovedSpec_Call) RunAndReturn(run func(int64, ...pg.QOpt) (*f func (_m *ORM) GetChainConfig(id int64) (*feeds.ChainConfig, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetChainConfig") + } + var r0 *feeds.ChainConfig var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.ChainConfig, error)); ok { @@ -927,6 +987,10 @@ func (_m *ORM) GetJobProposal(id int64, qopts ...pg.QOpt) (*feeds.JobProposal, e _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetJobProposal") + } + var r0 *feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) (*feeds.JobProposal, error)); ok { @@ -989,6 +1053,10 @@ func (_c *ORM_GetJobProposal_Call) RunAndReturn(run func(int64, ...pg.QOpt) (*fe func (_m *ORM) GetJobProposalByRemoteUUID(_a0 uuid.UUID) (*feeds.JobProposal, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetJobProposalByRemoteUUID") + } + var r0 *feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func(uuid.UUID) (*feeds.JobProposal, error)); ok { @@ -1043,6 +1111,10 @@ func (_c *ORM_GetJobProposalByRemoteUUID_Call) RunAndReturn(run func(uuid.UUID) func (_m *ORM) GetLatestSpec(jpID int64) (*feeds.JobProposalSpec, error) { ret := _m.Called(jpID) + if len(ret) == 0 { + panic("no return value specified for GetLatestSpec") + } + var r0 *feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.JobProposalSpec, error)); ok { @@ -1097,6 +1169,10 @@ func (_c *ORM_GetLatestSpec_Call) RunAndReturn(run func(int64) (*feeds.JobPropos func (_m *ORM) GetManager(id int64) (*feeds.FeedsManager, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetManager") + } + var r0 *feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.FeedsManager, error)); ok { @@ -1158,6 +1234,10 @@ func (_m *ORM) GetSpec(id int64, qopts ...pg.QOpt) (*feeds.JobProposalSpec, erro _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetSpec") + } + var r0 *feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) (*feeds.JobProposalSpec, error)); ok { @@ -1227,6 +1307,10 @@ func (_m *ORM) IsJobManaged(jobID int64, qopts ...pg.QOpt) (bool, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for IsJobManaged") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) (bool, error)); ok { @@ -1287,6 +1371,10 @@ func (_c *ORM_IsJobManaged_Call) RunAndReturn(run func(int64, ...pg.QOpt) (bool, func (_m *ORM) ListChainConfigsByManagerIDs(mgrIDs []int64) ([]feeds.ChainConfig, error) { ret := _m.Called(mgrIDs) + if len(ret) == 0 { + panic("no return value specified for ListChainConfigsByManagerIDs") + } + var r0 []feeds.ChainConfig var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.ChainConfig, error)); ok { @@ -1341,6 +1429,10 @@ func (_c *ORM_ListChainConfigsByManagerIDs_Call) RunAndReturn(run func([]int64) func (_m *ORM) ListJobProposals() ([]feeds.JobProposal, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListJobProposals") + } + var r0 []feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func() ([]feeds.JobProposal, error)); ok { @@ -1401,6 +1493,10 @@ func (_m *ORM) ListJobProposalsByManagersIDs(ids []int64, qopts ...pg.QOpt) ([]f _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for ListJobProposalsByManagersIDs") + } + var r0 []feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func([]int64, ...pg.QOpt) ([]feeds.JobProposal, error)); ok { @@ -1463,6 +1559,10 @@ func (_c *ORM_ListJobProposalsByManagersIDs_Call) RunAndReturn(run func([]int64, func (_m *ORM) ListManagers() ([]feeds.FeedsManager, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListManagers") + } + var r0 []feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func() ([]feeds.FeedsManager, error)); ok { @@ -1516,6 +1616,10 @@ func (_c *ORM_ListManagers_Call) RunAndReturn(run func() ([]feeds.FeedsManager, func (_m *ORM) ListManagersByIDs(ids []int64) ([]feeds.FeedsManager, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for ListManagersByIDs") + } + var r0 []feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.FeedsManager, error)); ok { @@ -1577,6 +1681,10 @@ func (_m *ORM) ListSpecsByJobProposalIDs(ids []int64, qopts ...pg.QOpt) ([]feeds _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for ListSpecsByJobProposalIDs") + } + var r0 []feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func([]int64, ...pg.QOpt) ([]feeds.JobProposalSpec, error)); ok { @@ -1646,6 +1754,10 @@ func (_m *ORM) RejectSpec(id int64, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RejectSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) error); ok { r0 = rf(id, qopts...) @@ -1703,6 +1815,10 @@ func (_m *ORM) RevokeSpec(id int64, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RevokeSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) error); ok { r0 = rf(id, qopts...) @@ -1753,6 +1869,10 @@ func (_c *ORM_RevokeSpec_Call) RunAndReturn(run func(int64, ...pg.QOpt) error) * func (_m *ORM) UpdateChainConfig(cfg feeds.ChainConfig) (int64, error) { ret := _m.Called(cfg) + if len(ret) == 0 { + panic("no return value specified for UpdateChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(feeds.ChainConfig) (int64, error)); ok { @@ -1812,6 +1932,10 @@ func (_m *ORM) UpdateJobProposalStatus(id int64, status feeds.JobProposalStatus, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UpdateJobProposalStatus") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, feeds.JobProposalStatus, ...pg.QOpt) error); ok { r0 = rf(id, status, qopts...) @@ -1870,6 +1994,10 @@ func (_m *ORM) UpdateManager(mgr feeds.FeedsManager, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UpdateManager") + } + var r0 error if rf, ok := ret.Get(0).(func(feeds.FeedsManager, ...pg.QOpt) error); ok { r0 = rf(mgr, qopts...) @@ -1927,6 +2055,10 @@ func (_m *ORM) UpdateSpecDefinition(id int64, spec string, qopts ...pg.QOpt) err _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UpdateSpecDefinition") + } + var r0 error if rf, ok := ret.Get(0).(func(int64, string, ...pg.QOpt) error); ok { r0 = rf(id, spec, qopts...) @@ -1985,6 +2117,10 @@ func (_m *ORM) UpsertJobProposal(jp *feeds.JobProposal, qopts ...pg.QOpt) (int64 _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for UpsertJobProposal") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(*feeds.JobProposal, ...pg.QOpt) (int64, error)); ok { diff --git a/core/services/feeds/mocks/service.go b/core/services/feeds/mocks/service.go index 1681918bb74..d8bc88c8159 100644 --- a/core/services/feeds/mocks/service.go +++ b/core/services/feeds/mocks/service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type Service struct { func (_m *Service) ApproveSpec(ctx context.Context, id int64, force bool) error { ret := _m.Called(ctx, id, force) + if len(ret) == 0 { + panic("no return value specified for ApproveSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, bool) error); ok { r0 = rf(ctx, id, force) @@ -32,6 +36,10 @@ func (_m *Service) ApproveSpec(ctx context.Context, id int64, force bool) error func (_m *Service) CancelSpec(ctx context.Context, id int64) error { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for CancelSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, id) @@ -46,6 +54,10 @@ func (_m *Service) CancelSpec(ctx context.Context, id int64) error { func (_m *Service) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -60,6 +72,10 @@ func (_m *Service) Close() error { func (_m *Service) CountJobProposalsByStatus() (*feeds.JobProposalCounts, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountJobProposalsByStatus") + } + var r0 *feeds.JobProposalCounts var r1 error if rf, ok := ret.Get(0).(func() (*feeds.JobProposalCounts, error)); ok { @@ -86,6 +102,10 @@ func (_m *Service) CountJobProposalsByStatus() (*feeds.JobProposalCounts, error) func (_m *Service) CountManagers() (int64, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountManagers") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func() (int64, error)); ok { @@ -110,6 +130,10 @@ func (_m *Service) CountManagers() (int64, error) { func (_m *Service) CreateChainConfig(ctx context.Context, cfg feeds.ChainConfig) (int64, error) { ret := _m.Called(ctx, cfg) + if len(ret) == 0 { + panic("no return value specified for CreateChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, feeds.ChainConfig) (int64, error)); ok { @@ -134,6 +158,10 @@ func (_m *Service) CreateChainConfig(ctx context.Context, cfg feeds.ChainConfig) func (_m *Service) DeleteChainConfig(ctx context.Context, id int64) (int64, error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for DeleteChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64) (int64, error)); ok { @@ -158,6 +186,10 @@ func (_m *Service) DeleteChainConfig(ctx context.Context, id int64) (int64, erro func (_m *Service) DeleteJob(ctx context.Context, args *feeds.DeleteJobArgs) (int64, error) { ret := _m.Called(ctx, args) + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, *feeds.DeleteJobArgs) (int64, error)); ok { @@ -182,6 +214,10 @@ func (_m *Service) DeleteJob(ctx context.Context, args *feeds.DeleteJobArgs) (in func (_m *Service) GetChainConfig(id int64) (*feeds.ChainConfig, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetChainConfig") + } + var r0 *feeds.ChainConfig var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.ChainConfig, error)); ok { @@ -208,6 +244,10 @@ func (_m *Service) GetChainConfig(id int64) (*feeds.ChainConfig, error) { func (_m *Service) GetJobProposal(id int64) (*feeds.JobProposal, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetJobProposal") + } + var r0 *feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.JobProposal, error)); ok { @@ -234,6 +274,10 @@ func (_m *Service) GetJobProposal(id int64) (*feeds.JobProposal, error) { func (_m *Service) GetManager(id int64) (*feeds.FeedsManager, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetManager") + } + var r0 *feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.FeedsManager, error)); ok { @@ -260,6 +304,10 @@ func (_m *Service) GetManager(id int64) (*feeds.FeedsManager, error) { func (_m *Service) GetSpec(id int64) (*feeds.JobProposalSpec, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetSpec") + } + var r0 *feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func(int64) (*feeds.JobProposalSpec, error)); ok { @@ -286,6 +334,10 @@ func (_m *Service) GetSpec(id int64) (*feeds.JobProposalSpec, error) { func (_m *Service) IsJobManaged(ctx context.Context, jobID int64) (bool, error) { ret := _m.Called(ctx, jobID) + if len(ret) == 0 { + panic("no return value specified for IsJobManaged") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(context.Context, int64) (bool, error)); ok { @@ -310,6 +362,10 @@ func (_m *Service) IsJobManaged(ctx context.Context, jobID int64) (bool, error) func (_m *Service) ListChainConfigsByManagerIDs(mgrIDs []int64) ([]feeds.ChainConfig, error) { ret := _m.Called(mgrIDs) + if len(ret) == 0 { + panic("no return value specified for ListChainConfigsByManagerIDs") + } + var r0 []feeds.ChainConfig var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.ChainConfig, error)); ok { @@ -336,6 +392,10 @@ func (_m *Service) ListChainConfigsByManagerIDs(mgrIDs []int64) ([]feeds.ChainCo func (_m *Service) ListJobProposals() ([]feeds.JobProposal, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListJobProposals") + } + var r0 []feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func() ([]feeds.JobProposal, error)); ok { @@ -362,6 +422,10 @@ func (_m *Service) ListJobProposals() ([]feeds.JobProposal, error) { func (_m *Service) ListJobProposalsByManagersIDs(ids []int64) ([]feeds.JobProposal, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for ListJobProposalsByManagersIDs") + } + var r0 []feeds.JobProposal var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.JobProposal, error)); ok { @@ -388,6 +452,10 @@ func (_m *Service) ListJobProposalsByManagersIDs(ids []int64) ([]feeds.JobPropos func (_m *Service) ListManagers() ([]feeds.FeedsManager, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListManagers") + } + var r0 []feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func() ([]feeds.FeedsManager, error)); ok { @@ -414,6 +482,10 @@ func (_m *Service) ListManagers() ([]feeds.FeedsManager, error) { func (_m *Service) ListManagersByIDs(ids []int64) ([]feeds.FeedsManager, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for ListManagersByIDs") + } + var r0 []feeds.FeedsManager var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.FeedsManager, error)); ok { @@ -440,6 +512,10 @@ func (_m *Service) ListManagersByIDs(ids []int64) ([]feeds.FeedsManager, error) func (_m *Service) ListSpecsByJobProposalIDs(ids []int64) ([]feeds.JobProposalSpec, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for ListSpecsByJobProposalIDs") + } + var r0 []feeds.JobProposalSpec var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]feeds.JobProposalSpec, error)); ok { @@ -466,6 +542,10 @@ func (_m *Service) ListSpecsByJobProposalIDs(ids []int64) ([]feeds.JobProposalSp func (_m *Service) ProposeJob(ctx context.Context, args *feeds.ProposeJobArgs) (int64, error) { ret := _m.Called(ctx, args) + if len(ret) == 0 { + panic("no return value specified for ProposeJob") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, *feeds.ProposeJobArgs) (int64, error)); ok { @@ -490,6 +570,10 @@ func (_m *Service) ProposeJob(ctx context.Context, args *feeds.ProposeJobArgs) ( func (_m *Service) RegisterManager(ctx context.Context, params feeds.RegisterManagerParams) (int64, error) { ret := _m.Called(ctx, params) + if len(ret) == 0 { + panic("no return value specified for RegisterManager") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, feeds.RegisterManagerParams) (int64, error)); ok { @@ -514,6 +598,10 @@ func (_m *Service) RegisterManager(ctx context.Context, params feeds.RegisterMan func (_m *Service) RejectSpec(ctx context.Context, id int64) error { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for RejectSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, id) @@ -528,6 +616,10 @@ func (_m *Service) RejectSpec(ctx context.Context, id int64) error { func (_m *Service) RevokeJob(ctx context.Context, args *feeds.RevokeJobArgs) (int64, error) { ret := _m.Called(ctx, args) + if len(ret) == 0 { + panic("no return value specified for RevokeJob") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, *feeds.RevokeJobArgs) (int64, error)); ok { @@ -552,6 +644,10 @@ func (_m *Service) RevokeJob(ctx context.Context, args *feeds.RevokeJobArgs) (in func (_m *Service) Start(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) @@ -566,6 +662,10 @@ func (_m *Service) Start(ctx context.Context) error { func (_m *Service) SyncNodeInfo(ctx context.Context, id int64) error { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for SyncNodeInfo") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, id) @@ -585,6 +685,10 @@ func (_m *Service) Unsafe_SetConnectionsManager(_a0 feeds.ConnectionsManager) { func (_m *Service) UpdateChainConfig(ctx context.Context, cfg feeds.ChainConfig) (int64, error) { ret := _m.Called(ctx, cfg) + if len(ret) == 0 { + panic("no return value specified for UpdateChainConfig") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(context.Context, feeds.ChainConfig) (int64, error)); ok { @@ -609,6 +713,10 @@ func (_m *Service) UpdateChainConfig(ctx context.Context, cfg feeds.ChainConfig) func (_m *Service) UpdateManager(ctx context.Context, mgr feeds.FeedsManager) error { ret := _m.Called(ctx, mgr) + if len(ret) == 0 { + panic("no return value specified for UpdateManager") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, feeds.FeedsManager) error); ok { r0 = rf(ctx, mgr) @@ -623,6 +731,10 @@ func (_m *Service) UpdateManager(ctx context.Context, mgr feeds.FeedsManager) er func (_m *Service) UpdateSpecDefinition(ctx context.Context, id int64, spec string) error { ret := _m.Called(ctx, id, spec) + if len(ret) == 0 { + panic("no return value specified for UpdateSpecDefinition") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64, string) error); ok { r0 = rf(ctx, id, spec) diff --git a/core/services/feeds/orm_test.go b/core/services/feeds/orm_test.go index 02b9e24739c..78af9bf6912 100644 --- a/core/services/feeds/orm_test.go +++ b/core/services/feeds/orm_test.go @@ -12,6 +12,7 @@ import ( "github.com/jmoiron/sqlx" + "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/configtest" @@ -24,7 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" ) @@ -645,7 +645,7 @@ func Test_ORM_CountJobProposalsByStatus(t *testing.T) { jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) // Create a spec for the pending job proposal - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) // Defer the FK requirement of an existing job for a job proposal to be approved require.NoError(t, utils.JustError(orm.db.Exec( @@ -870,7 +870,7 @@ func Test_ORM_UpsertJobProposal(t *testing.T) { assert.True(t, actual.PendingUpdate) // Approve - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) // Defer the FK requirement of an existing job for a job proposal. require.NoError(t, utils.JustError(orm.db.Exec( @@ -943,7 +943,7 @@ func Test_ORM_ApproveSpec(t *testing.T) { PendingUpdate: true, }) require.NoError(t, err) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) // Defer the FK requirement of an existing job for a job proposal. require.NoError(t, utils.JustError(orm.db.Exec( @@ -982,7 +982,7 @@ func Test_ORM_CancelSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -994,7 +994,7 @@ func Test_ORM_CancelSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusDeleted, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1056,7 +1056,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - createJobSpec(t, orm, int64(jpID)) + createJobSpec(t, orm, jpID) return jpID }, @@ -1068,7 +1068,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) externalJobID := uuid.NullUUID{UUID: uuid.New(), Valid: true} @@ -1090,7 +1090,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) externalJobID := uuid.NullUUID{UUID: uuid.New(), Valid: true} @@ -1131,7 +1131,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusCancelled, fmID) - createJobSpec(t, orm, int64(jpID)) + createJobSpec(t, orm, jpID) return jpID }, @@ -1143,7 +1143,7 @@ func Test_ORM_DeleteProposal(t *testing.T) { before: func(orm *TestORM) int64 { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusRejected, fmID) - createJobSpec(t, orm, int64(jpID)) + createJobSpec(t, orm, jpID) return jpID }, @@ -1211,7 +1211,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1224,7 +1224,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) externalJobID := uuid.NullUUID{UUID: uuid.New(), Valid: true} @@ -1246,7 +1246,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusCancelled, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1258,7 +1258,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusRejected, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1270,7 +1270,7 @@ func Test_ORM_RevokeSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusDeleted, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1324,7 +1324,7 @@ func Test_ORM_ExistsSpecByJobProposalIDAndVersion(t *testing.T) { jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) ) - createJobSpec(t, orm, int64(jpID)) + createJobSpec(t, orm, jpID) exists, err := orm.ExistsSpecByJobProposalIDAndVersion(jpID, 1) require.NoError(t, err) @@ -1342,7 +1342,7 @@ func Test_ORM_GetSpec(t *testing.T) { orm = setupORM(t) fmID = createFeedsManager(t, orm) jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID = createJobSpec(t, orm, int64(jpID)) + specID = createJobSpec(t, orm, jpID) ) actual, err := orm.GetSpec(specID) @@ -1361,7 +1361,7 @@ func Test_ORM_GetApprovedSpec(t *testing.T) { orm = setupORM(t) fmID = createFeedsManager(t, orm) jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID = createJobSpec(t, orm, int64(jpID)) + specID = createJobSpec(t, orm, jpID) externalJobID = uuid.NullUUID{UUID: uuid.New(), Valid: true} ) @@ -1398,7 +1398,7 @@ func Test_ORM_GetLatestSpec(t *testing.T) { jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) ) - _ = createJobSpec(t, orm, int64(jpID)) + _ = createJobSpec(t, orm, jpID) spec2ID, err := orm.CreateSpec(feeds.JobProposalSpec{ Definition: "spec data", Version: 2, @@ -1429,8 +1429,8 @@ func Test_ORM_ListSpecsByJobProposalIDs(t *testing.T) { ) // Create the specs for the proposals - createJobSpec(t, orm, int64(jp1ID)) - createJobSpec(t, orm, int64(jp2ID)) + createJobSpec(t, orm, jp1ID) + createJobSpec(t, orm, jp2ID) specs, err := orm.ListSpecsByJobProposalIDs([]int64{jp1ID, jp2ID}) require.NoError(t, err) @@ -1466,7 +1466,7 @@ func Test_ORM_RejectSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1478,7 +1478,7 @@ func Test_ORM_RejectSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) externalJobID := uuid.NullUUID{UUID: uuid.New(), Valid: true} @@ -1500,7 +1500,7 @@ func Test_ORM_RejectSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusCancelled, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1512,7 +1512,7 @@ func Test_ORM_RejectSpec(t *testing.T) { before: func(orm *TestORM) (int64, int64) { fmID := createFeedsManager(t, orm) jpID := createJobProposal(t, orm, feeds.JobProposalStatusDeleted, fmID) - specID := createJobSpec(t, orm, int64(jpID)) + specID := createJobSpec(t, orm, jpID) return jpID, specID }, @@ -1566,7 +1566,7 @@ func Test_ORM_UpdateSpecDefinition(t *testing.T) { orm = setupORM(t) fmID = createFeedsManager(t, orm) jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID = createJobSpec(t, orm, int64(jpID)) + specID = createJobSpec(t, orm, jpID) ) prev, err := orm.GetSpec(specID) @@ -1596,7 +1596,7 @@ func Test_ORM_IsJobManaged(t *testing.T) { orm = setupORM(t) fmID = createFeedsManager(t, orm) jpID = createJobProposal(t, orm, feeds.JobProposalStatusPending, fmID) - specID = createJobSpec(t, orm, int64(jpID)) + specID = createJobSpec(t, orm, jpID) externalJobID = uuid.NullUUID{UUID: uuid.New(), Valid: true} ) diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index ea6e6cae5ab..a1b4e9b2837 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" pb "github.com/smartcontractkit/chainlink/v2/core/services/feeds/proto" @@ -32,7 +33,6 @@ import ( ocr2 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" ) @@ -1073,7 +1073,7 @@ func (s *service) findExistingJobForOCR2(j *job.Job, qopts pg.QOpt) (int32, erro // findExistingJobForOCRFlux looks for existing job for OCR or flux func (s *service) findExistingJobForOCRFlux(j *job.Job, qopts pg.QOpt) (int32, error) { var address ethkey.EIP55Address - var evmChainID *utils.Big + var evmChainID *big.Big switch j.Type { case job.OffchainReporting: diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index d811a4461fd..d822cd9787d 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -9,9 +9,18 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/google/uuid" + "github.com/lib/pq" "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -33,16 +42,7 @@ import ( "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/versioning" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" - - "github.com/google/uuid" - "github.com/lib/pq" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "gopkg.in/guregu/null.v4" ) const FluxMonitorTestSpecTemplate = ` @@ -75,10 +75,7 @@ name = "%s" externalJobID = "%s" evmChainID = 0 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] -p2pv2Bootstrappers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] keyBundleID = "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5" transmitterAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" isBootstrapPeer = false @@ -629,7 +626,7 @@ func Test_Service_ProposeJob(t *testing.T) { JobProposalID: idBootstrap, } - httpTimeout = models.MustMakeDuration(1 * time.Second) + httpTimeout = *commonconfig.MustNewDuration(1 * time.Second) ) testCases := []struct { @@ -809,7 +806,7 @@ func Test_Service_DeleteJob(t *testing.T) { Status: feeds.JobProposalStatusApproved, } - httpTimeout = models.MustMakeDuration(1 * time.Second) + httpTimeout = *commonconfig.MustNewDuration(1 * time.Second) ) testCases := []struct { @@ -949,7 +946,7 @@ answer1 [type=median index=0]; Definition: defn, } - httpTimeout = models.MustMakeDuration(1 * time.Second) + httpTimeout = *commonconfig.MustNewDuration(1 * time.Second) ) testCases := []struct { @@ -1546,7 +1543,7 @@ func Test_Service_ListSpecsByJobProposalIDs(t *testing.T) { } func Test_Service_ApproveSpec(t *testing.T) { - var evmChainID *utils.Big + var evmChainID *big.Big address := ethkey.EIP55AddressFromAddress(common.Address{}) externalJobID := uuid.New() @@ -1613,7 +1610,7 @@ answer1 [type=median index=0]; testCases := []struct { name string - httpTimeout *models.Duration + httpTimeout *commonconfig.Duration before func(svc *TestService) id int64 force bool @@ -1621,7 +1618,7 @@ answer1 [type=median index=0]; }{ { name: "pending job success for new proposals", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1659,7 +1656,7 @@ answer1 [type=median index=0]; }, { name: "cancelled spec success when it is the latest spec", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", cancelledSpec.ID, mock.Anything).Return(cancelledSpec, nil) @@ -1698,7 +1695,7 @@ answer1 [type=median index=0]; }, { name: "pending job fail due to spec missing external job id", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec2, nil) @@ -1778,7 +1775,7 @@ answer1 [type=median index=0]; }, { name: "already existing job replacement (found via external job id) error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -1793,7 +1790,7 @@ answer1 [type=median index=0]; }, { name: "already existing job replacement error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -1809,7 +1806,7 @@ answer1 [type=median index=0]; }, { name: "already existing self managed job replacement success if forced (via external job id)", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1848,7 +1845,7 @@ answer1 [type=median index=0]; }, { name: "already existing self managed job replacement success if forced", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1888,7 +1885,7 @@ answer1 [type=median index=0]; }, { name: "already existing FMS managed job replacement success if forced", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1947,7 +1944,7 @@ answer1 [type=median index=0]; }, { name: "bridges do not exist", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -1970,7 +1967,7 @@ answer1 [type=median index=0]; }, { name: "Fetching the approved spec fails (via external job id)", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -1985,7 +1982,7 @@ answer1 [type=median index=0]; }, { name: "Fetching the approved spec fails", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -2001,7 +1998,7 @@ answer1 [type=median index=0]; }, { name: "spec cancellation fails (via external job id)", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -2017,7 +2014,7 @@ answer1 [type=median index=0]; }, { name: "spec cancellation fails", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.EXPECT().GetSpec(spec.ID, mock.Anything).Return(spec, nil) @@ -2034,7 +2031,7 @@ answer1 [type=median index=0]; }, { name: "create job error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2059,7 +2056,7 @@ answer1 [type=median index=0]; }, { name: "approve spec orm error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2090,7 +2087,7 @@ answer1 [type=median index=0]; }, { name: "fms call error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2253,7 +2250,7 @@ answer1 [type=median index=0]; testCases := []struct { name string - httpTimeout *models.Duration + httpTimeout *commonconfig.Duration before func(svc *TestService) id int64 force bool @@ -2261,7 +2258,7 @@ answer1 [type=median index=0]; }{ { name: "pending job success", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2298,7 +2295,7 @@ answer1 [type=median index=0]; }, { name: "cancelled spec success when it is the latest spec", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", cancelledSpec.ID, mock.Anything).Return(cancelledSpec, nil) @@ -2364,7 +2361,7 @@ answer1 [type=median index=0]; }, { name: "already existing job replacement error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2379,7 +2376,7 @@ answer1 [type=median index=0]; }, { name: "already existing self managed job replacement success if forced without feedID", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2418,7 +2415,7 @@ answer1 [type=median index=0]; }, { name: "already existing self managed job replacement success if forced with feedID", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(&feeds.JobProposalSpec{ @@ -2463,7 +2460,7 @@ answer1 [type=median index=0]; }, { name: "already existing FMS managed job replacement success if forced", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2551,7 +2548,7 @@ answer1 [type=median index=0]; }, { name: "bridges do not exist", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2574,7 +2571,7 @@ answer1 [type=median index=0]; }, { name: "create job error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2599,7 +2596,7 @@ answer1 [type=median index=0]; }, { name: "approve spec orm error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2630,7 +2627,7 @@ answer1 [type=median index=0]; }, { name: "fms call error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -2759,7 +2756,7 @@ chainID = 0 testCases := []struct { name string - httpTimeout *models.Duration + httpTimeout *commonconfig.Duration before func(svc *TestService) id int64 force bool @@ -2767,7 +2764,7 @@ chainID = 0 }{ { name: "pending job success", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2804,7 +2801,7 @@ chainID = 0 }, { name: "cancelled spec success when it is the latest spec", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", cancelledSpec.ID, mock.Anything).Return(cancelledSpec, nil) @@ -2870,7 +2867,7 @@ chainID = 0 }, { name: "already existing job replacement error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2885,7 +2882,7 @@ chainID = 0 }, { name: "already existing self managed job replacement success if forced without feedID", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -2924,7 +2921,7 @@ chainID = 0 }, { name: "already existing self managed job replacement success if forced with feedID", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(&feeds.JobProposalSpec{ @@ -2969,7 +2966,7 @@ chainID = 0 }, { name: "already existing FMS managed job replacement success if forced", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -3057,7 +3054,7 @@ chainID = 0 }, { name: "bridges do not exist", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.connMgr.On("GetClient", jp.FeedsManagerID).Return(svc.fmsClient, nil) svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) @@ -3080,7 +3077,7 @@ chainID = 0 }, { name: "create job error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -3105,7 +3102,7 @@ chainID = 0 }, { name: "approve spec orm error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -3136,7 +3133,7 @@ chainID = 0 }, { name: "fms call error", - httpTimeout: models.MustNewDuration(1 * time.Minute), + httpTimeout: commonconfig.MustNewDuration(1 * time.Minute), before: func(svc *TestService) { svc.orm.On("GetSpec", spec.ID, mock.Anything).Return(spec, nil) svc.orm.On("GetJobProposal", jp.ID, mock.Anything).Return(jp, nil) @@ -3468,9 +3465,7 @@ func Test_Service_StartStop(t *testing.T) { tt.beforeFunc(svc) } - require.NoError(t, svc.Start(testutils.Context(t))) - - svc.Close() + servicetest.Run(t, svc) }) } } diff --git a/core/services/fluxmonitorv2/config.go b/core/services/fluxmonitorv2/config.go index 2680f30a777..18fdf72798b 100644 --- a/core/services/fluxmonitorv2/config.go +++ b/core/services/fluxmonitorv2/config.go @@ -4,8 +4,8 @@ import ( "time" "github.com/smartcontractkit/chainlink-common/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) // Config defines the Flux Monitor configuration. @@ -28,7 +28,7 @@ type FluxMonitorConfig interface { } type JobPipelineConfig interface { - DefaultHTTPTimeout() models.Duration + DefaultHTTPTimeout() commonconfig.Duration } // MinimumPollingInterval returns the minimum duration between polling ticks diff --git a/core/services/fluxmonitorv2/flags.go b/core/services/fluxmonitorv2/flags.go index bad5a1f2752..c50a767ae1c 100644 --- a/core/services/fluxmonitorv2/flags.go +++ b/core/services/fluxmonitorv2/flags.go @@ -7,9 +7,9 @@ import ( "github.com/ethereum/go-ethereum/core/types" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flags_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name Flags --output ./mocks/ --case=underscore --structname Flags --filename flags.go diff --git a/core/services/fluxmonitorv2/flags_test.go b/core/services/fluxmonitorv2/flags_test.go index 99d182a9671..c00c439d859 100644 --- a/core/services/fluxmonitorv2/flags_test.go +++ b/core/services/fluxmonitorv2/flags_test.go @@ -7,10 +7,10 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestFlags_IsLowered(t *testing.T) { diff --git a/core/services/fluxmonitorv2/flux_monitor.go b/core/services/fluxmonitorv2/flux_monitor.go index 79dd44c8014..8fe0fc7c70e 100644 --- a/core/services/fluxmonitorv2/flux_monitor.go +++ b/core/services/fluxmonitorv2/flux_monitor.go @@ -20,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" + evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flags_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -338,12 +339,12 @@ func (fm *FluxMonitor) HandleLog(broadcast log.Broadcast) { fm.backlog.Add(PriorityAnswerUpdatedLog, broadcast) case *flags_wrapper.FlagsFlagRaised: - if log.Subject == utils.ZeroAddress || log.Subject == fm.contractAddress { + if log.Subject == evmutils.ZeroAddress || log.Subject == fm.contractAddress { fm.backlog.Add(PriorityFlagChangedLog, broadcast) } case *flags_wrapper.FlagsFlagLowered: - if log.Subject == utils.ZeroAddress || log.Subject == fm.contractAddress { + if log.Subject == evmutils.ZeroAddress || log.Subject == fm.contractAddress { fm.backlog.Add(PriorityFlagChangedLog, broadcast) } diff --git a/core/services/fluxmonitorv2/flux_monitor_test.go b/core/services/fluxmonitorv2/flux_monitor_test.go index 1a14fb8bd0a..b13edcc12d8 100644 --- a/core/services/fluxmonitorv2/flux_monitor_test.go +++ b/core/services/fluxmonitorv2/flux_monitor_test.go @@ -21,6 +21,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" 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" @@ -701,7 +702,7 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { Once(). Run(func(mock.Arguments) { readyToAssert.ItHappened() }) - require.NoError(t, fm.Start(testutils.Context(t))) + servicetest.Run(t, fm) var logBroadcasts []*logmocks.Broadcast @@ -724,8 +725,6 @@ func TestPollingDeviationChecker_BuffersLogs(t *testing.T) { logsAwaiter.ItHappened() readyToAssert.AwaitOrFail(t) - - fm.Close() } func TestFluxMonitor_TriggerIdleTimeThreshold(t *testing.T) { @@ -1049,8 +1048,7 @@ func TestFluxMonitor_IdleTimerResetsOnNewRound(t *testing.T) { idleDurationOccured := make(chan struct{}, 4) initialPollOccurred := make(chan struct{}, 1) - require.NoError(t, fm.Start(testutils.Context(t))) - t.Cleanup(func() { fm.Close() }) + servicetest.Run(t, fm) // Initial Poll roundState1 := flux_aggregator_wrapper.OracleRoundState{RoundId: 1, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()} @@ -1169,11 +1167,9 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutAtZero(t *testing.T) { require.NoError(t, fm.SetOracleAddress()) fm.ExportedRoundState(t) - require.NoError(t, fm.Start(testutils.Context(t))) + servicetest.Run(t, fm) g.Eventually(ch).Should(gomega.BeClosed()) - - fm.Close() } func TestFluxMonitor_UsesPreviousRoundStateOnStartup_RoundTimeout(t *testing.T) { @@ -1229,15 +1225,13 @@ func TestFluxMonitor_UsesPreviousRoundStateOnStartup_RoundTimeout(t *testing.T) Run(func(mock.Arguments) { close(chRoundState) }). Maybe() - require.NoError(t, fm.Start(testutils.Context(t))) + servicetest.Run(t, fm) if test.expectedToSubmit { g.Eventually(chRoundState).Should(gomega.BeClosed()) } else { g.Consistently(chRoundState).ShouldNot(gomega.BeClosed()) } - - require.NoError(t, fm.Close()) }) } } @@ -1310,8 +1304,7 @@ func TestFluxMonitor_UsesPreviousRoundStateOnStartup_IdleTimer(t *testing.T) { }). Maybe() - require.NoError(t, fm.Start(testutils.Context(t))) - t.Cleanup(func() { fm.Close() }) + servicetest.Run(t, fm) assert.Eventually(t, func() bool { return len(initialPollOccurred) == 1 }, 3*time.Second, 10*time.Millisecond) @@ -1385,7 +1378,7 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutNotZero(t *testing.T) { Run(func(mock.Arguments) { close(chRoundState2) }). Once() - require.NoError(t, fm.Start(testutils.Context(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) @@ -1401,7 +1394,6 @@ func TestFluxMonitor_RoundTimeoutCausesPoll_timesOutNotZero(t *testing.T) { g.Eventually(chRoundState2).Should(gomega.BeClosed()) time.Sleep(time.Duration(2*timeout) * time.Second) - require.NoError(t, fm.Close()) } func TestFluxMonitor_ConsumeLogBroadcast(t *testing.T) { @@ -1927,8 +1919,7 @@ func TestFluxMonitor_DrumbeatTicker(t *testing.T) { Return(flux_aggregator_wrapper.OracleRoundState{RoundId: 4, EligibleToSubmit: false, LatestSubmission: answerBigInt, StartedAt: now()}, nil). Maybe() - require.NoError(t, fm.Start(testutils.Context(t))) - defer func() { assert.NoError(t, fm.Close()) }() + servicetest.Run(t, fm) waitTime := 15 * time.Second interval := 50 * time.Millisecond diff --git a/core/services/fluxmonitorv2/integrations_test.go b/core/services/fluxmonitorv2/integrations_test.go index 729bcd76eba..7f45e6eb19c 100644 --- a/core/services/fluxmonitorv2/integrations_test.go +++ b/core/services/fluxmonitorv2/integrations_test.go @@ -26,9 +26,11 @@ import ( "github.com/jmoiron/sqlx" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" + evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flags_wrapper" faw "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flux_aggregator_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" @@ -447,8 +449,8 @@ func TestFluxMonitor_Deviation(t *testing.T) { // Set up chainlink app app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(1 * time.Second) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 }) @@ -517,7 +519,7 @@ func TestFluxMonitor_Deviation(t *testing.T) { s = fmt.Sprintf(s, fa.aggregatorContractAddress, 2*time.Second) requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: string(s), + TOML: s, }) assert.NoError(t, err) @@ -619,8 +621,8 @@ func TestFluxMonitor_NewRound(t *testing.T) { // Set up chainlink app app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(1 * time.Second) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) flags := ethkey.EIP55AddressFromAddress(fa.flagsContractAddress) c.EVM[0].FlagsContractAddress = &flags }) @@ -667,14 +669,14 @@ ds1 -> ds1_parse s = fmt.Sprintf(s, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), pollTimerPeriod, mockServer.URL) // raise flags to disable polling - _, err = fa.flagsContract.RaiseFlag(fa.sergey, utils.ZeroAddress) // global kill switch + _, err = fa.flagsContract.RaiseFlag(fa.sergey, evmutils.ZeroAddress) // global kill switch require.NoError(t, err) _, err = fa.flagsContract.RaiseFlag(fa.sergey, fa.aggregatorContractAddress) require.NoError(t, err) fa.backend.Commit() requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: string(s), + TOML: s, }) assert.NoError(t, err) @@ -730,8 +732,8 @@ func TestFluxMonitor_HibernationMode(t *testing.T) { // Start chainlink app app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(1 * time.Second) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) flags := ethkey.EIP55AddressFromAddress(fa.flagsContractAddress) c.EVM[0].FlagsContractAddress = &flags }) @@ -776,7 +778,7 @@ ds1 -> ds1_parse s = fmt.Sprintf(s, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), "1000ms", mockServer.URL) // raise flags - _, err = fa.flagsContract.RaiseFlag(fa.sergey, utils.ZeroAddress) // global kill switch + _, err = fa.flagsContract.RaiseFlag(fa.sergey, evmutils.ZeroAddress) // global kill switch require.NoError(t, err) _, err = fa.flagsContract.RaiseFlag(fa.sergey, fa.aggregatorContractAddress) @@ -784,7 +786,7 @@ ds1 -> ds1_parse fa.backend.Commit() requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: string(s), + TOML: s, }) assert.NoError(t, err) @@ -795,7 +797,7 @@ ds1 -> ds1_parse cltest.AssertPipelineRunsStays(t, j.PipelineSpec.ID, app.GetSqlxDB(), 0) // lower global kill switch flag - should trigger job run - _, err = fa.flagsContract.LowerFlags(fa.sergey, []common.Address{utils.ZeroAddress}) + _, err = fa.flagsContract.LowerFlags(fa.sergey, []common.Address{evmutils.ZeroAddress}) require.NoError(t, err) fa.backend.Commit() awaitSubmission(t, fa.backend, submissionReceived) @@ -816,7 +818,7 @@ ds1 -> ds1_parse // raise both flags _, err = fa.flagsContract.RaiseFlag(fa.sergey, fa.aggregatorContractAddress) require.NoError(t, err) - _, err = fa.flagsContract.RaiseFlag(fa.sergey, utils.ZeroAddress) + _, err = fa.flagsContract.RaiseFlag(fa.sergey, evmutils.ZeroAddress) require.NoError(t, err) fa.backend.Commit() @@ -847,8 +849,8 @@ func TestFluxMonitor_InvalidSubmission(t *testing.T) { // Set up chainlink app app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(1 * time.Second) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) // Report a price that is above the maximum allowed value, @@ -887,14 +889,14 @@ ds1 -> ds1_parse s := fmt.Sprintf(toml, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), "100ms", mockServer.URL) // raise flags - _, err = fa.flagsContract.RaiseFlag(fa.sergey, utils.ZeroAddress) // global kill switch + _, err = fa.flagsContract.RaiseFlag(fa.sergey, evmutils.ZeroAddress) // global kill switch require.NoError(t, err) _, err = fa.flagsContract.RaiseFlag(fa.sergey, fa.aggregatorContractAddress) require.NoError(t, err) fa.backend.Commit() requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: string(s), + TOML: s, }) assert.NoError(t, err) @@ -924,8 +926,8 @@ func TestFluxMonitorAntiSpamLogic(t *testing.T) { // Set up chainlink app app := startApplication(t, fa, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(100 * time.Millisecond) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(1 * time.Second) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(100 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) answer := int64(1) // Answer the nodes give on the first round @@ -989,7 +991,7 @@ ds1 -> ds1_parse -> ds1_multiply s = fmt.Sprintf(s, fa.aggregatorContractAddress, testutils.SimulatedChainID.String(), "200ms", mockServer.URL) requestBody, err := json.Marshal(web.CreateJobRequest{ - TOML: string(s), + TOML: s, }) assert.NoError(t, err) diff --git a/core/services/fluxmonitorv2/mocks/contract_submitter.go b/core/services/fluxmonitorv2/mocks/contract_submitter.go index 03540a6cb1c..3154b4c86ee 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type ContractSubmitter struct { func (_m *ContractSubmitter) Submit(ctx context.Context, roundID *big.Int, submission *big.Int, idempotencyKey *string) error { ret := _m.Called(ctx, roundID, submission, idempotencyKey) + if len(ret) == 0 { + panic("no return value specified for Submit") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *big.Int, *big.Int, *string) error); ok { r0 = rf(ctx, roundID, submission, idempotencyKey) diff --git a/core/services/fluxmonitorv2/mocks/flags.go b/core/services/fluxmonitorv2/mocks/flags.go index 08ad0f5b3f7..6ff1616111b 100644 --- a/core/services/fluxmonitorv2/mocks/flags.go +++ b/core/services/fluxmonitorv2/mocks/flags.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type Flags struct { func (_m *Flags) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -37,6 +41,10 @@ func (_m *Flags) Address() common.Address { func (_m *Flags) ContractExists() bool { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ContractExists") + } + var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() @@ -51,6 +59,10 @@ func (_m *Flags) ContractExists() bool { func (_m *Flags) IsLowered(contractAddr common.Address) (bool, error) { ret := _m.Called(contractAddr) + if len(ret) == 0 { + panic("no return value specified for IsLowered") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(common.Address) (bool, error)); ok { @@ -75,6 +87,10 @@ func (_m *Flags) IsLowered(contractAddr common.Address) (bool, error) { func (_m *Flags) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { diff --git a/core/services/fluxmonitorv2/mocks/key_store_interface.go b/core/services/fluxmonitorv2/mocks/key_store_interface.go index c409a987e02..98f5ab71020 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type KeyStoreInterface struct { func (_m *KeyStoreInterface) EnabledKeysForChain(chainID *big.Int) ([]ethkey.KeyV2, error) { ret := _m.Called(chainID) + if len(ret) == 0 { + panic("no return value specified for EnabledKeysForChain") + } + var r0 []ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(*big.Int) ([]ethkey.KeyV2, error)); ok { @@ -53,6 +57,10 @@ func (_m *KeyStoreInterface) GetRoundRobinAddress(chainID *big.Int, addrs ...com _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetRoundRobinAddress") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*big.Int, ...common.Address) (common.Address, error)); ok { diff --git a/core/services/fluxmonitorv2/mocks/orm.go b/core/services/fluxmonitorv2/mocks/orm.go index 5080f19edf0..8d277d61d2e 100644 --- a/core/services/fluxmonitorv2/mocks/orm.go +++ b/core/services/fluxmonitorv2/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -23,6 +23,10 @@ type ORM struct { func (_m *ORM) CountFluxMonitorRoundStats() (int, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CountFluxMonitorRoundStats") + } + var r0 int var r1 error if rf, ok := ret.Get(0).(func() (int, error)); ok { @@ -47,6 +51,10 @@ func (_m *ORM) CountFluxMonitorRoundStats() (int, error) { func (_m *ORM) CreateEthTransaction(ctx context.Context, fromAddress common.Address, toAddress common.Address, payload []byte, gasLimit uint32, idempotencyKey *string) error { ret := _m.Called(ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey) + if len(ret) == 0 { + panic("no return value specified for CreateEthTransaction") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, common.Address, common.Address, []byte, uint32, *string) error); ok { r0 = rf(ctx, fromAddress, toAddress, payload, gasLimit, idempotencyKey) @@ -61,6 +69,10 @@ func (_m *ORM) CreateEthTransaction(ctx context.Context, fromAddress common.Addr func (_m *ORM) DeleteFluxMonitorRoundsBackThrough(aggregator common.Address, roundID uint32) error { ret := _m.Called(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) @@ -75,6 +87,10 @@ func (_m *ORM) DeleteFluxMonitorRoundsBackThrough(aggregator common.Address, rou func (_m *ORM) FindOrCreateFluxMonitorRoundStats(aggregator common.Address, roundID uint32, newRoundLogs uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error) { ret := _m.Called(aggregator, roundID, newRoundLogs) + if len(ret) == 0 { + panic("no return value specified for FindOrCreateFluxMonitorRoundStats") + } + var r0 fluxmonitorv2.FluxMonitorRoundStatsV2 var r1 error if rf, ok := ret.Get(0).(func(common.Address, uint32, uint) (fluxmonitorv2.FluxMonitorRoundStatsV2, error)); ok { @@ -99,6 +115,10 @@ func (_m *ORM) FindOrCreateFluxMonitorRoundStats(aggregator common.Address, roun func (_m *ORM) MostRecentFluxMonitorRoundID(aggregator common.Address) (uint32, error) { ret := _m.Called(aggregator) + if len(ret) == 0 { + panic("no return value specified for MostRecentFluxMonitorRoundID") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(common.Address) (uint32, error)); ok { @@ -130,6 +150,10 @@ func (_m *ORM) UpdateFluxMonitorRoundStats(aggregator common.Address, roundID ui _ca = append(_ca, _va...) ret := _m.Called(_ca...) + 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...) diff --git a/core/services/fluxmonitorv2/orm_test.go b/core/services/fluxmonitorv2/orm_test.go index 6e06a1e65b8..bcbec4363e2 100644 --- a/core/services/fluxmonitorv2/orm_test.go +++ b/core/services/fluxmonitorv2/orm_test.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + "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" @@ -22,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestORM_MostRecentFluxMonitorRoundID(t *testing.T) { @@ -159,7 +159,7 @@ func makeJob(t *testing.T) *job.Job { IdleTimerDisabled: false, CreatedAt: time.Now(), UpdatedAt: time.Now(), - EVMChainID: (*utils.Big)(testutils.FixtureChainID), + EVMChainID: (*big.Big)(testutils.FixtureChainID), }, } } diff --git a/core/services/fluxmonitorv2/validate.go b/core/services/fluxmonitorv2/validate.go index 02dbfb01284..fc531fc7cb4 100644 --- a/core/services/fluxmonitorv2/validate.go +++ b/core/services/fluxmonitorv2/validate.go @@ -8,13 +8,13 @@ import ( "github.com/pelletier/go-toml" "github.com/pkg/errors" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ValidationConfig interface { - DefaultHTTPTimeout() models.Duration + DefaultHTTPTimeout() commonconfig.Duration } func ValidatedFluxMonitorSpec(config ValidationConfig, ts string) (job.Job, error) { diff --git a/core/services/fluxmonitorv2/validate_test.go b/core/services/fluxmonitorv2/validate_test.go index 94dc8b6b709..40efd1d724d 100644 --- a/core/services/fluxmonitorv2/validate_test.go +++ b/core/services/fluxmonitorv2/validate_test.go @@ -6,8 +6,8 @@ import ( "time" "github.com/smartcontractkit/chainlink-common/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils/tomlutils" "github.com/stretchr/testify/assert" @@ -16,7 +16,9 @@ import ( type testcfg struct{} -func (testcfg) DefaultHTTPTimeout() models.Duration { return models.MustMakeDuration(2 * time.Second) } +func (testcfg) DefaultHTTPTimeout() commonconfig.Duration { + return *commonconfig.MustNewDuration(2 * time.Second) +} func TestValidate(t *testing.T) { var tt = []struct { diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index 5496bbdefc1..c8c522e6a62 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -6,6 +6,7 @@ import ( "crypto/ecdsa" "encoding/json" "fmt" + "strings" "sync" "time" @@ -13,6 +14,8 @@ import ( ethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -23,62 +26,77 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + fallow "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" + fsub "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" "github.com/smartcontractkit/chainlink/v2/core/services/s4" ) type functionsConnectorHandler struct { services.StateMachine - connector connector.GatewayConnector - signerKey *ecdsa.PrivateKey - nodeAddress string - storage s4.Storage - allowlist functions.OnchainAllowlist - rateLimiter *hc.RateLimiter - subscriptions functions.OnchainSubscriptions - minimumBalance assets.Link - listener FunctionsListener - offchainTransmitter OffchainTransmitter - heartbeatRequests map[RequestID]*HeartbeatResponse - orderedRequests []RequestID - mu sync.Mutex - chStop services.StopChan - shutdownWaitGroup sync.WaitGroup - lggr logger.Logger + connector connector.GatewayConnector + signerKey *ecdsa.PrivateKey + nodeAddress string + storage s4.Storage + allowlist fallow.OnchainAllowlist + rateLimiter *hc.RateLimiter + subscriptions fsub.OnchainSubscriptions + minimumBalance assets.Link + listener FunctionsListener + offchainTransmitter OffchainTransmitter + allowedHeartbeatInitiators map[string]struct{} + heartbeatRequests map[RequestID]*HeartbeatResponse + requestTimeoutSec uint32 + orderedRequests []RequestID + mu sync.Mutex + chStop services.StopChan + shutdownWaitGroup sync.WaitGroup + lggr logger.Logger } -const ( - HeartbeatRequestTimeoutSec = 240 - HeartbeatCacheSize = 1000 -) +const HeartbeatCacheSize = 1000 var ( _ connector.Signer = &functionsConnectorHandler{} _ connector.GatewayConnectorHandler = &functionsConnectorHandler{} ) +var ( + promStorageUserUpdatesCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "storage_user_updates", + Help: "Number of storage updates performed by users", + }, []string{}) +) + // internal request ID is a hash of (sender, requestID) func InternalId(sender []byte, requestId []byte) RequestID { return RequestID(crypto.Keccak256Hash(append(sender, requestId...)).Bytes()) } -func NewFunctionsConnectorHandler(nodeAddress string, signerKey *ecdsa.PrivateKey, storage s4.Storage, allowlist functions.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions functions.OnchainSubscriptions, listener FunctionsListener, offchainTransmitter OffchainTransmitter, minimumBalance assets.Link, lggr logger.Logger) (*functionsConnectorHandler, error) { +func NewFunctionsConnectorHandler(pluginConfig *config.PluginConfig, signerKey *ecdsa.PrivateKey, storage s4.Storage, allowlist fallow.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions fsub.OnchainSubscriptions, listener FunctionsListener, offchainTransmitter OffchainTransmitter, lggr logger.Logger) (*functionsConnectorHandler, error) { if signerKey == nil || storage == nil || allowlist == nil || rateLimiter == nil || subscriptions == nil || listener == nil || offchainTransmitter == nil { return nil, fmt.Errorf("all dependencies must be non-nil") } + allowedHeartbeatInitiators := make(map[string]struct{}) + for _, initiator := range pluginConfig.AllowedHeartbeatInitiators { + allowedHeartbeatInitiators[strings.ToLower(initiator)] = struct{}{} + } return &functionsConnectorHandler{ - nodeAddress: nodeAddress, - signerKey: signerKey, - storage: storage, - allowlist: allowlist, - rateLimiter: rateLimiter, - subscriptions: subscriptions, - minimumBalance: minimumBalance, - listener: listener, - offchainTransmitter: offchainTransmitter, - heartbeatRequests: make(map[RequestID]*HeartbeatResponse), - chStop: make(services.StopChan), - lggr: lggr.Named("FunctionsConnectorHandler"), + nodeAddress: pluginConfig.GatewayConnectorConfig.NodeAddress, + signerKey: signerKey, + storage: storage, + allowlist: allowlist, + rateLimiter: rateLimiter, + subscriptions: subscriptions, + minimumBalance: pluginConfig.MinimumSubscriptionBalance, + listener: listener, + offchainTransmitter: offchainTransmitter, + allowedHeartbeatInitiators: allowedHeartbeatInitiators, + heartbeatRequests: make(map[RequestID]*HeartbeatResponse), + requestTimeoutSec: pluginConfig.RequestTimeoutSec, + chStop: make(services.StopChan), + lggr: lggr.Named("FunctionsConnectorHandler"), }, nil } @@ -185,6 +203,7 @@ func (h *functionsConnectorHandler) handleSecretsSet(ctx context.Context, gatewa err = h.storage.Put(ctx, &key, &record, request.Signature) if err == nil { response.Success = true + promStorageUserUpdatesCount.WithLabelValues().Inc() } else { response.ErrorMessage = fmt.Sprintf("Failed to set secret: %v", err) } @@ -201,6 +220,10 @@ func (h *functionsConnectorHandler) handleHeartbeat(ctx context.Context, gateway h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse(fmt.Sprintf("failed to unmarshal request: %v", err))) return } + if _, ok := h.allowedHeartbeatInitiators[requestBody.Sender]; !ok { + h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse("sender not allowed to send heartbeat requests")) + return + } if !bytes.Equal(request.RequestInitiator, fromAddr.Bytes()) { h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse("RequestInitiator doesn't match sender")) return @@ -209,6 +232,10 @@ func (h *functionsConnectorHandler) handleHeartbeat(ctx context.Context, gateway h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse("SubscriptionOwner doesn't match sender")) return } + if request.Timestamp < uint64(time.Now().Unix())-uint64(h.requestTimeoutSec) { + h.sendResponseAndLog(ctx, gatewayId, requestBody, internalErrorResponse("Request is too old")) + return + } internalId := InternalId(fromAddr.Bytes(), request.RequestId) request.RequestId = internalId[:] @@ -240,7 +267,7 @@ func internalErrorResponse(internalError string) HeartbeatResponse { func (h *functionsConnectorHandler) handleOffchainRequest(request *OffchainRequest) { defer h.shutdownWaitGroup.Done() stopCtx, _ := h.chStop.NewCtx() - ctx, cancel := context.WithTimeout(stopCtx, time.Duration(HeartbeatRequestTimeoutSec)*time.Second) + ctx, cancel := context.WithTimeout(stopCtx, time.Duration(h.requestTimeoutSec)*time.Second) defer cancel() err := h.listener.HandleOffchainRequest(ctx, request) if err != nil { diff --git a/core/services/functions/connector_handler_test.go b/core/services/functions/connector_handler_test.go index 409f9cdcc56..aadc84ba96a 100644 --- a/core/services/functions/connector_handler_test.go +++ b/core/services/functions/connector_handler_test.go @@ -10,6 +10,7 @@ import ( "time" geth_common "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/onsi/gomega" "github.com/smartcontractkit/chainlink-common/pkg/assets" @@ -19,9 +20,12 @@ import ( sfmocks "github.com/smartcontractkit/chainlink/v2/core/services/functions/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/common" + gwconnector "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" gcmocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector/mocks" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" - gfmocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/mocks" + fallowMocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist/mocks" + fsubMocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" "github.com/smartcontractkit/chainlink/v2/core/services/s4" s4mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" @@ -30,7 +34,7 @@ import ( "github.com/stretchr/testify/require" ) -func newOffchainRequest(t *testing.T, sender []byte) (*api.Message, functions.RequestID) { +func newOffchainRequest(t *testing.T, sender []byte, ageSec uint64) (*api.Message, functions.RequestID) { requestId := make([]byte, 32) _, err := rand.Read(requestId) require.NoError(t, err) @@ -39,6 +43,7 @@ func newOffchainRequest(t *testing.T, sender []byte) (*api.Message, functions.Re RequestInitiator: sender, SubscriptionId: 1, SubscriptionOwner: sender, + Timestamp: uint64(time.Now().Unix()) - ageSec, } internalId := functions.InternalId(request.RequestInitiator, request.RequestId) @@ -62,9 +67,9 @@ func TestFunctionsConnectorHandler(t *testing.T) { privateKey, addr := testutils.NewPrivateKeyAndAddress(t) storage := s4mocks.NewStorage(t) connector := gcmocks.NewGatewayConnector(t) - allowlist := gfmocks.NewOnchainAllowlist(t) + allowlist := fallowMocks.NewOnchainAllowlist(t) rateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) - subscriptions := gfmocks.NewOnchainSubscriptions(t) + subscriptions := fsubMocks.NewOnchainSubscriptions(t) reportCh := make(chan *functions.OffchainResponse) offchainTransmitter := sfmocks.NewOffchainTransmitter(t) offchainTransmitter.On("ReportChannel", mock.Anything).Return(reportCh) @@ -74,7 +79,15 @@ func TestFunctionsConnectorHandler(t *testing.T) { allowlist.On("Close", mock.Anything).Return(nil) subscriptions.On("Start", mock.Anything).Return(nil) subscriptions.On("Close", mock.Anything).Return(nil) - handler, err := functions.NewFunctionsConnectorHandler(addr.Hex(), privateKey, storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, *assets.NewLinkFromJuels(100), logger) + config := &config.PluginConfig{ + GatewayConnectorConfig: &gwconnector.ConnectorConfig{ + NodeAddress: addr.Hex(), + }, + MinimumSubscriptionBalance: *assets.NewLinkFromJuels(100), + RequestTimeoutSec: 1_000, + AllowedHeartbeatInitiators: []string{crypto.PubkeyToAddress(privateKey.PublicKey).Hex()}, + } + handler, err := functions.NewFunctionsConnectorHandler(config, privateKey, storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger) require.NoError(t, err) handler.SetConnector(connector) @@ -257,7 +270,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { t.Run("heartbeat success", func(t *testing.T) { ctx := testutils.Context(t) - msg, internalId := newOffchainRequest(t, addr.Bytes()) + msg, internalId := newOffchainRequest(t, addr.Bytes(), 0) require.NoError(t, msg.Sign(privateKey)) // first call to trigger the request @@ -292,7 +305,7 @@ func TestFunctionsConnectorHandler(t *testing.T) { t.Run("heartbeat internal error", func(t *testing.T) { ctx := testutils.Context(t) - msg, _ := newOffchainRequest(t, addr.Bytes()) + msg, _ := newOffchainRequest(t, addr.Bytes(), 0) require.NoError(t, msg.Sign(privateKey)) // first call to trigger the request @@ -319,7 +332,23 @@ func TestFunctionsConnectorHandler(t *testing.T) { t.Run("heartbeat sender address doesn't match", func(t *testing.T) { ctx := testutils.Context(t) - msg, _ := newOffchainRequest(t, geth_common.BytesToAddress([]byte("0x1234")).Bytes()) + msg, _ := newOffchainRequest(t, geth_common.BytesToAddress([]byte("0x1234")).Bytes(), 0) + require.NoError(t, msg.Sign(privateKey)) + + var response functions.HeartbeatResponse + allowlist.On("Allow", addr).Return(true).Once() + connector.On("SendToGateway", mock.Anything, "gw1", mock.Anything).Run(func(args mock.Arguments) { + respMsg, ok := args[2].(*api.Message) + require.True(t, ok) + require.NoError(t, json.Unmarshal(respMsg.Body.Payload, &response)) + require.Equal(t, functions.RequestStateInternalError, response.Status) + }).Return(nil).Once() + handler.HandleGatewayMessage(ctx, "gw1", msg) + }) + + t.Run("heartbeat request too old", func(t *testing.T) { + ctx := testutils.Context(t) + msg, _ := newOffchainRequest(t, addr.Bytes(), 10_000) require.NoError(t, msg.Sign(privateKey)) var response functions.HeartbeatResponse diff --git a/core/services/functions/external_adapter_client.go b/core/services/functions/external_adapter_client.go index db4fed30e5f..fb64924a922 100644 --- a/core/services/functions/external_adapter_client.go +++ b/core/services/functions/external_adapter_client.go @@ -14,8 +14,8 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" "github.com/smartcontractkit/chainlink/v2/core/bridges" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ExternalAdapterClient supports two endpoints: @@ -228,13 +228,13 @@ func (ea *externalAdapterClient) request( switch eaResp.Result { case "error": - userError, err = utils.TryParseHex(eaResp.Data.Error) + userError, err = hex.DecodeString(eaResp.Data.Error) if err != nil { return nil, nil, nil, errors.Wrap(err, "error decoding userError hex string") } return nil, userError, eaResp.Data.Domains, nil case "success": - userResult, err = utils.TryParseHex(eaResp.Data.Result) + userResult, err = hex.DecodeString(eaResp.Data.Result) if err != nil { return nil, nil, nil, errors.Wrap(err, "error decoding result hex string") } diff --git a/core/services/functions/listener.go b/core/services/functions/listener.go index 65c364adb7c..f9d74f1bae9 100644 --- a/core/services/functions/listener.go +++ b/core/services/functions/listener.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/cbor" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/functions/listener_test.go b/core/services/functions/listener_test.go index 0fcc9c65599..75161d3410b 100644 --- a/core/services/functions/listener_test.go +++ b/core/services/functions/listener_test.go @@ -19,6 +19,9 @@ import ( decryptionPlugin "github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -38,12 +41,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" evmrelay_mocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types/mocks" s4_mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" sync_mocks "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type FunctionsListenerUniverse struct { @@ -81,7 +82,7 @@ func NewFunctionsListenerUniverse(t *testing.T, timeoutSec int, pruneFrequencySe ethClient := evmtest.NewEthClientMockWithDefaultChain(t) broadcaster := log_mocks.NewBroadcaster(t) broadcaster.On("AddDependents", 1) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) db := pgtest.NewSqlxDB(t) kst := cltest.NewKeyStore(t, db, cfg.Database()) @@ -160,7 +161,7 @@ func TestFunctionsListener_HandleOracleRequestV1_Success(t *testing.T) { request := types.OracleRequest{ RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner, Flags: packFlags(1, 0), // tier no 1 of request size, allows up to 100 bytes Data: make([]byte, 12), @@ -175,9 +176,8 @@ func TestFunctionsListener_HandleOracleRequestV1_Success(t *testing.T) { close(doneCh) }).Return(nil) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_HandleOffchainRequest_Success(t *testing.T) { @@ -194,7 +194,7 @@ func TestFunctionsListener_HandleOffchainRequest_Success(t *testing.T) { request := &functions_service.OffchainRequest{ RequestId: RequestID[:], RequestInitiator: SubscriptionOwner.Bytes(), - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner.Bytes(), Timestamp: uint64(time.Now().Unix()), Data: functions_service.RequestData{}, @@ -210,7 +210,7 @@ func TestFunctionsListener_HandleOffchainRequest_Invalid(t *testing.T) { request := &functions_service.OffchainRequest{ RequestId: RequestID[:], RequestInitiator: []byte("invalid_address"), - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner.Bytes(), Timestamp: uint64(time.Now().Unix()), Data: functions_service.RequestData{}, @@ -238,7 +238,7 @@ func TestFunctionsListener_HandleOffchainRequest_InternalError(t *testing.T) { request := &functions_service.OffchainRequest{ RequestId: RequestID[:], RequestInitiator: SubscriptionOwner.Bytes(), - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner.Bytes(), Timestamp: uint64(time.Now().Unix()), Data: functions_service.RequestData{}, @@ -255,7 +255,7 @@ func TestFunctionsListener_HandleOracleRequestV1_ComputationError(t *testing.T) request := types.OracleRequest{ RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner, Flags: packFlags(1, 0), // tier no 1 of request size, allows up to 100 bytes Data: make([]byte, 12), @@ -270,9 +270,8 @@ func TestFunctionsListener_HandleOracleRequestV1_ComputationError(t *testing.T) close(doneCh) }).Return(nil) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_HandleOracleRequestV1_ThresholdDecryptedSecrets(t *testing.T) { @@ -292,7 +291,7 @@ func TestFunctionsListener_HandleOracleRequestV1_ThresholdDecryptedSecrets(t *te cborBytes = cborBytes[1:] request := types.OracleRequest{ RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner, Flags: packFlags(1, 1), // tiers no 1 of request size and secrets size, allow up to 100 bytes Data: cborBytes, @@ -312,9 +311,8 @@ func TestFunctionsListener_HandleOracleRequestV1_ThresholdDecryptedSecrets(t *te close(doneCh) }).Return(nil) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_HandleOracleRequestV1_CBORTooBig(t *testing.T) { @@ -326,7 +324,7 @@ func TestFunctionsListener_HandleOracleRequestV1_CBORTooBig(t *testing.T) { request := types.OracleRequest{ RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner, Flags: packFlags(0, 0), // tier no 0 of request size, allows only for max 10 bytes Data: make([]byte, 20), @@ -339,9 +337,8 @@ func TestFunctionsListener_HandleOracleRequestV1_CBORTooBig(t *testing.T) { close(doneCh) }).Return(nil) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_ReportSourceCodeDomains(t *testing.T) { @@ -353,7 +350,7 @@ func TestFunctionsListener_ReportSourceCodeDomains(t *testing.T) { request := types.OracleRequest{ RequestId: RequestID, - SubscriptionId: uint64(SubscriptionID), + SubscriptionId: SubscriptionID, SubscriptionOwner: SubscriptionOwner, Flags: packFlags(1, 0), // tier no 1 of request size, allows up to 100 bytes Data: make([]byte, 12), @@ -395,9 +392,8 @@ func TestFunctionsListener_PruneRequests(t *testing.T) { doneCh <- true }) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_TimeoutRequests(t *testing.T) { @@ -411,9 +407,8 @@ func TestFunctionsListener_TimeoutRequests(t *testing.T) { doneCh <- true }) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) <-doneCh - uni.service.Close() } func TestFunctionsListener_ORMDoesNotFreezeHandlersForever(t *testing.T) { @@ -434,7 +429,6 @@ func TestFunctionsListener_ORMDoesNotFreezeHandlersForever(t *testing.T) { ormCallExited.Done() }).Return(errors.New("timeout")) - require.NoError(t, uni.service.Start(testutils.Context(t))) + servicetest.Run(t, uni.service) ormCallExited.Wait() // should not freeze - uni.service.Close() } diff --git a/core/services/functions/mocks/bridge_accessor.go b/core/services/functions/mocks/bridge_accessor.go index 65e81ab8b83..fa765287c44 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type BridgeAccessor struct { func (_m *BridgeAccessor) NewExternalAdapterClient() (functions.ExternalAdapterClient, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for NewExternalAdapterClient") + } + var r0 functions.ExternalAdapterClient var r1 error if rf, ok := ret.Get(0).(func() (functions.ExternalAdapterClient, error)); ok { diff --git a/core/services/functions/mocks/external_adapter_client.go b/core/services/functions/mocks/external_adapter_client.go index b06f13fdea7..dbf4081c95d 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type ExternalAdapterClient struct { func (_m *ExternalAdapterClient) FetchEncryptedSecrets(ctx context.Context, encryptedSecretsUrls []byte, requestId string, jobName string) ([]byte, []byte, error) { ret := _m.Called(ctx, encryptedSecretsUrls, requestId, jobName) + if len(ret) == 0 { + panic("no return value specified for FetchEncryptedSecrets") + } + var r0 []byte var r1 []byte var r2 error @@ -53,6 +57,10 @@ func (_m *ExternalAdapterClient) FetchEncryptedSecrets(ctx context.Context, encr func (_m *ExternalAdapterClient) RunComputation(ctx context.Context, requestId string, jobName string, subscriptionOwner string, subscriptionId uint64, flags functions.RequestFlags, nodeProvidedSecrets string, requestData *functions.RequestData) ([]byte, []byte, []string, error) { ret := _m.Called(ctx, requestId, jobName, subscriptionOwner, subscriptionId, flags, nodeProvidedSecrets, requestData) + if len(ret) == 0 { + panic("no return value specified for RunComputation") + } + var r0 []byte var r1 []byte var r2 []string diff --git a/core/services/functions/mocks/functions_listener.go b/core/services/functions/mocks/functions_listener.go index d2aeb2ddab8..d63248f00cf 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type FunctionsListener struct { func (_m *FunctionsListener) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *FunctionsListener) Close() error { func (_m *FunctionsListener) HandleOffchainRequest(ctx context.Context, request *functions.OffchainRequest) error { ret := _m.Called(ctx, request) + if len(ret) == 0 { + panic("no return value specified for HandleOffchainRequest") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *functions.OffchainRequest) error); ok { r0 = rf(ctx, request) @@ -46,6 +54,10 @@ func (_m *FunctionsListener) HandleOffchainRequest(ctx context.Context, request func (_m *FunctionsListener) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/functions/mocks/offchain_transmitter.go b/core/services/functions/mocks/offchain_transmitter.go index d9a7be04dd4..5eee967e685 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type OffchainTransmitter struct { func (_m *OffchainTransmitter) ReportChannel() chan *functions.OffchainResponse { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ReportChannel") + } + var r0 chan *functions.OffchainResponse if rf, ok := ret.Get(0).(func() chan *functions.OffchainResponse); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *OffchainTransmitter) ReportChannel() chan *functions.OffchainResponse func (_m *OffchainTransmitter) TransmitReport(ctx context.Context, report *functions.OffchainResponse) error { ret := _m.Called(ctx, report) + if len(ret) == 0 { + panic("no return value specified for TransmitReport") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *functions.OffchainResponse) error); ok { r0 = rf(ctx, report) diff --git a/core/services/functions/mocks/orm.go b/core/services/functions/mocks/orm.go index 8d11b0b9817..90055fe6286 100644 --- a/core/services/functions/mocks/orm.go +++ b/core/services/functions/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -27,6 +27,10 @@ func (_m *ORM) CreateRequest(request *functions.Request, qopts ...pg.QOpt) error _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateRequest") + } + var r0 error if rf, ok := ret.Get(0).(func(*functions.Request, ...pg.QOpt) error); ok { r0 = rf(request, qopts...) @@ -48,6 +52,10 @@ func (_m *ORM) FindById(requestID functions.RequestID, qopts ...pg.QOpt) (*funct _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindById") + } + var r0 *functions.Request var r1 error if rf, ok := ret.Get(0).(func(functions.RequestID, ...pg.QOpt) (*functions.Request, error)); ok { @@ -81,6 +89,10 @@ func (_m *ORM) FindOldestEntriesByState(state functions.RequestState, limit uint _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindOldestEntriesByState") + } + var r0 []functions.Request var r1 error if rf, ok := ret.Get(0).(func(functions.RequestState, uint32, ...pg.QOpt) ([]functions.Request, error)); ok { @@ -114,6 +126,10 @@ func (_m *ORM) PruneOldestRequests(maxRequestsInDB uint32, batchSize uint32, qop _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for PruneOldestRequests") + } + var r0 uint32 var r1 uint32 var r2 error @@ -152,6 +168,10 @@ func (_m *ORM) SetConfirmed(requestID functions.RequestID, qopts ...pg.QOpt) err _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for SetConfirmed") + } + var r0 error if rf, ok := ret.Get(0).(func(functions.RequestID, ...pg.QOpt) error); ok { r0 = rf(requestID, qopts...) @@ -173,6 +193,10 @@ func (_m *ORM) SetError(requestID functions.RequestID, errorType functions.ErrTy _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for SetError") + } + var r0 error if rf, ok := ret.Get(0).(func(functions.RequestID, functions.ErrType, []byte, time.Time, bool, ...pg.QOpt) error); ok { r0 = rf(requestID, errorType, computationError, readyAt, readyForProcessing, qopts...) @@ -194,6 +218,10 @@ func (_m *ORM) SetFinalized(requestID functions.RequestID, reportedResult []byte _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for SetFinalized") + } + var r0 error if rf, ok := ret.Get(0).(func(functions.RequestID, []byte, []byte, ...pg.QOpt) error); ok { r0 = rf(requestID, reportedResult, reportedError, qopts...) @@ -215,6 +243,10 @@ func (_m *ORM) SetResult(requestID functions.RequestID, computationResult []byte _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for SetResult") + } + var r0 error if rf, ok := ret.Get(0).(func(functions.RequestID, []byte, time.Time, ...pg.QOpt) error); ok { r0 = rf(requestID, computationResult, readyAt, qopts...) @@ -236,6 +268,10 @@ func (_m *ORM) TimeoutExpiredResults(cutoff time.Time, limit uint32, qopts ...pg _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for TimeoutExpiredResults") + } + var r0 []functions.RequestID var r1 error if rf, ok := ret.Get(0).(func(time.Time, uint32, ...pg.QOpt) ([]functions.RequestID, error)); ok { diff --git a/core/services/functions/orm_test.go b/core/services/functions/orm_test.go index 459b1f56a60..ca92aafcb0e 100644 --- a/core/services/functions/orm_test.go +++ b/core/services/functions/orm_test.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -47,7 +48,7 @@ func createRequest(t *testing.T, orm functions.ORM) (functions.RequestID, common func createRequestWithTimestamp(t *testing.T, orm functions.ORM, ts time.Time) (functions.RequestID, common.Hash) { id := newRequestID() - txHash := testutils.NewAddress().Hash() + txHash := utils.RandomHash() newReq := &functions.Request{ RequestID: id, RequestTxHash: &txHash, diff --git a/core/services/gateway/api/message.go b/core/services/gateway/api/message.go index d0a116675ae..5e6c8e49247 100644 --- a/core/services/gateway/api/message.go +++ b/core/services/gateway/api/message.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" gw_common "github.com/smartcontractkit/chainlink/v2/core/services/gateway/common" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -19,6 +20,7 @@ const ( MessageMethodMaxLen = 64 MessageDonIdMaxLen = 64 MessageReceiverLen = 2 + 2*20 + NullChar = "\x00" ) /* @@ -55,12 +57,21 @@ func (m *Message) Validate() error { if len(m.Body.MessageId) == 0 || len(m.Body.MessageId) > MessageIdMaxLen { return errors.New("invalid message ID length") } + if strings.HasSuffix(m.Body.MessageId, NullChar) { + return errors.New("message ID ending with null bytes") + } if len(m.Body.Method) == 0 || len(m.Body.Method) > MessageMethodMaxLen { return errors.New("invalid method name length") } + if strings.HasSuffix(m.Body.Method, NullChar) { + return errors.New("method name ending with null bytes") + } if len(m.Body.DonId) == 0 || len(m.Body.DonId) > MessageDonIdMaxLen { return errors.New("invalid DON ID length") } + if strings.HasSuffix(m.Body.DonId, NullChar) { + return errors.New("DON ID ending with null bytes") + } if len(m.Body.Receiver) != 0 && len(m.Body.Receiver) != MessageReceiverLen { return errors.New("invalid Receiver length") } @@ -97,7 +108,7 @@ func (m *Message) ExtractSigner() (signerAddress []byte, err error) { return nil, errors.New("nil message") } rawData := getRawMessageBody(&m.Body) - signatureBytes, err := utils.TryParseHex(m.Signature) + signatureBytes, err := hex.DecodeString(m.Signature) if err != nil { return nil, err } diff --git a/core/services/gateway/api/message_test.go b/core/services/gateway/api/message_test.go index a0835ea24bb..1f292db26b9 100644 --- a/core/services/gateway/api/message_test.go +++ b/core/services/gateway/api/message_test.go @@ -31,22 +31,38 @@ func TestMessage_Validate(t *testing.T) { // missing message ID msg.Body.MessageId = "" require.Error(t, msg.Validate()) + // message ID ending with null bytes + msg.Body.MessageId = "myid\x00\x00" + require.Error(t, msg.Validate()) msg.Body.MessageId = "abcd" + require.NoError(t, msg.Validate()) // missing DON ID msg.Body.DonId = "" require.Error(t, msg.Validate()) + // DON ID ending with null bytes + msg.Body.DonId = "mydon\x00\x00" + require.Error(t, msg.Validate()) msg.Body.DonId = "donA" + require.NoError(t, msg.Validate()) - // method too long + // method name too long msg.Body.Method = string(bytes.Repeat([]byte("a"), api.MessageMethodMaxLen+1)) require.Error(t, msg.Validate()) + // empty method name + msg.Body.Method = "" + require.Error(t, msg.Validate()) + // method name ending with null bytes + msg.Body.Method = "method\x00" + require.Error(t, msg.Validate()) msg.Body.Method = "request" + require.NoError(t, msg.Validate()) // incorrect receiver msg.Body.Receiver = "blah" require.Error(t, msg.Validate()) msg.Body.Receiver = "0x0000000000000000000000000000000000000000" + require.NoError(t, msg.Validate()) // invalid signature msg.Signature = "0x00" diff --git a/core/services/gateway/connectionmanager.go b/core/services/gateway/connectionmanager.go index 9f88b51e7b5..e5f7fb13afb 100644 --- a/core/services/gateway/connectionmanager.go +++ b/core/services/gateway/connectionmanager.go @@ -287,6 +287,10 @@ func (m *donConnectionManager) readLoop(nodeAddress string, nodeState *nodeState m.lggr.Errorw("message validation error when reading from node", "nodeAddress", nodeAddress, "err", err) break } + if msg.Body.Sender != nodeAddress { + m.lggr.Errorw("message sender mismatch when reading from node", "nodeAddress", nodeAddress, "sender", msg.Body.Sender) + break + } err = m.handler.HandleNodeMessage(ctx, msg, nodeAddress) if err != nil { m.lggr.Error("error when calling HandleNodeMessage ", err) diff --git a/core/services/gateway/connector/connector.go b/core/services/gateway/connector/connector.go index 27db8fd44b6..9f809a326c8 100644 --- a/core/services/gateway/connector/connector.go +++ b/core/services/gateway/connector/connector.go @@ -11,6 +11,7 @@ import ( "github.com/gorilla/websocket" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" @@ -82,10 +83,10 @@ func NewGatewayConnector(config *ConnectorConfig, signer Signer, handler Gateway if config == nil || signer == nil || handler == nil || clock == nil || lggr == nil { return nil, errors.New("nil dependency") } - if len(config.DonId) == 0 || len(config.DonId) > int(network.HandshakeDonIdLen) { + if len(config.DonId) == 0 || len(config.DonId) > network.HandshakeDonIdLen { return nil, errors.New("invalid DON ID") } - addressBytes, err := utils.TryParseHex(config.NodeAddress) + addressBytes, err := hex.DecodeString(config.NodeAddress) if err != nil { return nil, err } diff --git a/core/services/gateway/connector/connector_test.go b/core/services/gateway/connector/connector_test.go index 4001914524b..1c2c6d26b10 100644 --- a/core/services/gateway/connector/connector_test.go +++ b/core/services/gateway/connector/connector_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector/mocks" @@ -121,8 +121,7 @@ func TestGatewayConnector_CleanStartAndClose(t *testing.T) { handler.On("Start", mock.Anything).Return(nil) handler.On("Close").Return(nil) signer.On("Sign", mock.Anything).Return(nil, errors.New("cannot sign")) - require.NoError(t, connector.Start(testutils.Context(t))) - require.NoError(t, connector.Close()) + servicetest.Run(t, connector) } func TestGatewayConnector_NewAuthHeader_SignerError(t *testing.T) { diff --git a/core/services/gateway/connector/mocks/gateway_connector.go b/core/services/gateway/connector/mocks/gateway_connector.go index a9fa69e1e3b..ba972425f66 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type GatewayConnector struct { func (_m *GatewayConnector) ChallengeResponse(_a0 *url.URL, challenge []byte) ([]byte, error) { ret := _m.Called(_a0, challenge) + if len(ret) == 0 { + panic("no return value specified for ChallengeResponse") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*url.URL, []byte) ([]byte, error)); ok { @@ -47,6 +51,10 @@ func (_m *GatewayConnector) ChallengeResponse(_a0 *url.URL, challenge []byte) ([ func (_m *GatewayConnector) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -61,6 +69,10 @@ func (_m *GatewayConnector) Close() error { func (_m *GatewayConnector) NewAuthHeader(_a0 *url.URL) ([]byte, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for NewAuthHeader") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*url.URL) ([]byte, error)); ok { @@ -87,6 +99,10 @@ func (_m *GatewayConnector) NewAuthHeader(_a0 *url.URL) ([]byte, error) { func (_m *GatewayConnector) SendToGateway(ctx context.Context, gatewayId string, msg *api.Message) error { ret := _m.Called(ctx, gatewayId, msg) + if len(ret) == 0 { + panic("no return value specified for SendToGateway") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, *api.Message) error); ok { r0 = rf(ctx, gatewayId, msg) @@ -101,6 +117,10 @@ func (_m *GatewayConnector) SendToGateway(ctx context.Context, gatewayId string, func (_m *GatewayConnector) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/connector/mocks/gateway_connector_handler.go b/core/services/gateway/connector/mocks/gateway_connector_handler.go index 8eb27708a5a..e83e06b60e3 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type GatewayConnectorHandler struct { func (_m *GatewayConnectorHandler) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -38,6 +42,10 @@ func (_m *GatewayConnectorHandler) HandleGatewayMessage(ctx context.Context, gat func (_m *GatewayConnectorHandler) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/connector/mocks/signer.go b/core/services/gateway/connector/mocks/signer.go index 497b25d8df3..18c7186f7fc 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ func (_m *Signer) Sign(data ...[]byte) ([]byte, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Sign") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(...[]byte) ([]byte, error)); ok { diff --git a/core/services/gateway/delegate.go b/core/services/gateway/delegate.go index d4180184aca..8a97f68d1ea 100644 --- a/core/services/gateway/delegate.go +++ b/core/services/gateway/delegate.go @@ -4,6 +4,7 @@ import ( "encoding/json" "github.com/google/uuid" + "github.com/jmoiron/sqlx" "github.com/pelletier/go-toml" "github.com/pkg/errors" @@ -18,13 +19,21 @@ import ( type Delegate struct { legacyChains legacyevm.LegacyChainContainer ks keystore.Eth + db *sqlx.DB + cfg pg.QConfig lggr logger.Logger } var _ job.Delegate = (*Delegate)(nil) -func NewDelegate(legacyChains legacyevm.LegacyChainContainer, ks keystore.Eth, lggr logger.Logger) *Delegate { - return &Delegate{legacyChains: legacyChains, ks: ks, lggr: lggr} +func NewDelegate(legacyChains legacyevm.LegacyChainContainer, ks keystore.Eth, db *sqlx.DB, cfg pg.QConfig, lggr logger.Logger) *Delegate { + return &Delegate{ + legacyChains: legacyChains, + ks: ks, + db: db, + cfg: cfg, + lggr: lggr, + } } func (d *Delegate) JobType() job.Type { @@ -47,7 +56,7 @@ func (d *Delegate) ServicesForSpec(spec job.Job) (services []job.ServiceCtx, err if err2 != nil { return nil, errors.Wrap(err2, "unmarshal gateway config") } - handlerFactory := NewHandlerFactory(d.legacyChains, d.lggr) + handlerFactory := NewHandlerFactory(d.legacyChains, d.db, d.cfg, d.lggr) gateway, err := NewGatewayFromConfig(&gatewayConfig, handlerFactory, d.lggr) if err != nil { return nil, err diff --git a/core/services/gateway/gateway_test.go b/core/services/gateway/gateway_test.go index 5fad6315a31..7a5457c788c 100644 --- a/core/services/gateway/gateway_test.go +++ b/core/services/gateway/gateway_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway" @@ -56,7 +57,7 @@ Address = "0x0001020304050607080900010203040506070809" `) lggr := logger.TestLogger(t) - _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, lggr), lggr) + _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, nil, nil, lggr), lggr) require.NoError(t, err) } @@ -74,7 +75,7 @@ HandlerName = "dummy" `) lggr := logger.TestLogger(t) - _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, lggr), lggr) + _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, nil, nil, lggr), lggr) require.Error(t, err) } @@ -88,7 +89,7 @@ HandlerName = "no_such_handler" `) lggr := logger.TestLogger(t) - _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, lggr), lggr) + _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, nil, nil, lggr), lggr) require.Error(t, err) } @@ -102,7 +103,7 @@ SomeOtherField = "abcd" `) lggr := logger.TestLogger(t) - _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, lggr), lggr) + _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, nil, nil, lggr), lggr) require.Error(t, err) } @@ -120,7 +121,7 @@ Address = "0xnot_an_address" `) lggr := logger.TestLogger(t) - _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, lggr), lggr) + _, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, tomlConfig), gateway.NewHandlerFactory(nil, nil, nil, lggr), lggr) require.Error(t, err) } @@ -128,10 +129,9 @@ func TestGateway_CleanStartAndClose(t *testing.T) { t.Parallel() lggr := logger.TestLogger(t) - gateway, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, buildConfig("")), gateway.NewHandlerFactory(nil, lggr), lggr) + gateway, err := gateway.NewGatewayFromConfig(parseTOMLConfig(t, buildConfig("")), gateway.NewHandlerFactory(nil, nil, nil, lggr), lggr) require.NoError(t, err) - require.NoError(t, gateway.Start(testutils.Context(t))) - require.NoError(t, gateway.Close()) + servicetest.Run(t, gateway) } func requireJsonRPCResult(t *testing.T, response []byte, expectedId string, expectedResult string) { @@ -225,7 +225,7 @@ func TestGateway_ProcessRequest_HandlerTimeout(t *testing.T) { gw, handler := newGatewayWithMockHandler(t) handler.On("HandleUserMessage", mock.Anything, mock.Anything, mock.Anything).Return(nil) - timeoutCtx, cancel := context.WithTimeout(testutils.Context(t), time.Duration(time.Millisecond*10)) + timeoutCtx, cancel := context.WithTimeout(testutils.Context(t), time.Millisecond*10) defer cancel() req := newSignedRequest(t, "abcd", "request", "testDON", []byte{}) diff --git a/core/services/gateway/handler_factory.go b/core/services/gateway/handler_factory.go index 368bc64c872..8ccae8c7c4b 100644 --- a/core/services/gateway/handler_factory.go +++ b/core/services/gateway/handler_factory.go @@ -4,11 +4,14 @@ import ( "encoding/json" "fmt" + "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) const ( @@ -18,19 +21,21 @@ const ( type handlerFactory struct { legacyChains legacyevm.LegacyChainContainer + db *sqlx.DB + cfg pg.QConfig lggr logger.Logger } var _ HandlerFactory = (*handlerFactory)(nil) -func NewHandlerFactory(legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger) HandlerFactory { - return &handlerFactory{legacyChains, lggr} +func NewHandlerFactory(legacyChains legacyevm.LegacyChainContainer, db *sqlx.DB, cfg pg.QConfig, lggr logger.Logger) HandlerFactory { + return &handlerFactory{legacyChains, db, cfg, lggr} } func (hf *handlerFactory) NewHandler(handlerType HandlerType, handlerConfig json.RawMessage, donConfig *config.DONConfig, don handlers.DON) (handlers.Handler, error) { switch handlerType { case FunctionsHandlerType: - return functions.NewFunctionsHandlerFromConfig(handlerConfig, donConfig, don, hf.legacyChains, hf.lggr) + return functions.NewFunctionsHandlerFromConfig(handlerConfig, donConfig, don, hf.legacyChains, hf.db, hf.cfg, hf.lggr) case DummyHandlerType: return handlers.NewDummyHandler(donConfig, don, hf.lggr) default: diff --git a/core/services/gateway/handlers/functions/allowlist.go b/core/services/gateway/handlers/functions/allowlist/allowlist.go similarity index 51% rename from core/services/gateway/handlers/functions/allowlist.go rename to core/services/gateway/handlers/functions/allowlist/allowlist.go index 0a18d6e6d87..20dc92ced70 100644 --- a/core/services/gateway/handlers/functions/allowlist.go +++ b/core/services/gateway/handlers/functions/allowlist/allowlist.go @@ -1,4 +1,4 @@ -package functions +package allowlist import ( "context" @@ -22,14 +22,26 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) +const ( + defaultStoredAllowlistBatchSize = 1000 + defaultOnchainAllowlistBatchSize = 100 + defaultFetchingDelayInRangeSec = 1 +) + type OnchainAllowlistConfig struct { // ContractAddress is required ContractAddress common.Address `json:"contractAddress"` ContractVersion uint32 `json:"contractVersion"` BlockConfirmations uint `json:"blockConfirmations"` // UpdateFrequencySec can be zero to disable periodic updates - UpdateFrequencySec uint `json:"updateFrequencySec"` - UpdateTimeoutSec uint `json:"updateTimeoutSec"` + UpdateFrequencySec uint `json:"updateFrequencySec"` + UpdateTimeoutSec uint `json:"updateTimeoutSec"` + StoredAllowlistBatchSize uint `json:"storedAllowlistBatchSize"` + OnchainAllowlistBatchSize uint `json:"onchainAllowlistBatchSize"` + // StoreAllowedSendersEnabled is a feature flag that enables storing in db a copy of the allowlist. + StoreAllowedSendersEnabled bool `json:"storeAllowedSendersEnabled"` + // FetchingDelayInRangeSec prevents RPC client being rate limited when fetching the allowlist in ranges. + FetchingDelayInRangeSec uint `json:"fetchingDelayInRangeSec"` } // OnchainAllowlist maintains an allowlist of addresses fetched from the blockchain (EVM-only). @@ -50,6 +62,7 @@ type onchainAllowlist struct { config OnchainAllowlistConfig allowlist atomic.Pointer[map[common.Address]struct{}] + orm ORM client evmclient.Client contractV1 *functions_router.FunctionsRouter blockConfirmations *big.Int @@ -58,7 +71,7 @@ type onchainAllowlist struct { stopCh services.StopChan } -func NewOnchainAllowlist(client evmclient.Client, config OnchainAllowlistConfig, lggr logger.Logger) (OnchainAllowlist, error) { +func NewOnchainAllowlist(client evmclient.Client, config OnchainAllowlistConfig, orm ORM, lggr logger.Logger) (OnchainAllowlist, error) { if client == nil { return nil, errors.New("client is nil") } @@ -68,12 +81,33 @@ func NewOnchainAllowlist(client evmclient.Client, config OnchainAllowlistConfig, if config.ContractVersion != 1 { return nil, fmt.Errorf("unsupported contract version %d", config.ContractVersion) } + + if config.StoredAllowlistBatchSize == 0 { + lggr.Info("StoredAllowlistBatchSize not specified, using default size: ", defaultStoredAllowlistBatchSize) + config.StoredAllowlistBatchSize = defaultStoredAllowlistBatchSize + } + + if config.OnchainAllowlistBatchSize == 0 { + lggr.Info("OnchainAllowlistBatchSize not specified, using default size: ", defaultOnchainAllowlistBatchSize) + config.OnchainAllowlistBatchSize = defaultOnchainAllowlistBatchSize + } + + if config.FetchingDelayInRangeSec == 0 { + lggr.Info("FetchingDelayInRangeSec not specified, using default delay: ", defaultFetchingDelayInRangeSec) + config.FetchingDelayInRangeSec = defaultFetchingDelayInRangeSec + } + + if config.UpdateFrequencySec != 0 && config.FetchingDelayInRangeSec >= config.UpdateFrequencySec { + return nil, fmt.Errorf("to avoid updates overlapping FetchingDelayInRangeSec:%d should be less than UpdateFrequencySec:%d", config.FetchingDelayInRangeSec, config.UpdateFrequencySec) + } + contractV1, err := functions_router.NewFunctionsRouter(config.ContractAddress, client) if err != nil { return nil, fmt.Errorf("unexpected error during functions_router.NewFunctionsRouter: %s", err) } allowlist := &onchainAllowlist{ config: config, + orm: orm, client: client, contractV1: contractV1, blockConfirmations: big.NewInt(int64(config.BlockConfirmations)), @@ -93,6 +127,8 @@ func (a *onchainAllowlist) Start(ctx context.Context) error { return nil } + a.loadStoredAllowedSenderList() + updateOnce := func() { timeoutCtx, cancel := utils.ContextFromChanWithTimeout(a.stopCh, time.Duration(a.config.UpdateTimeoutSec)*time.Second) if err := a.UpdateFromContract(timeoutCtx); err != nil { @@ -172,17 +208,113 @@ func (a *onchainAllowlist) updateFromContractV1(ctx context.Context, blockNum *b if err != nil { return errors.Wrap(err, "unexpected error during functions_allow_list.NewTermsOfServiceAllowList") } - addrList, err := tosContract.GetAllAllowedSenders(&bind.CallOpts{ + + var allowedSenderList []common.Address + if !a.config.StoreAllowedSendersEnabled { + allowedSenderList, err = tosContract.GetAllAllowedSenders(&bind.CallOpts{ + Pending: false, + BlockNumber: blockNum, + Context: ctx, + }) + if err != nil { + return errors.Wrap(err, "error calling GetAllAllowedSenders") + } + } else { + err = a.syncBlockedSenders(ctx, tosContract, blockNum) + if err != nil { + return errors.Wrap(err, "failed to sync the stored allowed and blocked senders") + } + + allowedSenderList, err = a.getAllowedSendersBatched(ctx, tosContract, blockNum) + if err != nil { + return errors.Wrap(err, "failed to get allowed senders in rage") + } + } + + a.update(allowedSenderList) + return nil +} + +func (a *onchainAllowlist) getAllowedSendersBatched(ctx context.Context, tosContract *functions_allow_list.TermsOfServiceAllowList, blockNum *big.Int) ([]common.Address, error) { + allowedSenderList := make([]common.Address, 0) + count, err := tosContract.GetAllowedSendersCount(&bind.CallOpts{ Pending: false, BlockNumber: blockNum, Context: ctx, }) if err != nil { - return errors.Wrap(err, "error calling GetAllAllowedSenders") + return nil, errors.Wrap(err, "unexpected error during functions_allow_list.GetAllowedSendersCount") } - a.update(addrList) + + throttleTicker := time.NewTicker(time.Duration(a.config.FetchingDelayInRangeSec) * time.Second) + for idxStart := uint64(0); idxStart < count; idxStart += uint64(a.config.OnchainAllowlistBatchSize) { + <-throttleTicker.C + + idxEnd := idxStart + uint64(a.config.OnchainAllowlistBatchSize) + if idxEnd >= count { + idxEnd = count - 1 + } + + allowedSendersBatch, err := tosContract.GetAllowedSendersInRange(&bind.CallOpts{ + Pending: false, + BlockNumber: blockNum, + Context: ctx, + }, idxStart, idxEnd) + if err != nil { + return nil, errors.Wrap(err, "error calling GetAllowedSendersInRange") + } + + allowedSenderList = append(allowedSenderList, allowedSendersBatch...) + err = a.orm.CreateAllowedSenders(allowedSendersBatch) + if err != nil { + a.lggr.Errorf("failed to update stored allowedSenderList: %w", err) + } + } + throttleTicker.Stop() + + return allowedSenderList, nil +} + +// syncBlockedSenders fetches the list of blocked addresses from the contract in batches +// and removes the addresses from the functions_allowlist table if present +func (a *onchainAllowlist) syncBlockedSenders(ctx context.Context, tosContract *functions_allow_list.TermsOfServiceAllowList, blockNum *big.Int) error { + count, err := tosContract.GetBlockedSendersCount(&bind.CallOpts{ + Pending: false, + BlockNumber: blockNum, + Context: ctx, + }) + if err != nil { + return errors.Wrap(err, "unexpected error during functions_allow_list.GetBlockedSendersCount") + } + + throttleTicker := time.NewTicker(time.Duration(a.config.FetchingDelayInRangeSec) * time.Second) + for idxStart := uint64(0); idxStart < count; idxStart += uint64(a.config.OnchainAllowlistBatchSize) { + <-throttleTicker.C + + idxEnd := idxStart + uint64(a.config.OnchainAllowlistBatchSize) + if idxEnd >= count { + idxEnd = count - 1 + } + + blockedSendersBatch, err := tosContract.GetBlockedSendersInRange(&bind.CallOpts{ + Pending: false, + BlockNumber: blockNum, + Context: ctx, + }, idxStart, idxEnd) + if err != nil { + return errors.Wrap(err, "error calling GetAllowedSendersInRange") + } + + err = a.orm.DeleteAllowedSenders(blockedSendersBatch) + if err != nil { + a.lggr.Errorf("failed to delete blocked address from allowed list in storage: %w", err) + } + } + throttleTicker.Stop() + return nil } + func (a *onchainAllowlist) update(addrList []common.Address) { newAllowlist := make(map[common.Address]struct{}) for _, addr := range addrList { @@ -191,3 +323,24 @@ func (a *onchainAllowlist) update(addrList []common.Address) { a.allowlist.Store(&newAllowlist) a.lggr.Infow("allowlist updated successfully", "len", len(addrList)) } + +func (a *onchainAllowlist) loadStoredAllowedSenderList() { + allowedList := make([]common.Address, 0) + offset := uint(0) + for { + asBatch, err := a.orm.GetAllowedSenders(offset, a.config.StoredAllowlistBatchSize) + if err != nil { + a.lggr.Errorf("failed to get stored allowed senders: %w", err) + break + } + + allowedList = append(allowedList, asBatch...) + + if len(asBatch) < int(a.config.StoredAllowlistBatchSize) { + break + } + offset += a.config.StoredAllowlistBatchSize + } + + a.update(allowedList) +} diff --git a/core/services/gateway/handlers/functions/allowlist/allowlist_test.go b/core/services/gateway/handlers/functions/allowlist/allowlist_test.go new file mode 100644 index 00000000000..e8cbca80b94 --- /dev/null +++ b/core/services/gateway/handlers/functions/allowlist/allowlist_test.go @@ -0,0 +1,184 @@ +package allowlist_test + +import ( + "context" + "encoding/hex" + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" + amocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist/mocks" +) + +const ( + addr1 = "9ed925d8206a4f88a2f643b28b3035b315753cd6" + addr2 = "ea6721ac65bced841b8ec3fc5fedea6141a0ade4" + addr3 = "84689acc87ff22841b8ec378300da5e141a99911" +) + +func sampleEncodedAllowlist(t *testing.T) []byte { + abiEncodedAddresses := + "0000000000000000000000000000000000000000000000000000000000000020" + + "0000000000000000000000000000000000000000000000000000000000000002" + + "000000000000000000000000" + addr1 + + "000000000000000000000000" + addr2 + rawData, err := hex.DecodeString(abiEncodedAddresses) + require.NoError(t, err) + return rawData +} + +func TestAllowlist_UpdateAndCheck(t *testing.T) { + t.Parallel() + + client := mocks.NewClient(t) + client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) + client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(sampleEncodedAllowlist(t), nil) + config := allowlist.OnchainAllowlistConfig{ + ContractVersion: 1, + ContractAddress: common.Address{}, + BlockConfirmations: 1, + } + + orm := amocks.NewORM(t) + allowlist, err := allowlist.NewOnchainAllowlist(client, config, orm, logger.TestLogger(t)) + require.NoError(t, err) + + err = allowlist.Start(testutils.Context(t)) + require.NoError(t, err) + t.Cleanup(func() { + assert.NoError(t, allowlist.Close()) + }) + + require.NoError(t, allowlist.UpdateFromContract(testutils.Context(t))) + require.False(t, allowlist.Allow(common.Address{})) + require.True(t, allowlist.Allow(common.HexToAddress(addr1))) + require.True(t, allowlist.Allow(common.HexToAddress(addr2))) + require.False(t, allowlist.Allow(common.HexToAddress(addr3))) +} + +func TestAllowlist_UnsupportedVersion(t *testing.T) { + t.Parallel() + + client := mocks.NewClient(t) + config := allowlist.OnchainAllowlistConfig{ + ContractVersion: 0, + ContractAddress: common.Address{}, + BlockConfirmations: 1, + } + + orm := amocks.NewORM(t) + _, err := allowlist.NewOnchainAllowlist(client, config, orm, logger.TestLogger(t)) + require.Error(t, err) +} + +func TestAllowlist_UpdatePeriodically(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithCancel(testutils.Context(t)) + client := mocks.NewClient(t) + client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) + client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + cancel() + }).Return(sampleEncodedAllowlist(t), nil) + config := allowlist.OnchainAllowlistConfig{ + ContractAddress: common.Address{}, + ContractVersion: 1, + BlockConfirmations: 1, + UpdateFrequencySec: 2, + UpdateTimeoutSec: 1, + } + + orm := amocks.NewORM(t) + orm.On("GetAllowedSenders", uint(0), uint(1000)).Return([]common.Address{}, nil) + + allowlist, err := allowlist.NewOnchainAllowlist(client, config, orm, logger.TestLogger(t)) + require.NoError(t, err) + + err = allowlist.Start(ctx) + require.NoError(t, err) + t.Cleanup(func() { + assert.NoError(t, allowlist.Close()) + }) + + gomega.NewGomegaWithT(t).Eventually(func() bool { + return allowlist.Allow(common.HexToAddress(addr1)) && !allowlist.Allow(common.HexToAddress(addr3)) + }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) +} +func TestAllowlist_UpdateFromContract(t *testing.T) { + t.Parallel() + + t.Run("OK-iterate_over_list_of_allowed_senders", func(t *testing.T) { + ctx, cancel := context.WithCancel(testutils.Context(t)) + client := mocks.NewClient(t) + client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) + client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + cancel() + }).Return(sampleEncodedAllowlist(t), nil) + config := allowlist.OnchainAllowlistConfig{ + ContractAddress: common.HexToAddress(addr3), + ContractVersion: 1, + BlockConfirmations: 1, + UpdateFrequencySec: 2, + UpdateTimeoutSec: 1, + StoredAllowlistBatchSize: 2, + OnchainAllowlistBatchSize: 16, + StoreAllowedSendersEnabled: true, + FetchingDelayInRangeSec: 0, + } + + orm := amocks.NewORM(t) + orm.On("DeleteAllowedSenders", []common.Address{common.HexToAddress(addr1), common.HexToAddress(addr2)}).Times(2).Return(nil) + orm.On("CreateAllowedSenders", []common.Address{common.HexToAddress(addr1), common.HexToAddress(addr2)}).Times(2).Return(nil) + + allowlist, err := allowlist.NewOnchainAllowlist(client, config, orm, logger.TestLogger(t)) + require.NoError(t, err) + + err = allowlist.UpdateFromContract(ctx) + require.NoError(t, err) + + gomega.NewGomegaWithT(t).Eventually(func() bool { + return allowlist.Allow(common.HexToAddress(addr1)) && !allowlist.Allow(common.HexToAddress(addr3)) + }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) + }) + + t.Run("OK-fetch_complete_list_of_allowed_senders_without_storing", func(t *testing.T) { + ctx, cancel := context.WithCancel(testutils.Context(t)) + client := mocks.NewClient(t) + client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) + client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + cancel() + }).Return(sampleEncodedAllowlist(t), nil) + config := allowlist.OnchainAllowlistConfig{ + ContractAddress: common.HexToAddress(addr3), + ContractVersion: 1, + BlockConfirmations: 1, + UpdateFrequencySec: 2, + UpdateTimeoutSec: 1, + StoredAllowlistBatchSize: 2, + OnchainAllowlistBatchSize: 16, + StoreAllowedSendersEnabled: false, + FetchingDelayInRangeSec: 0, + } + + orm := amocks.NewORM(t) + allowlist, err := allowlist.NewOnchainAllowlist(client, config, orm, logger.TestLogger(t)) + require.NoError(t, err) + + err = allowlist.UpdateFromContract(ctx) + require.NoError(t, err) + + gomega.NewGomegaWithT(t).Eventually(func() bool { + return allowlist.Allow(common.HexToAddress(addr1)) && !allowlist.Allow(common.HexToAddress(addr3)) + }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) + }) +} diff --git a/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go b/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go similarity index 83% rename from core/services/gateway/handlers/functions/mocks/onchain_allowlist.go rename to core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go index 8cbf301f0ea..6668a3c76ff 100644 --- a/core/services/gateway/handlers/functions/mocks/onchain_allowlist.go +++ b/core/services/gateway/handlers/functions/allowlist/mocks/onchain_allowlist.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type OnchainAllowlist struct { func (_m *OnchainAllowlist) Allow(_a0 common.Address) bool { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Allow") + } + var r0 bool if rf, ok := ret.Get(0).(func(common.Address) bool); ok { r0 = rf(_a0) @@ -33,6 +37,10 @@ func (_m *OnchainAllowlist) Allow(_a0 common.Address) bool { func (_m *OnchainAllowlist) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -47,6 +55,10 @@ func (_m *OnchainAllowlist) Close() error { func (_m *OnchainAllowlist) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -61,6 +73,10 @@ func (_m *OnchainAllowlist) Start(_a0 context.Context) error { func (_m *OnchainAllowlist) UpdateFromContract(ctx context.Context) error { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for UpdateFromContract") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) diff --git a/core/services/gateway/handlers/functions/allowlist/mocks/orm.go b/core/services/gateway/handlers/functions/allowlist/mocks/orm.go new file mode 100644 index 00000000000..c2ba27c3a24 --- /dev/null +++ b/core/services/gateway/handlers/functions/allowlist/mocks/orm.go @@ -0,0 +1,116 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + +package mocks + +import ( + common "github.com/ethereum/go-ethereum/common" + mock "github.com/stretchr/testify/mock" + + pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" +) + +// ORM is an autogenerated mock type for the ORM type +type ORM struct { + mock.Mock +} + +// CreateAllowedSenders provides a mock function with given fields: allowedSenders, qopts +func (_m *ORM) CreateAllowedSenders(allowedSenders []common.Address, qopts ...pg.QOpt) error { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, allowedSenders) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateAllowedSenders") + } + + var r0 error + if rf, ok := ret.Get(0).(func([]common.Address, ...pg.QOpt) error); ok { + r0 = rf(allowedSenders, qopts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteAllowedSenders provides a mock function with given fields: blockedSenders, qopts +func (_m *ORM) DeleteAllowedSenders(blockedSenders []common.Address, qopts ...pg.QOpt) error { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, blockedSenders) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DeleteAllowedSenders") + } + + var r0 error + if rf, ok := ret.Get(0).(func([]common.Address, ...pg.QOpt) error); ok { + r0 = rf(blockedSenders, qopts...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// GetAllowedSenders provides a mock function with given fields: offset, limit, qopts +func (_m *ORM) GetAllowedSenders(offset uint, limit uint, qopts ...pg.QOpt) ([]common.Address, error) { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, offset, limit) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetAllowedSenders") + } + + var r0 []common.Address + var r1 error + if rf, ok := ret.Get(0).(func(uint, uint, ...pg.QOpt) ([]common.Address, error)); ok { + return rf(offset, limit, qopts...) + } + if rf, ok := ret.Get(0).(func(uint, uint, ...pg.QOpt) []common.Address); ok { + r0 = rf(offset, limit, qopts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]common.Address) + } + } + + if rf, ok := ret.Get(1).(func(uint, uint, ...pg.QOpt) error); ok { + r1 = rf(offset, limit, qopts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// 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 { + mock.TestingT + Cleanup(func()) +}) *ORM { + mock := &ORM{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/services/gateway/handlers/functions/allowlist/orm.go b/core/services/gateway/handlers/functions/allowlist/orm.go new file mode 100644 index 00000000000..07ee1ea3b3b --- /dev/null +++ b/core/services/gateway/handlers/functions/allowlist/orm.go @@ -0,0 +1,123 @@ +package allowlist + +import ( + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + + "github.com/jmoiron/sqlx" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" +) + +//go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore +type ORM interface { + GetAllowedSenders(offset, limit uint, qopts ...pg.QOpt) ([]common.Address, error) + CreateAllowedSenders(allowedSenders []common.Address, qopts ...pg.QOpt) error + DeleteAllowedSenders(blockedSenders []common.Address, qopts ...pg.QOpt) error +} + +type orm struct { + q pg.Q + lggr logger.Logger + routerContractAddress common.Address +} + +var _ ORM = (*orm)(nil) +var ( + ErrInvalidParameters = errors.New("invalid parameters provided to create a functions contract cache ORM") +) + +const ( + tableName = "functions_allowlist" +) + +func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, routerContractAddress common.Address) (ORM, error) { + if db == nil || cfg == nil || lggr == nil || routerContractAddress == (common.Address{}) { + return nil, ErrInvalidParameters + } + + return &orm{ + q: pg.NewQ(db, lggr, cfg), + lggr: lggr, + routerContractAddress: routerContractAddress, + }, nil +} + +func (o *orm) GetAllowedSenders(offset, limit uint, qopts ...pg.QOpt) ([]common.Address, error) { + var addresses []common.Address + stmt := fmt.Sprintf(` + SELECT allowed_address + FROM %s + WHERE router_contract_address = $1 + ORDER BY id ASC + OFFSET $2 + LIMIT $3; + `, tableName) + err := o.q.WithOpts(qopts...).Select(&addresses, stmt, o.routerContractAddress, offset, limit) + if err != nil { + return addresses, err + } + o.lggr.Debugf("Successfully fetched allowed sender list from DB. offset: %d, limit: %d, length: %d", offset, limit, len(addresses)) + + return addresses, nil +} + +func (o *orm) CreateAllowedSenders(allowedSenders []common.Address, qopts ...pg.QOpt) error { + var valuesPlaceholder []string + for i := 1; i <= len(allowedSenders)*2; i += 2 { + valuesPlaceholder = append(valuesPlaceholder, fmt.Sprintf("($%d, $%d)", i, i+1)) + } + + stmt := fmt.Sprintf(` + INSERT INTO %s (allowed_address, router_contract_address) + VALUES %s ON CONFLICT (allowed_address, router_contract_address) DO NOTHING;`, tableName, strings.Join(valuesPlaceholder, ", ")) + + var args []interface{} + for _, as := range allowedSenders { + args = append(args, as, o.routerContractAddress) + } + + _, err := o.q.WithOpts(qopts...).Exec(stmt, args...) + if err != nil { + return err + } + + o.lggr.Debugf("Successfully stored allowed senders: %v for routerContractAddress: %s", allowedSenders, o.routerContractAddress) + + return nil +} + +func (o *orm) DeleteAllowedSenders(blockedSenders []common.Address, qopts ...pg.QOpt) error { + var valuesPlaceholder []string + for i := 1; i <= len(blockedSenders); i++ { + valuesPlaceholder = append(valuesPlaceholder, fmt.Sprintf("$%d", i+1)) + } + + stmt := fmt.Sprintf(` + DELETE FROM %s + WHERE router_contract_address = $1 + AND allowed_address IN (%s);`, tableName, strings.Join(valuesPlaceholder, ", ")) + + args := []interface{}{o.routerContractAddress} + for _, bs := range blockedSenders { + args = append(args, bs) + } + + res, err := o.q.WithOpts(qopts...).Exec(stmt, args...) + if err != nil { + return err + } + + rowsAffected, err := res.RowsAffected() + if err != nil { + return err + } + + o.lggr.Debugf("Successfully removed blocked senders from the allowed list: %v for routerContractAddress: %s. rowsAffected: %d", blockedSenders, o.routerContractAddress, rowsAffected) + + return nil +} diff --git a/core/services/gateway/handlers/functions/allowlist/orm_test.go b/core/services/gateway/handlers/functions/allowlist/orm_test.go new file mode 100644 index 00000000000..0f63e83cd5f --- /dev/null +++ b/core/services/gateway/handlers/functions/allowlist/orm_test.go @@ -0,0 +1,190 @@ +package allowlist_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + "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/gateway/handlers/functions/allowlist" +) + +func setupORM(t *testing.T) (allowlist.ORM, error) { + t.Helper() + + var ( + db = pgtest.NewSqlxDB(t) + lggr = logger.TestLogger(t) + ) + + return allowlist.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) +} + +func seedAllowedSenders(t *testing.T, orm allowlist.ORM, amount int) []common.Address { + storedAllowedSenders := make([]common.Address, amount) + for i := 0; i < amount; i++ { + address := testutils.NewAddress() + storedAllowedSenders[i] = address + } + + err := orm.CreateAllowedSenders(storedAllowedSenders) + require.NoError(t, err) + + return storedAllowedSenders +} +func TestORM_GetAllowedSenders(t *testing.T) { + t.Parallel() + t.Run("fetch first page", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + storedAllowedSenders := seedAllowedSenders(t, orm, 2) + results, err := orm.GetAllowedSenders(0, 1) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, storedAllowedSenders[0], results[0]) + }) + + t.Run("fetch second page", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + storedAllowedSenders := seedAllowedSenders(t, orm, 2) + results, err := orm.GetAllowedSenders(1, 5) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, storedAllowedSenders[1], results[0]) + }) +} + +func TestORM_CreateAllowedSenders(t *testing.T) { + t.Parallel() + + t.Run("OK-create_an_allowed_sender", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + expected := testutils.NewAddress() + err = orm.CreateAllowedSenders([]common.Address{expected}) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 1) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, expected, results[0]) + }) + + t.Run("OK-create_an_existing_allowed_sender", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + expected := testutils.NewAddress() + err = orm.CreateAllowedSenders([]common.Address{expected}) + require.NoError(t, err) + + err = orm.CreateAllowedSenders([]common.Address{expected}) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 5) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, expected, results[0]) + }) + + t.Run("OK-create_multiple_allowed_senders_in_one_query", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + expected := []common.Address{testutils.NewAddress(), testutils.NewAddress()} + err = orm.CreateAllowedSenders(expected) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 2) + require.NoError(t, err) + require.Equal(t, 2, len(results), "incorrect results length") + require.Equal(t, expected[0], results[0]) + require.Equal(t, expected[1], results[1]) + }) + + t.Run("OK-create_multiple_allowed_senders_with_duplicates", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + addr1 := testutils.NewAddress() + addr2 := testutils.NewAddress() + expected := []common.Address{addr1, addr2} + + duplicatedAddressInput := []common.Address{addr1, addr1, addr1, addr2} + err = orm.CreateAllowedSenders(duplicatedAddressInput) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 10) + require.NoError(t, err) + require.Equal(t, 2, len(results), "incorrect results length") + require.Equal(t, expected[0], results[0]) + require.Equal(t, expected[1], results[1]) + }) +} + +func TestORM_DeleteAllowedSenders(t *testing.T) { + t.Parallel() + + t.Run("OK-delete_blocked_sender_from_allowed_list", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + add1 := testutils.NewAddress() + add2 := testutils.NewAddress() + add3 := testutils.NewAddress() + err = orm.CreateAllowedSenders([]common.Address{add1, add2, add3}) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 10) + require.NoError(t, err) + require.Equal(t, 3, len(results), "incorrect results length") + require.Equal(t, add1, results[0]) + + err = orm.DeleteAllowedSenders([]common.Address{add1, add3}) + require.NoError(t, err) + + results, err = orm.GetAllowedSenders(0, 10) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, add2, results[0]) + }) + + t.Run("OK-delete_non_existing_blocked_sender_from_allowed_list", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + add1 := testutils.NewAddress() + add2 := testutils.NewAddress() + err = orm.CreateAllowedSenders([]common.Address{add1, add2}) + require.NoError(t, err) + + results, err := orm.GetAllowedSenders(0, 10) + require.NoError(t, err) + require.Equal(t, 2, len(results), "incorrect results length") + require.Equal(t, add1, results[0]) + + add3 := testutils.NewAddress() + err = orm.DeleteAllowedSenders([]common.Address{add3}) + require.NoError(t, err) + + results, err = orm.GetAllowedSenders(0, 10) + require.NoError(t, err) + require.Equal(t, 2, len(results), "incorrect results length") + require.Equal(t, add1, results[0]) + require.Equal(t, add2, results[1]) + }) +} + +func Test_NewORM(t *testing.T) { + t.Run("OK-create_ORM", func(t *testing.T) { + _, err := allowlist.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), testutils.NewAddress()) + require.NoError(t, err) + }) + t.Run("NOK-create_ORM_with_nil_fields", func(t *testing.T) { + _, err := allowlist.NewORM(nil, nil, nil, common.Address{}) + require.Error(t, err) + }) + t.Run("NOK-create_ORM_with_empty_address", func(t *testing.T) { + _, err := allowlist.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), common.Address{}) + require.Error(t, err) + }) +} diff --git a/core/services/gateway/handlers/functions/allowlist_test.go b/core/services/gateway/handlers/functions/allowlist_test.go deleted file mode 100644 index fdaea81b2c0..00000000000 --- a/core/services/gateway/handlers/functions/allowlist_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package functions_test - -import ( - "context" - "encoding/hex" - "math/big" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/onsi/gomega" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" -) - -const ( - addr1 = "9ed925d8206a4f88a2f643b28b3035b315753cd6" - addr2 = "ea6721ac65bced841b8ec3fc5fedea6141a0ade4" - addr3 = "84689acc87ff22841b8ec378300da5e141a99911" -) - -func sampleEncodedAllowlist(t *testing.T) []byte { - abiEncodedAddresses := - "0000000000000000000000000000000000000000000000000000000000000020" + - "0000000000000000000000000000000000000000000000000000000000000002" + - "000000000000000000000000" + addr1 + - "000000000000000000000000" + addr2 - rawData, err := hex.DecodeString(abiEncodedAddresses) - require.NoError(t, err) - return rawData -} - -func TestAllowlist_UpdateAndCheck(t *testing.T) { - t.Parallel() - - client := mocks.NewClient(t) - client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) - client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(sampleEncodedAllowlist(t), nil) - config := functions.OnchainAllowlistConfig{ - ContractVersion: 1, - ContractAddress: common.Address{}, - BlockConfirmations: 1, - } - allowlist, err := functions.NewOnchainAllowlist(client, config, logger.TestLogger(t)) - require.NoError(t, err) - - err = allowlist.Start(testutils.Context(t)) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, allowlist.Close()) - }) - - require.NoError(t, allowlist.UpdateFromContract(testutils.Context(t))) - require.False(t, allowlist.Allow(common.Address{})) - require.True(t, allowlist.Allow(common.HexToAddress(addr1))) - require.True(t, allowlist.Allow(common.HexToAddress(addr2))) - require.False(t, allowlist.Allow(common.HexToAddress(addr3))) -} - -func TestAllowlist_UnsupportedVersion(t *testing.T) { - t.Parallel() - - client := mocks.NewClient(t) - config := functions.OnchainAllowlistConfig{ - ContractVersion: 0, - ContractAddress: common.Address{}, - BlockConfirmations: 1, - } - _, err := functions.NewOnchainAllowlist(client, config, logger.TestLogger(t)) - require.Error(t, err) -} - -func TestAllowlist_UpdatePeriodically(t *testing.T) { - t.Parallel() - - ctx, cancel := context.WithCancel(testutils.Context(t)) - client := mocks.NewClient(t) - client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) - client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - cancel() - }).Return(sampleEncodedAllowlist(t), nil) - config := functions.OnchainAllowlistConfig{ - ContractAddress: common.Address{}, - ContractVersion: 1, - BlockConfirmations: 1, - UpdateFrequencySec: 1, - UpdateTimeoutSec: 1, - } - allowlist, err := functions.NewOnchainAllowlist(client, config, logger.TestLogger(t)) - require.NoError(t, err) - - err = allowlist.Start(ctx) - require.NoError(t, err) - t.Cleanup(func() { - assert.NoError(t, allowlist.Close()) - }) - - gomega.NewGomegaWithT(t).Eventually(func() bool { - return allowlist.Allow(common.HexToAddress(addr1)) && !allowlist.Allow(common.HexToAddress(addr3)) - }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) -} diff --git a/core/services/gateway/handlers/functions/handler.functions.go b/core/services/gateway/handlers/functions/handler.functions.go index 5277f9789d6..ff272e4e577 100644 --- a/core/services/gateway/handlers/functions/handler.functions.go +++ b/core/services/gateway/handlers/functions/handler.functions.go @@ -10,6 +10,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/jmoiron/sqlx" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.uber.org/multierr" @@ -22,6 +23,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/gateway/config" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" + fallow "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" + fsub "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) var ( @@ -58,10 +62,10 @@ var ( type FunctionsHandlerConfig struct { ChainID string `json:"chainId"` // Not specifying OnchainAllowlist config disables allowlist checks - OnchainAllowlist *OnchainAllowlistConfig `json:"onchainAllowlist"` + OnchainAllowlist *fallow.OnchainAllowlistConfig `json:"onchainAllowlist"` // Not specifying OnchainSubscriptions config disables minimum balance checks - OnchainSubscriptions *OnchainSubscriptionsConfig `json:"onchainSubscriptions"` - MinimumSubscriptionBalance *assets.Link `json:"minimumSubscriptionBalance"` + OnchainSubscriptions *fsub.OnchainSubscriptionsConfig `json:"onchainSubscriptions"` + MinimumSubscriptionBalance *assets.Link `json:"minimumSubscriptionBalance"` // Not specifying RateLimiter config disables rate limiting UserRateLimiter *hc.RateLimiterConfig `json:"userRateLimiter"` NodeRateLimiter *hc.RateLimiterConfig `json:"nodeRateLimiter"` @@ -77,8 +81,8 @@ type functionsHandler struct { donConfig *config.DONConfig don handlers.DON pendingRequests hc.RequestCache[PendingRequest] - allowlist OnchainAllowlist - subscriptions OnchainSubscriptions + allowlist fallow.OnchainAllowlist + subscriptions fsub.OnchainSubscriptions minimumBalance *assets.Link userRateLimiter *hc.RateLimiter nodeRateLimiter *hc.RateLimiter @@ -96,20 +100,25 @@ type PendingRequest struct { var _ handlers.Handler = (*functionsHandler)(nil) -func NewFunctionsHandlerFromConfig(handlerConfig json.RawMessage, donConfig *config.DONConfig, don handlers.DON, legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger) (handlers.Handler, error) { +func NewFunctionsHandlerFromConfig(handlerConfig json.RawMessage, donConfig *config.DONConfig, don handlers.DON, legacyChains legacyevm.LegacyChainContainer, db *sqlx.DB, qcfg pg.QConfig, lggr logger.Logger) (handlers.Handler, error) { var cfg FunctionsHandlerConfig err := json.Unmarshal(handlerConfig, &cfg) if err != nil { return nil, err } lggr = lggr.Named("FunctionsHandler:" + donConfig.DonId) - var allowlist OnchainAllowlist + var allowlist fallow.OnchainAllowlist if cfg.OnchainAllowlist != nil { chain, err2 := legacyChains.Get(cfg.ChainID) if err2 != nil { return nil, err2 } - allowlist, err2 = NewOnchainAllowlist(chain.Client(), *cfg.OnchainAllowlist, lggr) + + orm, err2 := fallow.NewORM(db, lggr, qcfg, cfg.OnchainAllowlist.ContractAddress) + if err2 != nil { + return nil, err2 + } + allowlist, err2 = fallow.NewOnchainAllowlist(chain.Client(), *cfg.OnchainAllowlist, orm, lggr) if err2 != nil { return nil, err2 } @@ -127,13 +136,19 @@ func NewFunctionsHandlerFromConfig(handlerConfig json.RawMessage, donConfig *con return nil, err } } - var subscriptions OnchainSubscriptions + var subscriptions fsub.OnchainSubscriptions if cfg.OnchainSubscriptions != nil { chain, err2 := legacyChains.Get(cfg.ChainID) if err2 != nil { return nil, err2 } - subscriptions, err2 = NewOnchainSubscriptions(chain.Client(), *cfg.OnchainSubscriptions, lggr) + + orm, err2 := fsub.NewORM(db, lggr, qcfg, cfg.OnchainSubscriptions.ContractAddress) + if err2 != nil { + return nil, err2 + } + + subscriptions, err2 = fsub.NewOnchainSubscriptions(chain.Client(), *cfg.OnchainSubscriptions, orm, lggr) if err2 != nil { return nil, err2 } @@ -151,8 +166,8 @@ func NewFunctionsHandler( donConfig *config.DONConfig, don handlers.DON, pendingRequestsCache hc.RequestCache[PendingRequest], - allowlist OnchainAllowlist, - subscriptions OnchainSubscriptions, + allowlist fallow.OnchainAllowlist, + subscriptions fsub.OnchainSubscriptions, minimumBalance *assets.Link, userRateLimiter *hc.RateLimiter, nodeRateLimiter *hc.RateLimiter, diff --git a/core/services/gateway/handlers/functions/handler.functions_test.go b/core/services/gateway/handlers/functions/handler.functions_test.go index f36b64709a2..2e2c1c77caf 100644 --- a/core/services/gateway/handlers/functions/handler.functions_test.go +++ b/core/services/gateway/handlers/functions/handler.functions_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" @@ -21,11 +22,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" - functions_mocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/mocks" + allowlist_mocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist/mocks" + subscriptions_mocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions/mocks" handlers_mocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/mocks" ) -func newFunctionsHandlerForATestDON(t *testing.T, nodes []gc.TestNode, requestTimeout time.Duration, heartbeatSender string) (handlers.Handler, *handlers_mocks.DON, *functions_mocks.OnchainAllowlist, *functions_mocks.OnchainSubscriptions) { +func newFunctionsHandlerForATestDON(t *testing.T, nodes []gc.TestNode, requestTimeout time.Duration, heartbeatSender string) (handlers.Handler, *handlers_mocks.DON, *allowlist_mocks.OnchainAllowlist, *subscriptions_mocks.OnchainSubscriptions) { cfg := functions.FunctionsHandlerConfig{} donConfig := &config.DONConfig{ Members: []config.NodeConfig{}, @@ -40,8 +42,8 @@ func newFunctionsHandlerForATestDON(t *testing.T, nodes []gc.TestNode, requestTi } don := handlers_mocks.NewDON(t) - allowlist := functions_mocks.NewOnchainAllowlist(t) - subscriptions := functions_mocks.NewOnchainSubscriptions(t) + allowlist := allowlist_mocks.NewOnchainAllowlist(t) + subscriptions := subscriptions_mocks.NewOnchainSubscriptions(t) minBalance := assets.NewLinkFromJuels(100) userRateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) require.NoError(t, err) @@ -82,7 +84,7 @@ func sendNodeReponses(t *testing.T, handler handlers.Handler, userRequestMsg api func TestFunctionsHandler_Minimal(t *testing.T) { t.Parallel() - handler, err := functions.NewFunctionsHandlerFromConfig(json.RawMessage("{}"), &config.DONConfig{}, nil, nil, logger.TestLogger(t)) + handler, err := functions.NewFunctionsHandlerFromConfig(json.RawMessage("{}"), &config.DONConfig{}, nil, nil, nil, nil, logger.TestLogger(t)) require.NoError(t, err) // empty message should always error out @@ -94,11 +96,10 @@ func TestFunctionsHandler_Minimal(t *testing.T) { func TestFunctionsHandler_CleanStartAndClose(t *testing.T) { t.Parallel() - handler, err := functions.NewFunctionsHandlerFromConfig(json.RawMessage("{}"), &config.DONConfig{}, nil, nil, logger.TestLogger(t)) + handler, err := functions.NewFunctionsHandlerFromConfig(json.RawMessage("{}"), &config.DONConfig{}, nil, nil, nil, nil, logger.TestLogger(t)) require.NoError(t, err) - require.NoError(t, handler.Start(testutils.Context(t))) - require.NoError(t, handler.Close()) + servicetest.Run(t, handler) } func TestFunctionsHandler_HandleUserMessage_SecretsSet(t *testing.T) { diff --git a/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go b/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go similarity index 87% rename from core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go rename to core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go index 64e2960f949..5f2054c4e47 100644 --- a/core/services/gateway/handlers/functions/mocks/onchain_subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions/mocks/onchain_subscriptions.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type OnchainSubscriptions struct { func (_m *OnchainSubscriptions) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *OnchainSubscriptions) Close() error { func (_m *OnchainSubscriptions) GetMaxUserBalance(_a0 common.Address) (*big.Int, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetMaxUserBalance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(common.Address) (*big.Int, error)); ok { @@ -60,6 +68,10 @@ func (_m *OnchainSubscriptions) GetMaxUserBalance(_a0 common.Address) (*big.Int, func (_m *OnchainSubscriptions) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go b/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go new file mode 100644 index 00000000000..0f278aa49b0 --- /dev/null +++ b/core/services/gateway/handlers/functions/subscriptions/mocks/orm.go @@ -0,0 +1,90 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + +package mocks + +import ( + subscriptions "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" + pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" + mock "github.com/stretchr/testify/mock" +) + +// ORM is an autogenerated mock type for the ORM type +type ORM struct { + mock.Mock +} + +// GetSubscriptions provides a mock function with given fields: offset, limit, qopts +func (_m *ORM) GetSubscriptions(offset uint, limit uint, qopts ...pg.QOpt) ([]subscriptions.StoredSubscription, error) { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, offset, limit) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetSubscriptions") + } + + var r0 []subscriptions.StoredSubscription + var r1 error + if rf, ok := ret.Get(0).(func(uint, uint, ...pg.QOpt) ([]subscriptions.StoredSubscription, error)); ok { + return rf(offset, limit, qopts...) + } + if rf, ok := ret.Get(0).(func(uint, uint, ...pg.QOpt) []subscriptions.StoredSubscription); ok { + r0 = rf(offset, limit, qopts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]subscriptions.StoredSubscription) + } + } + + if rf, ok := ret.Get(1).(func(uint, uint, ...pg.QOpt) error); ok { + r1 = rf(offset, limit, qopts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UpsertSubscription provides a mock function with given fields: subscription, qopts +func (_m *ORM) UpsertSubscription(subscription subscriptions.StoredSubscription, qopts ...pg.QOpt) error { + _va := make([]interface{}, len(qopts)) + for _i := range qopts { + _va[_i] = qopts[_i] + } + var _ca []interface{} + _ca = append(_ca, subscription) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for UpsertSubscription") + } + + var r0 error + if rf, ok := ret.Get(0).(func(subscriptions.StoredSubscription, ...pg.QOpt) error); ok { + r0 = rf(subscription, qopts...) + } else { + r0 = ret.Error(0) + } + + 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 { + mock.TestingT + Cleanup(func()) +}) *ORM { + mock := &ORM{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/services/gateway/handlers/functions/subscriptions/orm.go b/core/services/gateway/handlers/functions/subscriptions/orm.go new file mode 100644 index 00000000000..369291ace54 --- /dev/null +++ b/core/services/gateway/handlers/functions/subscriptions/orm.go @@ -0,0 +1,143 @@ +package subscriptions + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/lib/pq" + "github.com/pkg/errors" + + "github.com/jmoiron/sqlx" + + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" +) + +//go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore +type ORM interface { + GetSubscriptions(offset, limit uint, qopts ...pg.QOpt) ([]StoredSubscription, error) + UpsertSubscription(subscription StoredSubscription, qopts ...pg.QOpt) error +} + +type orm struct { + q pg.Q + lggr logger.Logger + routerContractAddress common.Address +} + +var _ ORM = (*orm)(nil) +var ( + ErrInvalidParameters = errors.New("invalid parameters provided to create a subscription contract ORM") +) + +const ( + tableName = "functions_subscriptions" +) + +type storedSubscriptionRow struct { + SubscriptionID uint64 + Owner common.Address + Balance int64 + BlockedBalance int64 + ProposedOwner common.Address + Consumers pq.ByteaArray + Flags []uint8 + RouterContractAddress common.Address +} + +func NewORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, routerContractAddress common.Address) (ORM, error) { + if db == nil || cfg == nil || lggr == nil || routerContractAddress == (common.Address{}) { + return nil, ErrInvalidParameters + } + + return &orm{ + q: pg.NewQ(db, lggr, cfg), + lggr: lggr, + routerContractAddress: routerContractAddress, + }, nil +} + +func (o *orm) GetSubscriptions(offset, limit uint, qopts ...pg.QOpt) ([]StoredSubscription, error) { + var storedSubscriptions []StoredSubscription + var storedSubscriptionRows []storedSubscriptionRow + stmt := fmt.Sprintf(` + SELECT subscription_id, owner, balance, blocked_balance, proposed_owner, consumers, flags, router_contract_address + FROM %s + WHERE router_contract_address = $1 + ORDER BY subscription_id ASC + OFFSET $2 + LIMIT $3; + `, tableName) + err := o.q.WithOpts(qopts...).Select(&storedSubscriptionRows, stmt, o.routerContractAddress, offset, limit) + if err != nil { + return storedSubscriptions, err + } + + for _, cs := range storedSubscriptionRows { + storedSubscriptions = append(storedSubscriptions, cs.encode()) + } + + return storedSubscriptions, nil +} + +// UpsertSubscription will update if a subscription exists or create if it does not. +// In case a subscription gets deleted we will update it with an owner address equal to 0x0. +func (o *orm) UpsertSubscription(subscription StoredSubscription, qopts ...pg.QOpt) error { + stmt := fmt.Sprintf(` + INSERT INTO %s (subscription_id, owner, balance, blocked_balance, proposed_owner, consumers, flags, router_contract_address) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8) ON CONFLICT (subscription_id, router_contract_address) DO UPDATE + SET owner=$2, balance=$3, blocked_balance=$4, proposed_owner=$5, consumers=$6, flags=$7, router_contract_address=$8;`, tableName) + + if subscription.Balance == nil { + subscription.Balance = big.NewInt(0) + } + + if subscription.BlockedBalance == nil { + subscription.BlockedBalance = big.NewInt(0) + } + + var consumers [][]byte + for _, c := range subscription.Consumers { + consumers = append(consumers, c.Bytes()) + } + + _, err := o.q.WithOpts(qopts...).Exec( + stmt, + subscription.SubscriptionID, + subscription.Owner, + subscription.Balance.Int64(), + subscription.BlockedBalance.Int64(), + subscription.ProposedOwner, + consumers, + subscription.Flags[:], + o.routerContractAddress, + ) + if err != nil { + return err + } + + o.lggr.Debugf("Successfully updated subscription: %d for routerContractAddress: %s", subscription.SubscriptionID, o.routerContractAddress) + + return nil +} + +func (cs *storedSubscriptionRow) encode() StoredSubscription { + consumers := make([]common.Address, 0) + for _, csc := range cs.Consumers { + consumers = append(consumers, common.BytesToAddress(csc)) + } + + return StoredSubscription{ + SubscriptionID: cs.SubscriptionID, + IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ + Balance: big.NewInt(cs.Balance), + Owner: cs.Owner, + BlockedBalance: big.NewInt(cs.BlockedBalance), + ProposedOwner: cs.ProposedOwner, + Consumers: consumers, + Flags: [32]byte(cs.Flags), + }, + } +} diff --git a/core/services/gateway/handlers/functions/subscriptions/orm_test.go b/core/services/gateway/handlers/functions/subscriptions/orm_test.go new file mode 100644 index 00000000000..6cb1146f03c --- /dev/null +++ b/core/services/gateway/handlers/functions/subscriptions/orm_test.go @@ -0,0 +1,245 @@ +package subscriptions_test + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" + "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/gateway/handlers/functions/subscriptions" +) + +var ( + defaultFlags = [32]byte{0x1, 0x2, 0x3} +) + +func setupORM(t *testing.T) (subscriptions.ORM, error) { + t.Helper() + + var ( + db = pgtest.NewSqlxDB(t) + lggr = logger.TestLogger(t) + ) + + return subscriptions.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) +} + +func seedSubscriptions(t *testing.T, orm subscriptions.ORM, amount int) []subscriptions.StoredSubscription { + storedSubscriptions := make([]subscriptions.StoredSubscription, 0) + for i := amount; i > 0; i-- { + cs := subscriptions.StoredSubscription{ + SubscriptionID: uint64(i), + IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ + Balance: big.NewInt(10), + Owner: testutils.NewAddress(), + BlockedBalance: big.NewInt(20), + ProposedOwner: common.Address{}, + Consumers: []common.Address{}, + Flags: defaultFlags, + }, + } + storedSubscriptions = append(storedSubscriptions, cs) + err := orm.UpsertSubscription(cs) + require.NoError(t, err) + } + return storedSubscriptions +} + +func TestORM_GetSubscriptions(t *testing.T) { + t.Parallel() + t.Run("fetch first page", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + storedSubscriptions := seedSubscriptions(t, orm, 2) + results, err := orm.GetSubscriptions(0, 1) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, storedSubscriptions[1], results[0]) + }) + + t.Run("fetch second page", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + storedSubscriptions := seedSubscriptions(t, orm, 2) + results, err := orm.GetSubscriptions(1, 5) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, storedSubscriptions[0], results[0]) + }) +} + +func TestORM_UpsertSubscription(t *testing.T) { + t.Parallel() + + t.Run("create a subscription", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + expected := subscriptions.StoredSubscription{ + SubscriptionID: uint64(1), + IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ + Balance: big.NewInt(10), + Owner: testutils.NewAddress(), + BlockedBalance: big.NewInt(20), + ProposedOwner: common.Address{}, + Consumers: []common.Address{testutils.NewAddress()}, + Flags: defaultFlags, + }, + } + err = orm.UpsertSubscription(expected) + require.NoError(t, err) + + results, err := orm.GetSubscriptions(0, 1) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, expected, results[0]) + }) + + t.Run("update a subscription", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + + expectedUpdated := subscriptions.StoredSubscription{ + SubscriptionID: uint64(1), + IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ + Balance: big.NewInt(10), + Owner: testutils.NewAddress(), + BlockedBalance: big.NewInt(20), + ProposedOwner: common.Address{}, + Consumers: []common.Address{}, + Flags: defaultFlags, + }, + } + err = orm.UpsertSubscription(expectedUpdated) + require.NoError(t, err) + + expectedNotUpdated := subscriptions.StoredSubscription{ + SubscriptionID: uint64(2), + IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ + Balance: big.NewInt(10), + Owner: testutils.NewAddress(), + BlockedBalance: big.NewInt(20), + ProposedOwner: common.Address{}, + Consumers: []common.Address{}, + Flags: defaultFlags, + }, + } + err = orm.UpsertSubscription(expectedNotUpdated) + require.NoError(t, err) + + // update the balance value + expectedUpdated.Balance = big.NewInt(20) + err = orm.UpsertSubscription(expectedUpdated) + require.NoError(t, err) + + results, err := orm.GetSubscriptions(0, 5) + require.NoError(t, err) + require.Equal(t, 2, len(results), "incorrect results length") + require.Equal(t, expectedNotUpdated, results[1]) + require.Equal(t, expectedUpdated, results[0]) + }) + + t.Run("update a deleted subscription", func(t *testing.T) { + orm, err := setupORM(t) + require.NoError(t, err) + + subscription := subscriptions.StoredSubscription{ + SubscriptionID: uint64(1), + IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ + Balance: big.NewInt(10), + Owner: testutils.NewAddress(), + BlockedBalance: big.NewInt(20), + ProposedOwner: common.Address{}, + Consumers: []common.Address{}, + Flags: defaultFlags, + }, + } + err = orm.UpsertSubscription(subscription) + require.NoError(t, err) + + // empty subscription + subscription.IFunctionsSubscriptionsSubscription = functions_router.IFunctionsSubscriptionsSubscription{ + Balance: big.NewInt(0), + Owner: common.Address{}, + BlockedBalance: big.NewInt(0), + ProposedOwner: common.Address{}, + Consumers: []common.Address{}, + Flags: [32]byte{}, + } + + err = orm.UpsertSubscription(subscription) + require.NoError(t, err) + + results, err := orm.GetSubscriptions(0, 5) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + require.Equal(t, subscription, results[0]) + }) + + t.Run("create a subscription with same id but different router address", func(t *testing.T) { + var ( + db = pgtest.NewSqlxDB(t) + lggr = logger.TestLogger(t) + ) + + orm1, err := subscriptions.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) + require.NoError(t, err) + orm2, err := subscriptions.NewORM(db, lggr, pgtest.NewQConfig(true), testutils.NewAddress()) + require.NoError(t, err) + + subscription := subscriptions.StoredSubscription{ + SubscriptionID: uint64(1), + IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ + Balance: assets.Ether(10).ToInt(), + Owner: testutils.NewAddress(), + BlockedBalance: assets.Ether(20).ToInt(), + ProposedOwner: common.Address{}, + Consumers: []common.Address{}, + Flags: defaultFlags, + }, + } + + err = orm1.UpsertSubscription(subscription) + require.NoError(t, err) + + // should update the existing subscription + subscription.Balance = assets.Ether(12).ToInt() + err = orm1.UpsertSubscription(subscription) + require.NoError(t, err) + + results, err := orm1.GetSubscriptions(0, 10) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + + // should create a new subscription because it comes from a different router contract + err = orm2.UpsertSubscription(subscription) + require.NoError(t, err) + + results, err = orm1.GetSubscriptions(0, 10) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + + results, err = orm2.GetSubscriptions(0, 10) + require.NoError(t, err) + require.Equal(t, 1, len(results), "incorrect results length") + }) +} +func Test_NewORM(t *testing.T) { + t.Run("OK-create_ORM", func(t *testing.T) { + _, err := subscriptions.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), testutils.NewAddress()) + require.NoError(t, err) + }) + t.Run("NOK-create_ORM_with_nil_fields", func(t *testing.T) { + _, err := subscriptions.NewORM(nil, nil, nil, common.Address{}) + require.Error(t, err) + }) + t.Run("NOK-create_ORM_with_empty_address", func(t *testing.T) { + _, err := subscriptions.NewORM(pgtest.NewSqlxDB(t), logger.TestLogger(t), pgtest.NewQConfig(true), common.Address{}) + require.Error(t, err) + }) +} diff --git a/core/services/gateway/handlers/functions/subscriptions.go b/core/services/gateway/handlers/functions/subscriptions/subscriptions.go similarity index 78% rename from core/services/gateway/handlers/functions/subscriptions.go rename to core/services/gateway/handlers/functions/subscriptions/subscriptions.go index ebffbbdd206..610aaa1d7f1 100644 --- a/core/services/gateway/handlers/functions/subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions/subscriptions.go @@ -1,4 +1,4 @@ -package functions +package subscriptions import ( "context" @@ -19,12 +19,15 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) +const defaultStoreBatchSize = 100 + type OnchainSubscriptionsConfig struct { ContractAddress common.Address `json:"contractAddress"` BlockConfirmations uint `json:"blockConfirmations"` UpdateFrequencySec uint `json:"updateFrequencySec"` UpdateTimeoutSec uint `json:"updateTimeoutSec"` UpdateRangeSize uint `json:"updateRangeSize"` + StoreBatchSize uint `json:"storeBatchSize"` } // OnchainSubscriptions maintains a mirror of all subscriptions fetched from the blockchain (EVM-only). @@ -43,6 +46,7 @@ type onchainSubscriptions struct { config OnchainSubscriptionsConfig subscriptions UserSubscriptions + orm ORM client evmclient.Client router *functions_router.FunctionsRouter blockConfirmations *big.Int @@ -52,7 +56,7 @@ type onchainSubscriptions struct { stopCh services.StopChan } -func NewOnchainSubscriptions(client evmclient.Client, config OnchainSubscriptionsConfig, lggr logger.Logger) (OnchainSubscriptions, error) { +func NewOnchainSubscriptions(client evmclient.Client, config OnchainSubscriptionsConfig, orm ORM, lggr logger.Logger) (OnchainSubscriptions, error) { if client == nil { return nil, errors.New("client is nil") } @@ -63,9 +67,17 @@ func NewOnchainSubscriptions(client evmclient.Client, config OnchainSubscription if err != nil { return nil, fmt.Errorf("unexpected error during functions_router.NewFunctionsRouter: %s", err) } + + // if StoreBatchSize is not specified use the default value + if config.StoreBatchSize == 0 { + lggr.Info("StoreBatchSize not specified, using default size: ", defaultStoreBatchSize) + config.StoreBatchSize = defaultStoreBatchSize + } + return &onchainSubscriptions{ config: config, subscriptions: NewUserSubscriptions(), + orm: orm, client: client, router: router, blockConfirmations: big.NewInt(int64(config.BlockConfirmations)), @@ -87,6 +99,8 @@ func (s *onchainSubscriptions) Start(ctx context.Context) error { return errors.New("OnchainSubscriptionsConfig.UpdateRangeSize must be greater than 0") } + s.loadStoredSubscriptions() + s.closeWait.Add(1) go s.queryLoop() @@ -190,7 +204,15 @@ func (s *onchainSubscriptions) querySubscriptionsRange(ctx context.Context, bloc for i, subscription := range subscriptions { subscriptionId := start + uint64(i) subscription := subscription - s.subscriptions.UpdateSubscription(subscriptionId, &subscription) + updated := s.subscriptions.UpdateSubscription(subscriptionId, &subscription) + if updated { + if err = s.orm.UpsertSubscription(StoredSubscription{ + SubscriptionID: subscriptionId, + IFunctionsSubscriptionsSubscription: subscription, + }); err != nil { + s.lggr.Errorf("unexpected error updating subscription in the db: %w", err) + } + } } return nil @@ -203,3 +225,30 @@ func (s *onchainSubscriptions) getSubscriptionsCount(ctx context.Context, blockN Context: ctx, }) } + +func (s *onchainSubscriptions) loadStoredSubscriptions() { + offset := uint(0) + for { + csBatch, err := s.orm.GetSubscriptions(offset, s.config.StoreBatchSize) + if err != nil { + break + } + + for _, cs := range csBatch { + _ = s.subscriptions.UpdateSubscription(cs.SubscriptionID, &functions_router.IFunctionsSubscriptionsSubscription{ + Balance: cs.Balance, + Owner: cs.Owner, + BlockedBalance: cs.BlockedBalance, + ProposedOwner: cs.ProposedOwner, + Consumers: cs.Consumers, + Flags: cs.Flags, + }) + } + s.lggr.Debugw("Loading stored subscriptions", "offset", offset, "batch_length", len(csBatch)) + + if len(csBatch) != int(s.config.StoreBatchSize) { + break + } + offset += s.config.StoreBatchSize + } +} diff --git a/core/services/gateway/handlers/functions/subscriptions_test.go b/core/services/gateway/handlers/functions/subscriptions/subscriptions_test.go similarity index 60% rename from core/services/gateway/handlers/functions/subscriptions_test.go rename to core/services/gateway/handlers/functions/subscriptions/subscriptions_test.go index adbf637ad73..be1d2520434 100644 --- a/core/services/gateway/handlers/functions/subscriptions_test.go +++ b/core/services/gateway/handlers/functions/subscriptions/subscriptions_test.go @@ -1,4 +1,4 @@ -package functions_test +package subscriptions_test import ( "math/big" @@ -15,14 +15,17 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" + smocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions/mocks" ) const ( validUser = "0x9ED925d8206a4f88a2f643b28B3035B315753Cd6" invalidUser = "0x6E2dc0F9DB014aE19888F539E59285D2Ea04244C" + storedUser = "0x3E2dc0F9DB014aE19888F539E59285D2Ea04233G" ) func TestSubscriptions_OnePass(t *testing.T) { @@ -40,14 +43,17 @@ func TestSubscriptions_OnePass(t *testing.T) { To: &common.Address{}, Data: hexutil.MustDecode("0xec2454e500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003"), }, mock.Anything).Return(getSubscriptionsInRange, nil) - config := functions.OnchainSubscriptionsConfig{ + config := subscriptions.OnchainSubscriptionsConfig{ ContractAddress: common.Address{}, BlockConfirmations: 1, UpdateFrequencySec: 1, UpdateTimeoutSec: 1, UpdateRangeSize: 3, } - subscriptions, err := functions.NewOnchainSubscriptions(client, config, logger.TestLogger(t)) + orm := smocks.NewORM(t) + orm.On("GetSubscriptions", uint(0), uint(100)).Return([]subscriptions.StoredSubscription{}, nil) + orm.On("UpsertSubscription", mock.Anything).Return(nil) + subscriptions, err := subscriptions.NewOnchainSubscriptions(client, config, orm, logger.TestLogger(t)) require.NoError(t, err) err = subscriptions.Start(ctx) @@ -88,14 +94,17 @@ func TestSubscriptions_MultiPass(t *testing.T) { To: &common.Address{}, Data: hexutil.MustDecode("0xec2454e500000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006"), }, mock.Anything).Return(getSubscriptionsInRange, nil) - config := functions.OnchainSubscriptionsConfig{ + config := subscriptions.OnchainSubscriptionsConfig{ ContractAddress: common.Address{}, BlockConfirmations: 1, UpdateFrequencySec: 1, UpdateTimeoutSec: 1, UpdateRangeSize: 3, } - subscriptions, err := functions.NewOnchainSubscriptions(client, config, logger.TestLogger(t)) + orm := smocks.NewORM(t) + orm.On("GetSubscriptions", uint(0), uint(100)).Return([]subscriptions.StoredSubscription{}, nil) + orm.On("UpsertSubscription", mock.Anything).Return(nil) + subscriptions, err := subscriptions.NewOnchainSubscriptions(client, config, orm, logger.TestLogger(t)) require.NoError(t, err) err = subscriptions.Start(ctx) @@ -108,3 +117,57 @@ func TestSubscriptions_MultiPass(t *testing.T) { return currentCycle.Load() == ncycles }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) } + +func TestSubscriptions_Stored(t *testing.T) { + getSubscriptionCount := hexutil.MustDecode("0x0000000000000000000000000000000000000000000000000000000000000003") + getSubscriptionsInRange := hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000109e6e1b12098cc8f3a1e9719a817ec53ab9b35c000000000000000000000000000000000000000000000000000034e23f515cb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000f5340f0968ee8b7dfd97e3327a6139273cc2c4fa000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001bc14b92364c75e20000000000000000000000009ed925d8206a4f88a2f643b28b3035b315753cd60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000005439e5881a529f3ccbffc0e82d49f9db3950aefe") + + ctx := testutils.Context(t) + client := mocks.NewClient(t) + client.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(42), nil) + client.On("CallContract", mock.Anything, ethereum.CallMsg{ // getSubscriptionCount + To: &common.Address{}, + Data: hexutil.MustDecode("0x66419970"), + }, mock.Anything).Return(getSubscriptionCount, nil) + client.On("CallContract", mock.Anything, ethereum.CallMsg{ // GetSubscriptionsInRange + To: &common.Address{}, + Data: hexutil.MustDecode("0xec2454e500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003"), + }, mock.Anything).Return(getSubscriptionsInRange, nil) + config := subscriptions.OnchainSubscriptionsConfig{ + ContractAddress: common.Address{}, + BlockConfirmations: 1, + UpdateFrequencySec: 1, + UpdateTimeoutSec: 1, + UpdateRangeSize: 3, + StoreBatchSize: 1, + } + + expectedBalance := big.NewInt(5) + orm := smocks.NewORM(t) + orm.On("GetSubscriptions", uint(0), uint(1)).Return([]subscriptions.StoredSubscription{ + { + SubscriptionID: 1, + IFunctionsSubscriptionsSubscription: functions_router.IFunctionsSubscriptionsSubscription{ + Balance: expectedBalance, + Owner: common.HexToAddress(storedUser), + BlockedBalance: big.NewInt(10), + }, + }, + }, nil) + orm.On("GetSubscriptions", uint(1), uint(1)).Return([]subscriptions.StoredSubscription{}, nil) + orm.On("UpsertSubscription", mock.Anything).Return(nil) + + subscriptions, err := subscriptions.NewOnchainSubscriptions(client, config, orm, logger.TestLogger(t)) + require.NoError(t, err) + + err = subscriptions.Start(ctx) + require.NoError(t, err) + t.Cleanup(func() { + assert.NoError(t, subscriptions.Close()) + }) + + gomega.NewGomegaWithT(t).Eventually(func() bool { + actualBalance, err := subscriptions.GetMaxUserBalance(common.HexToAddress(storedUser)) + return err == nil && assert.Equal(t, expectedBalance, actualBalance) + }, testutils.WaitTimeout(t), time.Second).Should(gomega.BeTrue()) +} diff --git a/core/services/gateway/handlers/functions/user_subscriptions.go b/core/services/gateway/handlers/functions/subscriptions/user_subscriptions.go similarity index 53% rename from core/services/gateway/handlers/functions/user_subscriptions.go rename to core/services/gateway/handlers/functions/subscriptions/user_subscriptions.go index c47ac8a4c90..ec506b6a864 100644 --- a/core/services/gateway/handlers/functions/user_subscriptions.go +++ b/core/services/gateway/handlers/functions/subscriptions/user_subscriptions.go @@ -1,4 +1,4 @@ -package functions +package subscriptions import ( "math/big" @@ -6,14 +6,16 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Methods are NOT thread-safe. +var ErrUserHasNoSubscription = errors.New("user has no subscriptions") + type UserSubscriptions interface { - UpdateSubscription(subscriptionId uint64, subscription *functions_router.IFunctionsSubscriptionsSubscription) + UpdateSubscription(subscriptionId uint64, subscription *functions_router.IFunctionsSubscriptionsSubscription) bool GetMaxUserBalance(user common.Address) (*big.Int, error) } @@ -29,29 +31,45 @@ func NewUserSubscriptions() UserSubscriptions { } } -func (us *userSubscriptions) UpdateSubscription(subscriptionId uint64, subscription *functions_router.IFunctionsSubscriptionsSubscription) { +// StoredSubscription is used to populate the user subscription maps from a persistent layer like postgres. +type StoredSubscription struct { + SubscriptionID uint64 + functions_router.IFunctionsSubscriptionsSubscription +} + +// UpdateSubscription updates a subscription returning false in case there was no variation to the current state. +func (us *userSubscriptions) UpdateSubscription(subscriptionId uint64, subscription *functions_router.IFunctionsSubscriptionsSubscription) bool { if subscription == nil || subscription.Owner == utils.ZeroAddress { user, ok := us.subscriptionIdsMap[subscriptionId] - if ok { - delete(us.userSubscriptionsMap[user], subscriptionId) - if len(us.userSubscriptionsMap[user]) == 0 { - delete(us.userSubscriptionsMap, user) - } + if !ok { + return false } + + delete(us.userSubscriptionsMap[user], subscriptionId) delete(us.subscriptionIdsMap, subscriptionId) - } else { - us.subscriptionIdsMap[subscriptionId] = subscription.Owner - if _, ok := us.userSubscriptionsMap[subscription.Owner]; !ok { - us.userSubscriptionsMap[subscription.Owner] = make(map[uint64]*functions_router.IFunctionsSubscriptionsSubscription) + if len(us.userSubscriptionsMap[user]) == 0 { + delete(us.userSubscriptionsMap, user) } - us.userSubscriptionsMap[subscription.Owner][subscriptionId] = subscription + return true + } + + // there is no change to the subscription + if us.userSubscriptionsMap[subscription.Owner][subscriptionId] == subscription { + return false + } + + us.subscriptionIdsMap[subscriptionId] = subscription.Owner + if _, ok := us.userSubscriptionsMap[subscription.Owner]; !ok { + us.userSubscriptionsMap[subscription.Owner] = make(map[uint64]*functions_router.IFunctionsSubscriptionsSubscription) } + us.userSubscriptionsMap[subscription.Owner][subscriptionId] = subscription + return true } func (us *userSubscriptions) GetMaxUserBalance(user common.Address) (*big.Int, error) { subs, exists := us.userSubscriptionsMap[user] if !exists { - return nil, errors.New("user has no subscriptions") + return nil, ErrUserHasNoSubscription } maxBalance := big.NewInt(0) diff --git a/core/services/gateway/handlers/functions/subscriptions/user_subscriptions_test.go b/core/services/gateway/handlers/functions/subscriptions/user_subscriptions_test.go new file mode 100644 index 00000000000..4d58155735f --- /dev/null +++ b/core/services/gateway/handlers/functions/subscriptions/user_subscriptions_test.go @@ -0,0 +1,149 @@ +package subscriptions_test + +import ( + "math/big" + "testing" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" + + "github.com/stretchr/testify/assert" +) + +func TestUserSubscriptions(t *testing.T) { + t.Parallel() + + us := subscriptions.NewUserSubscriptions() + + t.Run("GetMaxUserBalance for unknown user", func(t *testing.T) { + _, err := us.GetMaxUserBalance(utils.RandomAddress()) + assert.Error(t, err) + }) + + t.Run("UpdateSubscription then GetMaxUserBalance", func(t *testing.T) { + user1 := utils.RandomAddress() + user1Balance := big.NewInt(10) + user2 := utils.RandomAddress() + user2Balance1 := big.NewInt(50) + user2Balance2 := big.NewInt(70) + + updated := us.UpdateSubscription(5, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: user1, + Balance: user1Balance, + }) + assert.True(t, updated) + + updated = us.UpdateSubscription(3, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: user2, + Balance: user2Balance1, + }) + assert.True(t, updated) + + updated = us.UpdateSubscription(10, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: user2, + Balance: user2Balance2, + }) + assert.True(t, updated) + + balance, err := us.GetMaxUserBalance(user1) + assert.NoError(t, err) + assert.Zero(t, balance.Cmp(user1Balance)) + + balance, err = us.GetMaxUserBalance(user2) + assert.NoError(t, err) + assert.Zero(t, balance.Cmp(user2Balance2)) + }) +} + +func TestUserSubscriptions_UpdateSubscription(t *testing.T) { + t.Parallel() + + t.Run("update balance", func(t *testing.T) { + us := subscriptions.NewUserSubscriptions() + owner := utils.RandomAddress() + + updated := us.UpdateSubscription(1, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: owner, + Balance: big.NewInt(10), + }) + assert.True(t, updated) + + updated = us.UpdateSubscription(1, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: owner, + Balance: big.NewInt(100), + }) + assert.True(t, updated) + }) + + t.Run("updated proposed owner", func(t *testing.T) { + us := subscriptions.NewUserSubscriptions() + owner := utils.RandomAddress() + + updated := us.UpdateSubscription(1, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: owner, + Balance: big.NewInt(10), + }) + assert.True(t, updated) + + updated = us.UpdateSubscription(1, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: owner, + Balance: big.NewInt(10), + ProposedOwner: utils.RandomAddress(), + }) + assert.True(t, updated) + }) + t.Run("remove subscriptions", func(t *testing.T) { + us := subscriptions.NewUserSubscriptions() + user2 := utils.RandomAddress() + user2Balance1 := big.NewInt(50) + user2Balance2 := big.NewInt(70) + + updated := us.UpdateSubscription(3, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: user2, + Balance: user2Balance1, + }) + assert.True(t, updated) + + updated = us.UpdateSubscription(10, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: user2, + Balance: user2Balance2, + }) + assert.True(t, updated) + + updated = us.UpdateSubscription(3, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: utils.ZeroAddress, + }) + assert.True(t, updated) + + updated = us.UpdateSubscription(10, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: utils.ZeroAddress, + }) + assert.True(t, updated) + + _, err := us.GetMaxUserBalance(user2) + assert.Error(t, err) + }) + + t.Run("remove a non existing subscription", func(t *testing.T) { + us := subscriptions.NewUserSubscriptions() + updated := us.UpdateSubscription(3, &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: utils.ZeroAddress, + }) + assert.False(t, updated) + }) + + t.Run("no actual changes", func(t *testing.T) { + us := subscriptions.NewUserSubscriptions() + subscription := &functions_router.IFunctionsSubscriptionsSubscription{ + Owner: utils.RandomAddress(), + Balance: big.NewInt(25), + BlockedBalance: big.NewInt(25), + } + updated := us.UpdateSubscription(5, subscription) + assert.True(t, updated) + + updated = us.UpdateSubscription(5, subscription) + assert.False(t, updated) + }) +} diff --git a/core/services/gateway/handlers/functions/user_subscriptions_test.go b/core/services/gateway/handlers/functions/user_subscriptions_test.go deleted file mode 100644 index 9e6a660adad..00000000000 --- a/core/services/gateway/handlers/functions/user_subscriptions_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package functions_test - -import ( - "math/big" - "testing" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_router" - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" - "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/stretchr/testify/assert" -) - -func TestUserSubscriptions(t *testing.T) { - t.Parallel() - - us := functions.NewUserSubscriptions() - - t.Run("GetMaxUserBalance for unknown user", func(t *testing.T) { - _, err := us.GetMaxUserBalance(utils.RandomAddress()) - assert.Error(t, err) - }) - - t.Run("UpdateSubscription then GetMaxUserBalance", func(t *testing.T) { - user1 := utils.RandomAddress() - user1Balance := big.NewInt(10) - user2 := utils.RandomAddress() - user2Balance1 := big.NewInt(50) - user2Balance2 := big.NewInt(70) - - us.UpdateSubscription(5, &functions_router.IFunctionsSubscriptionsSubscription{ - Owner: user1, - Balance: user1Balance, - }) - us.UpdateSubscription(3, &functions_router.IFunctionsSubscriptionsSubscription{ - Owner: user2, - Balance: user2Balance1, - }) - us.UpdateSubscription(10, &functions_router.IFunctionsSubscriptionsSubscription{ - Owner: user2, - Balance: user2Balance2, - }) - - balance, err := us.GetMaxUserBalance(user1) - assert.NoError(t, err) - assert.Zero(t, balance.Cmp(user1Balance)) - - balance, err = us.GetMaxUserBalance(user2) - assert.NoError(t, err) - assert.Zero(t, balance.Cmp(user2Balance2)) - }) - - t.Run("UpdateSubscription to remove subscriptions", func(t *testing.T) { - user2 := utils.RandomAddress() - user2Balance1 := big.NewInt(50) - user2Balance2 := big.NewInt(70) - - us.UpdateSubscription(3, &functions_router.IFunctionsSubscriptionsSubscription{ - Owner: user2, - Balance: user2Balance1, - }) - us.UpdateSubscription(10, &functions_router.IFunctionsSubscriptionsSubscription{ - Owner: user2, - Balance: user2Balance2, - }) - - us.UpdateSubscription(3, &functions_router.IFunctionsSubscriptionsSubscription{ - Owner: utils.ZeroAddress, - }) - us.UpdateSubscription(10, &functions_router.IFunctionsSubscriptionsSubscription{ - Owner: utils.ZeroAddress, - }) - - _, err := us.GetMaxUserBalance(user2) - assert.Error(t, err) - }) -} diff --git a/core/services/gateway/handlers/mocks/don.go b/core/services/gateway/handlers/mocks/don.go index 02df7c0334f..6e88708dd7d 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type DON struct { func (_m *DON) SendToNode(ctx context.Context, nodeAddress string, msg *api.Message) error { ret := _m.Called(ctx, nodeAddress, msg) + if len(ret) == 0 { + panic("no return value specified for SendToNode") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, *api.Message) error); ok { r0 = rf(ctx, nodeAddress, msg) diff --git a/core/services/gateway/handlers/mocks/handler.go b/core/services/gateway/handlers/mocks/handler.go index 10a31c6d76e..7dfe1eae784 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type Handler struct { func (_m *Handler) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -35,6 +39,10 @@ func (_m *Handler) Close() error { func (_m *Handler) HandleNodeMessage(ctx context.Context, msg *api.Message, nodeAddr string) error { ret := _m.Called(ctx, msg, nodeAddr) + if len(ret) == 0 { + panic("no return value specified for HandleNodeMessage") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *api.Message, string) error); ok { r0 = rf(ctx, msg, nodeAddr) @@ -49,6 +57,10 @@ func (_m *Handler) HandleNodeMessage(ctx context.Context, msg *api.Message, node func (_m *Handler) HandleUserMessage(ctx context.Context, msg *api.Message, callbackCh chan<- handlers.UserCallbackPayload) error { ret := _m.Called(ctx, msg, callbackCh) + if len(ret) == 0 { + panic("no return value specified for HandleUserMessage") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *api.Message, chan<- handlers.UserCallbackPayload) error); ok { r0 = rf(ctx, msg, callbackCh) @@ -63,6 +75,10 @@ func (_m *Handler) HandleUserMessage(ctx context.Context, msg *api.Message, call func (_m *Handler) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/integration_tests/gateway_integration_test.go b/core/services/gateway/integration_tests/gateway_integration_test.go index 310047950e6..a2064b7a591 100644 --- a/core/services/gateway/integration_tests/gateway_integration_test.go +++ b/core/services/gateway/integration_tests/gateway_integration_test.go @@ -5,6 +5,7 @@ import ( "context" "crypto/ecdsa" "fmt" + "io" "net/http" "strings" "sync/atomic" @@ -14,6 +15,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway" @@ -35,18 +37,18 @@ Path = "/node" Port = 0 HandshakeTimeoutMillis = 2_000 MaxRequestBytes = 20_000 -ReadTimeoutMillis = 100 -RequestTimeoutMillis = 100 -WriteTimeoutMillis = 100 +ReadTimeoutMillis = 1000 +RequestTimeoutMillis = 1000 +WriteTimeoutMillis = 1000 [UserServerConfig] Path = "/user" Port = 0 ContentTypeHeader = "application/jsonrpc" MaxRequestBytes = 20_000 -ReadTimeoutMillis = 100 -RequestTimeoutMillis = 100 -WriteTimeoutMillis = 100 +ReadTimeoutMillis = 1000 +RequestTimeoutMillis = 1000 +WriteTimeoutMillis = 1000 [[Dons]] DonId = "test_don" @@ -71,6 +73,13 @@ Id = "test_gateway" URL = "%s" ` +const ( + messageId1 = "123" + messageId2 = "456" + + nodeResponsePayload = `{"response":"correct response"}` +) + func parseGatewayConfig(t *testing.T, tomlConfig string) *config.GatewayConfig { var cfg config.GatewayConfig err := toml.Unmarshal([]byte(tomlConfig), &cfg) @@ -93,6 +102,21 @@ type client struct { func (c *client) HandleGatewayMessage(ctx context.Context, gatewayId string, msg *api.Message) { c.done.Store(true) + // send back user's message without re-signing - should be ignored by the Gateway + _ = c.connector.SendToGateway(ctx, gatewayId, msg) + // send back a correct response + responseMsg := &api.Message{Body: api.MessageBody{ + MessageId: msg.Body.MessageId, + Method: "test", + DonId: "test_don", + Receiver: msg.Body.Sender, + Payload: []byte(nodeResponsePayload), + }} + err := responseMsg.Sign(c.privateKey) + if err != nil { + panic(err) + } + _ = c.connector.SendToGateway(ctx, gatewayId, responseMsg) } func (c *client) Sign(data ...[]byte) ([]byte, error) { @@ -110,16 +134,18 @@ func (*client) Close() error { func TestIntegration_Gateway_NoFullNodes_BasicConnectionAndMessage(t *testing.T) { t.Parallel() - nodeKeys := common.NewTestNodes(t, 1)[0] + testWallets := common.NewTestNodes(t, 2) + nodeKeys := testWallets[0] + userKeys := testWallets[1] // Verify that addresses in config are case-insensitive nodeKeys.Address = strings.ToUpper(nodeKeys.Address) // Launch Gateway lggr := logger.TestLogger(t) gatewayConfig := fmt.Sprintf(gatewayConfigTemplate, nodeKeys.Address) - gateway, err := gateway.NewGatewayFromConfig(parseGatewayConfig(t, gatewayConfig), gateway.NewHandlerFactory(nil, lggr), lggr) + gateway, err := gateway.NewGatewayFromConfig(parseGatewayConfig(t, gatewayConfig), gateway.NewHandlerFactory(nil, nil, nil, lggr), lggr) require.NoError(t, err) - require.NoError(t, gateway.Start(testutils.Context(t))) + servicetest.Run(t, gateway) userPort, nodePort := gateway.GetUserPort(), gateway.GetNodePort() userUrl := fmt.Sprintf("http://localhost:%d/user", userPort) nodeUrl := fmt.Sprintf("ws://localhost:%d/node", nodePort) @@ -129,22 +155,41 @@ func TestIntegration_Gateway_NoFullNodes_BasicConnectionAndMessage(t *testing.T) connector, err := connector.NewGatewayConnector(parseConnectorConfig(t, nodeConfigTemplate, nodeKeys.Address, nodeUrl), client, client, utils.NewRealClock(), lggr) require.NoError(t, err) client.connector = connector - require.NoError(t, connector.Start(testutils.Context(t))) + servicetest.Run(t, connector) - // Send requests until one of them reaches Connector + // Send requests until one of them reaches Connector (i.e. the node) gomega.NewGomegaWithT(t).Eventually(func() bool { - msg := &api.Message{Body: api.MessageBody{MessageId: "123", Method: "test", DonId: "test_don"}} - require.NoError(t, msg.Sign(nodeKeys.PrivateKey)) - codec := api.JsonRPCCodec{} - rawMsg, err := codec.EncodeRequest(msg) - require.NoError(t, err) - req, err := http.NewRequestWithContext(testutils.Context(t), "POST", userUrl, bytes.NewBuffer(rawMsg)) - require.NoError(t, err) + req := newHttpRequestObject(t, messageId1, userUrl, userKeys.PrivateKey) httpClient := &http.Client{} _, _ = httpClient.Do(req) // could initially return error if Gateway is not fully initialized yet return client.done.Load() }, testutils.WaitTimeout(t), testutils.TestInterval).Should(gomega.Equal(true)) - require.NoError(t, connector.Close()) - require.NoError(t, gateway.Close()) + // Send another request and validate that response has correct content and sender + req := newHttpRequestObject(t, messageId2, userUrl, userKeys.PrivateKey) + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + + rawResp, err := io.ReadAll(resp.Body) + require.NoError(t, err) + codec := api.JsonRPCCodec{} + respMsg, err := codec.DecodeResponse(rawResp) + require.NoError(t, err) + require.NoError(t, respMsg.Validate()) + require.Equal(t, strings.ToLower(nodeKeys.Address), respMsg.Body.Sender) + require.Equal(t, messageId2, respMsg.Body.MessageId) + require.Equal(t, nodeResponsePayload, string(respMsg.Body.Payload)) +} + +func newHttpRequestObject(t *testing.T, messageId string, userUrl string, signerKey *ecdsa.PrivateKey) *http.Request { + msg := &api.Message{Body: api.MessageBody{MessageId: messageId, Method: "test", DonId: "test_don"}} + require.NoError(t, msg.Sign(signerKey)) + codec := api.JsonRPCCodec{} + rawMsg, err := codec.EncodeRequest(msg) + require.NoError(t, err) + req, err := http.NewRequestWithContext(testutils.Context(t), "POST", userUrl, bytes.NewBuffer(rawMsg)) + require.NoError(t, err) + return req } diff --git a/core/services/gateway/network/httpserver_test.go b/core/services/gateway/network/httpserver_test.go index 92215245e20..dac00df2a12 100644 --- a/core/services/gateway/network/httpserver_test.go +++ b/core/services/gateway/network/httpserver_test.go @@ -47,7 +47,7 @@ func startNewServer(t *testing.T, maxRequestBytes int64, readTimeoutMillis uint3 } func sendRequest(t *testing.T, url string, body []byte) *http.Response { - req, err := http.NewRequest("POST", url, bytes.NewBuffer(body)) + req, err := http.NewRequestWithContext(testutils.Context(t), "POST", url, bytes.NewBuffer(body)) require.NoError(t, err) client := &http.Client{} resp, err := client.Do(req) diff --git a/core/services/gateway/network/mocks/connection_acceptor.go b/core/services/gateway/network/mocks/connection_acceptor.go index 738904984af..c45cc7fbe3e 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -22,6 +22,10 @@ func (_m *ConnectionAcceptor) AbortHandshake(attemptId string) { func (_m *ConnectionAcceptor) FinalizeHandshake(attemptId string, response []byte, conn *websocket.Conn) error { ret := _m.Called(attemptId, response, conn) + if len(ret) == 0 { + panic("no return value specified for FinalizeHandshake") + } + var r0 error if rf, ok := ret.Get(0).(func(string, []byte, *websocket.Conn) error); ok { r0 = rf(attemptId, response, conn) @@ -36,6 +40,10 @@ func (_m *ConnectionAcceptor) FinalizeHandshake(attemptId string, response []byt func (_m *ConnectionAcceptor) StartHandshake(authHeader []byte) (string, []byte, error) { ret := _m.Called(authHeader) + if len(ret) == 0 { + panic("no return value specified for StartHandshake") + } + var r0 string var r1 []byte var r2 error diff --git a/core/services/gateway/network/mocks/connection_initiator.go b/core/services/gateway/network/mocks/connection_initiator.go index 3ff60e61398..87e4f407328 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type ConnectionInitiator struct { func (_m *ConnectionInitiator) ChallengeResponse(_a0 *url.URL, challenge []byte) ([]byte, error) { ret := _m.Called(_a0, challenge) + if len(ret) == 0 { + panic("no return value specified for ChallengeResponse") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*url.URL, []byte) ([]byte, error)); ok { @@ -43,6 +47,10 @@ func (_m *ConnectionInitiator) ChallengeResponse(_a0 *url.URL, challenge []byte) func (_m *ConnectionInitiator) NewAuthHeader(_a0 *url.URL) ([]byte, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for NewAuthHeader") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*url.URL) ([]byte, error)); ok { diff --git a/core/services/gateway/network/mocks/http_request_handler.go b/core/services/gateway/network/mocks/http_request_handler.go index 7716626ac72..7c5ff4025cf 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type HTTPRequestHandler struct { func (_m *HTTPRequestHandler) ProcessRequest(ctx context.Context, rawRequest []byte) ([]byte, int) { ret := _m.Called(ctx, rawRequest) + if len(ret) == 0 { + panic("no return value specified for ProcessRequest") + } + var r0 []byte var r1 int if rf, ok := ret.Get(0).(func(context.Context, []byte) ([]byte, int)); ok { diff --git a/core/services/gateway/network/mocks/http_server.go b/core/services/gateway/network/mocks/http_server.go index 197e77f1b8a..81e180e7b8d 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type HttpServer struct { func (_m *HttpServer) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *HttpServer) Close() error { func (_m *HttpServer) GetPort() int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetPort") + } + var r0 int if rf, ok := ret.Get(0).(func() int); ok { r0 = rf() @@ -51,6 +59,10 @@ func (_m *HttpServer) SetHTTPRequestHandler(handler network.HTTPRequestHandler) func (_m *HttpServer) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/network/mocks/web_socket_server.go b/core/services/gateway/network/mocks/web_socket_server.go index d88cd5ba4f7..4f75f3b7d0f 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type WebSocketServer struct { func (_m *WebSocketServer) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -31,6 +35,10 @@ func (_m *WebSocketServer) Close() error { func (_m *WebSocketServer) GetPort() int { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetPort") + } + var r0 int if rf, ok := ret.Get(0).(func() int); ok { r0 = rf() @@ -45,6 +53,10 @@ func (_m *WebSocketServer) GetPort() int { func (_m *WebSocketServer) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/gateway/network/wsconnection_test.go b/core/services/gateway/network/wsconnection_test.go index 5fd8aa50e33..4ded4f40b10 100644 --- a/core/services/gateway/network/wsconnection_test.go +++ b/core/services/gateway/network/wsconnection_test.go @@ -9,6 +9,7 @@ import ( "github.com/gorilla/websocket" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/network" @@ -30,18 +31,17 @@ func (ssl *serverSideLogic) wsHandler(w http.ResponseWriter, r *http.Request) { } func TestWSConnectionWrapper_ClientReconnect(t *testing.T) { - ctx := testutils.Context(t) lggr := logger.TestLogger(t) // server ssl := &serverSideLogic{connWrapper: network.NewWSConnectionWrapper(lggr)} - require.NoError(t, ssl.connWrapper.Start(ctx)) + servicetest.Run(t, ssl.connWrapper) s := httptest.NewServer(http.HandlerFunc(ssl.wsHandler)) serverURL := "ws" + strings.TrimPrefix(s.URL, "http") defer s.Close() // client clientConnWrapper := network.NewWSConnectionWrapper(lggr) - require.NoError(t, clientConnWrapper.Start(ctx)) + servicetest.Run(t, clientConnWrapper) // connect, write a message, disconnect conn, _, err := websocket.DefaultDialer.Dial(serverURL, nil) @@ -64,8 +64,4 @@ func TestWSConnectionWrapper_ClientReconnect(t *testing.T) { require.NoError(t, writeErr) <-ssl.connWrapper.ReadChannel() // consumed by server conn.Close() - - ssl.connWrapper.Close() - clientConnWrapper.Close() - clientConnWrapper.Close() // safe to call Close() twice } diff --git a/core/services/gateway/network/wsserver_test.go b/core/services/gateway/network/wsserver_test.go index 1a4c04787b4..0b24dbe6614 100644 --- a/core/services/gateway/network/wsserver_test.go +++ b/core/services/gateway/network/wsserver_test.go @@ -49,7 +49,7 @@ func startNewWSServer(t *testing.T, readTimeoutMillis uint32) (server network.We } func sendRequestWithHeader(t *testing.T, url string, headerName string, headerValue string) *http.Response { - req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte{})) + req, err := http.NewRequestWithContext(testutils.Context(t), "POST", url, bytes.NewBuffer([]byte{})) require.NoError(t, err) req.Header.Set(headerName, headerValue) diff --git a/core/services/health_test.go b/core/services/health_test.go index 3bd0e5d39b2..b95b266ca19 100644 --- a/core/services/health_test.go +++ b/core/services/health_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" ) @@ -20,7 +21,9 @@ func TestNewInBackupHealthReport(t *testing.T) { require.Eventually(t, func() bool { return observed.Len() >= 1 }, time.Second*5, time.Millisecond*100) require.Equal(t, "Starting InBackupHealthReport", observed.TakeAll()[0].Message) - res, err := http.Get("http://localhost:1234/health") + req, err := http.NewRequestWithContext(tests.Context(t), "GET", "http://localhost:1234/health", nil) + require.NoError(t, err) + res, err := http.DefaultClient.Do(req) require.NoError(t, err) require.Equal(t, http.StatusNoContent, res.StatusCode) diff --git a/core/services/job/helpers_test.go b/core/services/job/helpers_test.go index 4151ed401c8..a7543753d63 100644 --- a/core/services/job/helpers_test.go +++ b/core/services/job/helpers_test.go @@ -36,10 +36,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "%s" evmChainID = "0" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] -p2pv2Bootstrappers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "%s" monitoringEndpoint = "chain.link:4321" @@ -108,7 +105,7 @@ ds1 -> ds1_parse -> ds1_multiply; type = "offchainreporting" schemaVersion = 1 contractAddress = "%s" - p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] + p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false transmitterAddress = "%s" keyBundleID = "%s" @@ -125,7 +122,6 @@ ds1 -> ds1_parse; schemaVersion = 1 contractAddress = "%s" evmChainID = "0" - p2pBootstrapPeers = [] isBootstrapPeer = true ` ocrJobSpecText = ` @@ -134,10 +130,7 @@ schemaVersion = 1 contractAddress = "%s" evmChainID = "0" p2pPeerID = "%s" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] -p2pv2Bootstrappers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "%s" monitoringEndpoint = "chain.link:4321" @@ -194,7 +187,7 @@ func makeOCRJobSpec(t *testing.T, transmitterAddress common.Address, b1, b2 stri func compareOCRJobSpecs(t *testing.T, expected, actual job.Job) { require.NotNil(t, expected.OCROracleSpec) require.Equal(t, expected.OCROracleSpec.ContractAddress, actual.OCROracleSpec.ContractAddress) - require.Equal(t, expected.OCROracleSpec.P2PBootstrapPeers, actual.OCROracleSpec.P2PBootstrapPeers) + require.Equal(t, expected.OCROracleSpec.P2PV2Bootstrappers, actual.OCROracleSpec.P2PV2Bootstrappers) require.Equal(t, expected.OCROracleSpec.IsBootstrapPeer, actual.OCROracleSpec.IsBootstrapPeer) require.Equal(t, expected.OCROracleSpec.EncryptedOCRKeyBundleID, actual.OCROracleSpec.EncryptedOCRKeyBundleID) require.Equal(t, expected.OCROracleSpec.TransmitterAddress, actual.OCROracleSpec.TransmitterAddress) @@ -207,7 +200,6 @@ func compareOCRJobSpecs(t *testing.T, expected, actual job.Job) { func makeMinimalHTTPOracleSpec(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig, contractAddress, transmitterAddress, keyBundle, fetchUrl, timeout string) *job.Job { var ocrSpec = job.OCROracleSpec{ - P2PBootstrapPeers: pq.StringArray{}, P2PV2Bootstrappers: pq.StringArray{}, ObservationTimeout: models.Interval(10 * time.Second), BlockchainTimeout: models.Interval(20 * time.Second), diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 21035140f54..3590b526022 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -19,7 +19,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "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/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "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" @@ -41,7 +43,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const mercuryOracleTOML = `name = 'LINK / ETH | 0x0000000000000000000000000000000000000000000000000000000000000001 | verifier_proxy 0x0000000000000000000000000000000000000001' @@ -454,6 +455,9 @@ func TestORM_CreateJob_VRFV2(t *testing.T) { var batchFulfillmentEnabled bool require.NoError(t, db.Get(&batchFulfillmentEnabled, `SELECT batch_fulfillment_enabled FROM vrf_specs LIMIT 1`)) require.False(t, batchFulfillmentEnabled) + var customRevertsPipelineEnabled bool + require.NoError(t, db.Get(&customRevertsPipelineEnabled, `SELECT custom_reverts_pipeline_enabled FROM vrf_specs LIMIT 1`)) + require.False(t, customRevertsPipelineEnabled) var batchFulfillmentGasMultiplier float64 require.NoError(t, db.Get(&batchFulfillmentGasMultiplier, `SELECT batch_fulfillment_gas_multiplier FROM vrf_specs LIMIT 1`)) require.Equal(t, float64(1.0), batchFulfillmentGasMultiplier) @@ -514,13 +518,14 @@ func TestORM_CreateJob_VRFV2Plus(t *testing.T) { fromAddresses := []string{cltest.NewEIP55Address().String(), cltest.NewEIP55Address().String()} jb, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec( testspecs.VRFSpecParams{ - VRFVersion: vrfcommon.V2Plus, - RequestedConfsDelay: 10, - FromAddresses: fromAddresses, - ChunkSize: 25, - BackoffInitialDelay: time.Minute, - BackoffMaxDelay: time.Hour, - GasLanePrice: assets.GWei(100), + VRFVersion: vrfcommon.V2Plus, + RequestedConfsDelay: 10, + FromAddresses: fromAddresses, + ChunkSize: 25, + BackoffInitialDelay: time.Minute, + BackoffMaxDelay: time.Hour, + GasLanePrice: assets.GWei(100), + CustomRevertsPipelineEnabled: true, }). Toml()) require.NoError(t, err) @@ -534,6 +539,9 @@ func TestORM_CreateJob_VRFV2Plus(t *testing.T) { var batchFulfillmentEnabled bool require.NoError(t, db.Get(&batchFulfillmentEnabled, `SELECT batch_fulfillment_enabled FROM vrf_specs LIMIT 1`)) require.False(t, batchFulfillmentEnabled) + var customRevertsPipelineEnabled bool + require.NoError(t, db.Get(&customRevertsPipelineEnabled, `SELECT custom_reverts_pipeline_enabled FROM vrf_specs LIMIT 1`)) + require.True(t, customRevertsPipelineEnabled) var batchFulfillmentGasMultiplier float64 require.NoError(t, db.Get(&batchFulfillmentGasMultiplier, `SELECT batch_fulfillment_gas_multiplier FROM vrf_specs LIMIT 1`)) require.Equal(t, float64(1.0), batchFulfillmentGasMultiplier) @@ -695,7 +703,7 @@ func TestORM_CreateJob_EVMChainID_Validation(t *testing.T) { } func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { - customChainID := utils.NewBig(testutils.NewRandomEVMChainID()) + customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { enabled := true @@ -764,7 +772,7 @@ func TestORM_CreateJob_OCR_DuplicatedContractAddress(t *testing.T) { } func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { - customChainID := utils.NewBig(testutils.NewRandomEVMChainID()) + customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { enabled := true @@ -825,7 +833,7 @@ func TestORM_CreateJob_OCR2_DuplicatedContractAddress(t *testing.T) { } func TestORM_CreateJob_OCR2_Sending_Keys_Transmitter_Keys_Validations(t *testing.T) { - customChainID := utils.NewBig(testutils.NewRandomEVMChainID()) + customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { enabled := true @@ -1021,7 +1029,7 @@ func Test_FindJob(t *testing.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. config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - chainID := utils.NewBigI(1337) + chainID := big.NewI(1337) enabled := true c.EVM = append(c.EVM, &evmcfg.EVMConfig{ ChainID: chainID, @@ -1154,7 +1162,7 @@ func Test_FindJob(t *testing.T) { assert.Equal(t, job.ID, jbID) - _, err2 = orm.FindJobIDByAddress("not-existing", utils.NewBigI(0)) + _, err2 = orm.FindJobIDByAddress("not-existing", big.NewI(0)) require.Error(t, err2) require.ErrorIs(t, err2, sql.ErrNoRows) }) @@ -1222,7 +1230,7 @@ func Test_FindJobsByPipelineSpecIDs(t *testing.T) { jb, err := directrequest.ValidatedDirectRequestSpec(testspecs.GetDirectRequestSpec()) require.NoError(t, err) - jb.DirectRequestSpec.EVMChainID = utils.NewBigI(0) + jb.DirectRequestSpec.EVMChainID = big.NewI(0) err = orm.CreateJob(&jb) require.NoError(t, err) @@ -1379,7 +1387,7 @@ func Test_FindPipelineRunIDsByJobID(t *testing.T) { var jb job.Job config := configtest.NewTestGeneralConfig(t) - db := pgtest.NewSqlxDB(t) + _, db := heavyweight.FullTestDBV2(t, nil) keyStore := cltest.NewKeyStore(t, db, config.Database()) require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) diff --git a/core/services/job/job_pipeline_orm_integration_test.go b/core/services/job/job_pipeline_orm_integration_test.go index f1307753d29..dd3062fa14b 100644 --- a/core/services/job/job_pipeline_orm_integration_test.go +++ b/core/services/job/job_pipeline_orm_integration_test.go @@ -9,6 +9,7 @@ import ( "github.com/jmoiron/sqlx" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -46,7 +47,7 @@ func TestPipelineORM_Integration(t *testing.T) { ` config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(30 * time.Millisecond) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(30 * time.Millisecond) }) db := pgtest.NewSqlxDB(t) keyStore := cltest.NewKeyStore(t, db, config.Database()) diff --git a/core/services/job/mocks/orm.go b/core/services/job/mocks/orm.go index 9e18573f4e5..062c6e936bc 100644 --- a/core/services/job/mocks/orm.go +++ b/core/services/job/mocks/orm.go @@ -1,11 +1,12 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks import ( - context "context" - common "github.com/ethereum/go-ethereum/common" + big "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + + context "context" ethkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -17,8 +18,6 @@ import ( pipeline "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - utils "github.com/smartcontractkit/chainlink/v2/core/utils" - uuid "github.com/google/uuid" ) @@ -31,6 +30,10 @@ type ORM struct { func (_m *ORM) AssertBridgesExist(p pipeline.Pipeline) error { ret := _m.Called(p) + if len(ret) == 0 { + panic("no return value specified for AssertBridgesExist") + } + var r0 error if rf, ok := ret.Get(0).(func(pipeline.Pipeline) error); ok { r0 = rf(p) @@ -45,6 +48,10 @@ func (_m *ORM) AssertBridgesExist(p pipeline.Pipeline) error { func (_m *ORM) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -59,6 +66,10 @@ func (_m *ORM) Close() error { func (_m *ORM) CountPipelineRunsByJobID(jobID int32) (int32, error) { ret := _m.Called(jobID) + if len(ret) == 0 { + panic("no return value specified for CountPipelineRunsByJobID") + } + var r0 int32 var r1 error if rf, ok := ret.Get(0).(func(int32) (int32, error)); ok { @@ -90,6 +101,10 @@ func (_m *ORM) CreateJob(jb *job.Job, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateJob") + } + var r0 error if rf, ok := ret.Get(0).(func(*job.Job, ...pg.QOpt) error); ok { r0 = rf(jb, qopts...) @@ -111,6 +126,10 @@ func (_m *ORM) DeleteJob(id int32, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } + var r0 error if rf, ok := ret.Get(0).(func(int32, ...pg.QOpt) error); ok { r0 = rf(id, qopts...) @@ -125,6 +144,10 @@ func (_m *ORM) DeleteJob(id int32, qopts ...pg.QOpt) error { func (_m *ORM) DismissError(ctx context.Context, errorID int64) error { ret := _m.Called(ctx, errorID) + if len(ret) == 0 { + panic("no return value specified for DismissError") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok { r0 = rf(ctx, errorID) @@ -139,6 +162,10 @@ func (_m *ORM) DismissError(ctx context.Context, errorID int64) error { func (_m *ORM) FindJob(ctx context.Context, id int32) (job.Job, error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for FindJob") + } + var r0 job.Job var r1 error if rf, ok := ret.Get(0).(func(context.Context, int32) (job.Job, error)); ok { @@ -170,6 +197,10 @@ func (_m *ORM) FindJobByExternalJobID(_a0 uuid.UUID, qopts ...pg.QOpt) (job.Job, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindJobByExternalJobID") + } + var r0 job.Job var r1 error if rf, ok := ret.Get(0).(func(uuid.UUID, ...pg.QOpt) (job.Job, error)); ok { @@ -191,7 +222,7 @@ func (_m *ORM) FindJobByExternalJobID(_a0 uuid.UUID, qopts ...pg.QOpt) (job.Job, } // FindJobIDByAddress provides a mock function with given fields: address, evmChainID, qopts -func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils.Big, qopts ...pg.QOpt) (int32, error) { +func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (int32, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -201,18 +232,22 @@ func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindJobIDByAddress") + } + var r0 int32 var r1 error - if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *utils.Big, ...pg.QOpt) (int32, error)); ok { + if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *big.Big, ...pg.QOpt) (int32, error)); ok { return rf(address, evmChainID, qopts...) } - if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *utils.Big, ...pg.QOpt) int32); ok { + if rf, ok := ret.Get(0).(func(ethkey.EIP55Address, *big.Big, ...pg.QOpt) int32); ok { r0 = rf(address, evmChainID, qopts...) } else { r0 = ret.Get(0).(int32) } - if rf, ok := ret.Get(1).(func(ethkey.EIP55Address, *utils.Big, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(ethkey.EIP55Address, *big.Big, ...pg.QOpt) error); ok { r1 = rf(address, evmChainID, qopts...) } else { r1 = ret.Error(1) @@ -225,6 +260,10 @@ func (_m *ORM) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils func (_m *ORM) FindJobIDsWithBridge(name string) ([]int32, error) { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for FindJobIDsWithBridge") + } + var r0 []int32 var r1 error if rf, ok := ret.Get(0).(func(string) ([]int32, error)); ok { @@ -251,6 +290,10 @@ func (_m *ORM) FindJobIDsWithBridge(name string) ([]int32, error) { func (_m *ORM) FindJobTx(ctx context.Context, id int32) (job.Job, error) { ret := _m.Called(ctx, id) + if len(ret) == 0 { + panic("no return value specified for FindJobTx") + } + var r0 job.Job var r1 error if rf, ok := ret.Get(0).(func(context.Context, int32) (job.Job, error)); ok { @@ -275,6 +318,10 @@ func (_m *ORM) FindJobTx(ctx context.Context, id int32) (job.Job, error) { func (_m *ORM) FindJobWithoutSpecErrors(id int32) (job.Job, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for FindJobWithoutSpecErrors") + } + var r0 job.Job var r1 error if rf, ok := ret.Get(0).(func(int32) (job.Job, error)); ok { @@ -299,6 +346,10 @@ func (_m *ORM) FindJobWithoutSpecErrors(id int32) (job.Job, error) { func (_m *ORM) FindJobs(offset int, limit int) ([]job.Job, int, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for FindJobs") + } + var r0 []job.Job var r1 int var r2 error @@ -332,6 +383,10 @@ func (_m *ORM) FindJobs(offset int, limit int) ([]job.Job, int, error) { func (_m *ORM) FindJobsByPipelineSpecIDs(ids []int32) ([]job.Job, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for FindJobsByPipelineSpecIDs") + } + var r0 []job.Job var r1 error if rf, ok := ret.Get(0).(func([]int32) ([]job.Job, error)); ok { @@ -365,6 +420,10 @@ func (_m *ORM) FindOCR2JobIDByAddress(contractID string, feedID *common.Hash, qo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindOCR2JobIDByAddress") + } + var r0 int32 var r1 error if rf, ok := ret.Get(0).(func(string, *common.Hash, ...pg.QOpt) (int32, error)); ok { @@ -389,6 +448,10 @@ func (_m *ORM) FindOCR2JobIDByAddress(contractID string, feedID *common.Hash, qo func (_m *ORM) FindPipelineRunByID(id int64) (pipeline.Run, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for FindPipelineRunByID") + } + var r0 pipeline.Run var r1 error if rf, ok := ret.Get(0).(func(int64) (pipeline.Run, error)); ok { @@ -413,6 +476,10 @@ func (_m *ORM) FindPipelineRunByID(id int64) (pipeline.Run, error) { func (_m *ORM) FindPipelineRunIDsByJobID(jobID int32, offset int, limit int) ([]int64, error) { ret := _m.Called(jobID, offset, limit) + if len(ret) == 0 { + panic("no return value specified for FindPipelineRunIDsByJobID") + } + var r0 []int64 var r1 error if rf, ok := ret.Get(0).(func(int32, int, int) ([]int64, error)); ok { @@ -439,6 +506,10 @@ func (_m *ORM) FindPipelineRunIDsByJobID(jobID int32, offset int, limit int) ([] func (_m *ORM) FindPipelineRunsByIDs(ids []int64) ([]pipeline.Run, error) { ret := _m.Called(ids) + if len(ret) == 0 { + panic("no return value specified for FindPipelineRunsByIDs") + } + var r0 []pipeline.Run var r1 error if rf, ok := ret.Get(0).(func([]int64) ([]pipeline.Run, error)); ok { @@ -472,6 +543,10 @@ func (_m *ORM) FindSpecError(id int64, qopts ...pg.QOpt) (job.SpecError, error) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindSpecError") + } + var r0 job.SpecError var r1 error if rf, ok := ret.Get(0).(func(int64, ...pg.QOpt) (job.SpecError, error)); ok { @@ -503,6 +578,10 @@ func (_m *ORM) FindSpecErrorsByJobIDs(ids []int32, qopts ...pg.QOpt) ([]job.Spec _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindSpecErrorsByJobIDs") + } + var r0 []job.SpecError var r1 error if rf, ok := ret.Get(0).(func([]int32, ...pg.QOpt) ([]job.SpecError, error)); ok { @@ -536,6 +615,10 @@ func (_m *ORM) FindTaskResultByRunIDAndTaskName(runID int64, taskName string, qo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for FindTaskResultByRunIDAndTaskName") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(int64, string, ...pg.QOpt) ([]byte, error)); ok { @@ -569,6 +652,10 @@ func (_m *ORM) InsertJob(_a0 *job.Job, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for InsertJob") + } + var r0 error if rf, ok := ret.Get(0).(func(*job.Job, ...pg.QOpt) error); ok { r0 = rf(_a0, qopts...) @@ -590,6 +677,10 @@ func (_m *ORM) InsertWebhookSpec(webhookSpec *job.WebhookSpec, qopts ...pg.QOpt) _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for InsertWebhookSpec") + } + var r0 error if rf, ok := ret.Get(0).(func(*job.WebhookSpec, ...pg.QOpt) error); ok { r0 = rf(webhookSpec, qopts...) @@ -604,6 +695,10 @@ func (_m *ORM) InsertWebhookSpec(webhookSpec *job.WebhookSpec, qopts ...pg.QOpt) func (_m *ORM) PipelineRuns(jobID *int32, offset int, size int) ([]pipeline.Run, int, error) { ret := _m.Called(jobID, offset, size) + if len(ret) == 0 { + panic("no return value specified for PipelineRuns") + } + var r0 []pipeline.Run var r1 int var r2 error @@ -644,6 +739,10 @@ func (_m *ORM) RecordError(jobID int32, description string, qopts ...pg.QOpt) er _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for RecordError") + } + var r0 error if rf, ok := ret.Get(0).(func(int32, string, ...pg.QOpt) error); ok { r0 = rf(jobID, description, qopts...) diff --git a/core/services/job/mocks/service_ctx.go b/core/services/job/mocks/service_ctx.go index 93ef76619d9..43c28632963 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type ServiceCtx struct { func (_m *ServiceCtx) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -31,6 +35,10 @@ func (_m *ServiceCtx) Close() error { func (_m *ServiceCtx) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/job/mocks/spawner.go b/core/services/job/mocks/spawner.go index 6866f1fc156..60d36b18fa5 100644 --- a/core/services/job/mocks/spawner.go +++ b/core/services/job/mocks/spawner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type Spawner struct { func (_m *Spawner) ActiveJobs() map[int32]job.Job { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ActiveJobs") + } + var r0 map[int32]job.Job if rf, ok := ret.Get(0).(func() map[int32]job.Job); ok { r0 = rf() @@ -36,6 +40,10 @@ func (_m *Spawner) ActiveJobs() map[int32]job.Job { func (_m *Spawner) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -57,6 +65,10 @@ func (_m *Spawner) CreateJob(jb *job.Job, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateJob") + } + var r0 error if rf, ok := ret.Get(0).(func(*job.Job, ...pg.QOpt) error); ok { r0 = rf(jb, qopts...) @@ -78,6 +90,10 @@ func (_m *Spawner) DeleteJob(jobID int32, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } + var r0 error if rf, ok := ret.Get(0).(func(int32, ...pg.QOpt) error); ok { r0 = rf(jobID, qopts...) @@ -92,6 +108,10 @@ func (_m *Spawner) DeleteJob(jobID int32, qopts ...pg.QOpt) error { func (_m *Spawner) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -108,6 +128,10 @@ func (_m *Spawner) HealthReport() map[string]error { func (_m *Spawner) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -122,6 +146,10 @@ func (_m *Spawner) Name() string { func (_m *Spawner) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -136,6 +164,10 @@ func (_m *Spawner) Ready() error { func (_m *Spawner) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -157,6 +189,10 @@ func (_m *Spawner) StartService(ctx context.Context, spec job.Job, qopts ...pg.Q _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for StartService") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, job.Job, ...pg.QOpt) error); ok { r0 = rf(ctx, spec, qopts...) diff --git a/core/services/job/models.go b/core/services/job/models.go index 05dcab831f1..17bac545be1 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -20,32 +20,34 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "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/keystore/keys/ethkey" "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" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" "github.com/smartcontractkit/chainlink/v2/core/utils/tomlutils" ) const ( + BlockHeaderFeeder Type = (Type)(pipeline.BlockHeaderFeederJobType) + BlockhashStore Type = (Type)(pipeline.BlockhashStoreJobType) + Bootstrap Type = (Type)(pipeline.BootstrapJobType) Cron Type = (Type)(pipeline.CronJobType) DirectRequest Type = (Type)(pipeline.DirectRequestJobType) FluxMonitor Type = (Type)(pipeline.FluxMonitorJobType) - OffchainReporting Type = (Type)(pipeline.OffchainReportingJobType) - OffchainReporting2 Type = (Type)(pipeline.OffchainReporting2JobType) + Gateway Type = (Type)(pipeline.GatewayJobType) Keeper Type = (Type)(pipeline.KeeperJobType) - VRF Type = (Type)(pipeline.VRFJobType) - BlockhashStore Type = (Type)(pipeline.BlockhashStoreJobType) - BlockHeaderFeeder Type = (Type)(pipeline.BlockHeaderFeederJobType) LegacyGasStationServer Type = (Type)(pipeline.LegacyGasStationServerJobType) LegacyGasStationSidecar Type = (Type)(pipeline.LegacyGasStationSidecarJobType) + OffchainReporting Type = (Type)(pipeline.OffchainReportingJobType) + OffchainReporting2 Type = (Type)(pipeline.OffchainReporting2JobType) + Stream Type = (Type)(pipeline.StreamJobType) + VRF Type = (Type)(pipeline.VRFJobType) Webhook Type = (Type)(pipeline.WebhookJobType) - Bootstrap Type = (Type)(pipeline.BootstrapJobType) - Gateway Type = (Type)(pipeline.GatewayJobType) ) //revive:disable:redefines-builtin-id @@ -69,52 +71,55 @@ func (t Type) SchemaVersion() uint32 { var ( requiresPipelineSpec = map[Type]bool{ + BlockHeaderFeeder: false, + BlockhashStore: false, + Bootstrap: false, Cron: true, DirectRequest: true, FluxMonitor: true, - OffchainReporting: false, // bootstrap jobs do not require it - OffchainReporting2: false, // bootstrap jobs do not require it + Gateway: false, Keeper: false, // observationSource is injected in the upkeep executor - VRF: true, - Webhook: true, - BlockhashStore: false, - BlockHeaderFeeder: false, LegacyGasStationServer: false, LegacyGasStationSidecar: false, - Bootstrap: false, - Gateway: false, + OffchainReporting2: false, // bootstrap jobs do not require it + OffchainReporting: false, // bootstrap jobs do not require it + Stream: true, + VRF: true, + Webhook: true, } supportsAsync = map[Type]bool{ + BlockHeaderFeeder: false, + BlockhashStore: false, + Bootstrap: false, Cron: true, DirectRequest: true, FluxMonitor: false, - OffchainReporting: false, - OffchainReporting2: false, + Gateway: false, Keeper: true, - VRF: true, - Webhook: true, - BlockhashStore: false, - BlockHeaderFeeder: false, LegacyGasStationServer: false, LegacyGasStationSidecar: false, - Bootstrap: false, - Gateway: false, + OffchainReporting2: false, + OffchainReporting: false, + Stream: true, + VRF: true, + Webhook: true, } schemaVersions = map[Type]uint32{ + BlockHeaderFeeder: 1, + BlockhashStore: 1, + Bootstrap: 1, Cron: 1, DirectRequest: 1, FluxMonitor: 1, - OffchainReporting: 1, - OffchainReporting2: 1, + Gateway: 1, Keeper: 1, - VRF: 1, - Webhook: 1, - BlockhashStore: 1, - BlockHeaderFeeder: 1, LegacyGasStationServer: 1, LegacyGasStationSidecar: 1, - Bootstrap: 1, - Gateway: 1, + OffchainReporting2: 1, + OffchainReporting: 1, + Stream: 1, + VRF: 1, + Webhook: 1, } ) @@ -151,6 +156,8 @@ type Job struct { GatewaySpecID *int32 EALSpec *EALSpec EALSpecID *int32 + LiquidityBalancerSpec *LiquidityBalancerSpec + LiquidityBalancerSpecID *int32 PipelineSpecID int32 PipelineSpec *pipeline.Spec JobSpecErrors []SpecError @@ -229,7 +236,7 @@ func (pr *PipelineRun) SetID(value string) error { if err != nil { return err } - pr.ID = int64(ID) + pr.ID = ID return nil } @@ -237,7 +244,6 @@ func (pr *PipelineRun) SetID(value string) error { type OCROracleSpec struct { ID int32 `toml:"-"` ContractAddress ethkey.EIP55Address `toml:"contractAddress"` - P2PBootstrapPeers pq.StringArray `toml:"p2pBootstrapPeers" db:"p2p_bootstrap_peers"` P2PV2Bootstrappers pq.StringArray `toml:"p2pv2Bootstrappers" db:"p2pv2_bootstrappers"` IsBootstrapPeer bool `toml:"isBootstrapPeer"` EncryptedOCRKeyBundleID *models.Sha256Hash `toml:"keyBundleID"` @@ -247,7 +253,7 @@ type OCROracleSpec struct { ContractConfigTrackerSubscribeInterval models.Interval `toml:"contractConfigTrackerSubscribeInterval"` ContractConfigTrackerPollInterval models.Interval `toml:"contractConfigTrackerPollInterval"` ContractConfigConfirmations uint16 `toml:"contractConfigConfirmations"` - EVMChainID *utils.Big `toml:"evmChainID" db:"evm_chain_id"` + EVMChainID *big.Big `toml:"evmChainID" db:"evm_chain_id"` DatabaseTimeout *models.Interval `toml:"databaseTimeout"` ObservationGracePeriod *models.Interval `toml:"observationGracePeriod"` ContractTransmitterTransmitTimeout *models.Interval `toml:"contractTransmitterTransmitTimeout"` @@ -271,7 +277,8 @@ func (s *OCROracleSpec) SetID(value string) error { return nil } -// JSONConfig is a Go mapping for JSON based database properties. +// JSONConfig is a map for config properties which are encoded as JSON in the database by implementing +// sql.Scanner and driver.Valuer. type JSONConfig map[string]interface{} // Bytes returns the raw bytes @@ -359,7 +366,7 @@ func (s *OCR2OracleSpec) RelayID() (relay.ID, error) { func (s *OCR2OracleSpec) getChainID() (relay.ChainID, error) { if s.ChainID != "" { - return relay.ChainID(s.ChainID), nil + return s.ChainID, nil } // backward compatible job spec return s.getChainIdFromRelayConfig() @@ -373,13 +380,13 @@ func (s *OCR2OracleSpec) getChainIdFromRelayConfig() (relay.ChainID, error) { } switch t := v.(type) { case string: - return relay.ChainID(t), nil + return t, nil case int, int64, int32: - return relay.ChainID(fmt.Sprintf("%d", v)), nil + return fmt.Sprintf("%d", v), nil case float64: // backward compatibility with JSONConfig.EVMChainID i := int64(t) - return relay.ChainID(strconv.FormatInt(i, 10)), nil + return strconv.FormatInt(i, 10), nil default: return "", fmt.Errorf("unable to parse chainID: unexpected type %T", t) @@ -435,7 +442,7 @@ type DirectRequestSpec struct { MinIncomingConfirmations clnull.Uint32 `toml:"minIncomingConfirmations"` Requesters models.AddressCollection `toml:"requesters"` MinContractPayment *commonassets.Link `toml:"minContractPaymentLinkJuels"` - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` CreatedAt time.Time `toml:"-"` UpdatedAt time.Time `toml:"-"` } @@ -476,9 +483,9 @@ type FluxMonitorSpec struct { DrumbeatRandomDelay time.Duration DrumbeatEnabled bool MinPayment *commonassets.Link - EVMChainID *utils.Big `toml:"evmChainID"` - CreatedAt time.Time `toml:"-"` - UpdatedAt time.Time `toml:"-"` + EVMChainID *big.Big `toml:"evmChainID"` + CreatedAt time.Time `toml:"-"` + UpdatedAt time.Time `toml:"-"` } type KeeperSpec struct { @@ -486,7 +493,7 @@ type KeeperSpec struct { ContractAddress ethkey.EIP55Address `toml:"contractAddress"` MinIncomingConfirmations *uint32 `toml:"minIncomingConfirmations"` FromAddress ethkey.EIP55Address `toml:"fromAddress"` - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` CreatedAt time.Time `toml:"-"` UpdatedAt time.Time `toml:"-"` } @@ -501,6 +508,9 @@ type VRFSpec struct { // for fulfilling requests. If set to true, batchCoordinatorAddress must be set in // the job spec. BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` + // CustomRevertsPipelineEnabled indicates to the vrf job to run the + // custom reverted txns pipeline along with VRF listener + CustomRevertsPipelineEnabled bool `toml:"customRevertsPipelineEnabled"` // BatchFulfillmentGasMultiplier is used to determine the final gas estimate for the batch // fulfillment. BatchFulfillmentGasMultiplier tomlutils.Float64 `toml:"batchFulfillmentGasMultiplier"` @@ -513,7 +523,7 @@ type VRFSpec struct { CoordinatorAddress ethkey.EIP55Address `toml:"coordinatorAddress"` PublicKey secp256k1.PublicKey `toml:"publicKey"` MinIncomingConfirmations uint32 `toml:"minIncomingConfirmations"` - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` PollPeriod time.Duration `toml:"pollPeriod"` // For v2 jobs RequestedConfsDelay int64 `toml:"requestedConfsDelay"` // For v2 jobs. Optional, defaults to 0 if not provided. @@ -587,7 +597,7 @@ type BlockhashStoreSpec struct { RunTimeout time.Duration `toml:"runTimeout"` // EVMChainID defines the chain ID for monitoring and storing of blockhashes. - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` // FromAddress is the sender address that should be used to store blockhashes. FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` @@ -636,7 +646,7 @@ type BlockHeaderFeederSpec struct { RunTimeout time.Duration `toml:"runTimeout"` // EVMChainID defines the chain ID for monitoring and storing of blockhashes. - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` // FromAddress is the sender address that should be used to store blockhashes. FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` @@ -663,11 +673,11 @@ type LegacyGasStationServerSpec struct { ForwarderAddress ethkey.EIP55Address `toml:"forwarderAddress"` // EVMChainID defines the chain ID from which the meta-transaction request originates. - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` // CCIPChainSelector is the CCIP chain selector that corresponds to EVMChainID param. // This selector is equivalent to (source) chainID specified in SendTransaction request - CCIPChainSelector *utils.Big `toml:"ccipChainSelector"` + CCIPChainSelector *big.Big `toml:"ccipChainSelector"` // FromAddress is the sender address that should be used to send meta-transactions FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` @@ -700,10 +710,10 @@ type LegacyGasStationSidecarSpec struct { RunTimeout time.Duration `toml:"runTimeout"` // EVMChainID defines the chain ID for the on-chain events tracked by sidecar - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` // CCIPChainSelector is the CCIP chain selector that corresponds to EVMChainID param - CCIPChainSelector *utils.Big `toml:"ccipChainSelector"` + CCIPChainSelector *big.Big `toml:"ccipChainSelector"` // CreatedAt is the time this job was created. CreatedAt time.Time `toml:"-"` @@ -773,7 +783,7 @@ type EALSpec struct { ForwarderAddress ethkey.EIP55Address `toml:"forwarderAddress"` // EVMChainID defines the chain ID from which the meta-transaction request originates. - EVMChainID *utils.Big `toml:"evmChainID"` + EVMChainID *big.Big `toml:"evmChainID"` // FromAddress is the sender address that should be used to send meta-transactions FromAddresses []ethkey.EIP55Address `toml:"fromAddresses"` @@ -793,3 +803,9 @@ type EALSpec struct { // UpdatedAt is the time this job was last updated. UpdatedAt time.Time `toml:"-"` } + +type LiquidityBalancerSpec struct { + ID int32 + + LiquidityBalancerConfig string `toml:"liquidityBalancerConfig" db:"liquidity_balancer_config"` +} diff --git a/core/services/job/models_test.go b/core/services/job/models_test.go index 277f0d7eb29..fa15e3b1b22 100644 --- a/core/services/job/models_test.go +++ b/core/services/job/models_test.go @@ -1,10 +1,20 @@ package job import ( + _ "embed" "reflect" "testing" + "time" + "github.com/pelletier/go-toml/v2" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" + + "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) { @@ -30,7 +40,7 @@ func TestOCR2OracleSpec_RelayIdentifier(t *testing.T) { Relay: relay.EVM, ChainID: "1", }, - want: relay.ID{Network: relay.EVM, ChainID: relay.ChainID("1")}, + want: relay.ID{Network: relay.EVM, ChainID: "1"}, }, { name: "evm implicitly configured", @@ -38,7 +48,7 @@ func TestOCR2OracleSpec_RelayIdentifier(t *testing.T) { Relay: relay.EVM, RelayConfig: map[string]any{"chainID": 1}, }, - want: relay.ID{Network: relay.EVM, ChainID: relay.ChainID("1")}, + want: relay.ID{Network: relay.EVM, ChainID: "1"}, }, { name: "evm implicitly configured with bad value", @@ -71,3 +81,183 @@ func TestOCR2OracleSpec_RelayIdentifier(t *testing.T) { }) } } + +var ( + //go:embed testdata/compact.toml + compact string + //go:embed testdata/pretty.toml + pretty string +) + +func TestOCR2OracleSpec(t *testing.T) { + val := OCR2OracleSpec{ + Relay: relay.EVM, + PluginType: types.Median, + ContractID: "foo", + OCRKeyBundleID: null.StringFrom("bar"), + TransmitterID: null.StringFrom("baz"), + ContractConfigConfirmations: 1, + ContractConfigTrackerPollInterval: *models.NewInterval(time.Second), + RelayConfig: map[string]interface{}{ + "chainID": 1337, + "fromBlock": 42, + "chainReader": evmtypes.ChainReaderConfig{ + Contracts: map[string]evmtypes.ChainContractReader{ + "median": { + ContractABI: `[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "round", + "type": "uint8" + } + ], + "name": "RoundRequested", + "type": "event" + }, + { + "inputs": [], + "name": "latestTransmissionDetails", + "outputs": [ + { + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "round", + "type": "uint8" + }, + { + "internalType": "int192", + "name": "latestAnswer_", + "type": "int192" + }, + { + "internalType": "uint64", + "name": "latestTimestamp_", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + } +] +`, + Configs: map[string]*evmtypes.ChainReaderDefinition{ + "LatestTransmissionDetails": { + ChainSpecificName: "latestTransmissionDetails", + OutputModifications: codec.ModifiersConfig{ + &codec.EpochToTimeModifierConfig{ + Fields: []string{"LatestTimestamp_"}, + }, + &codec.RenameModifierConfig{ + Fields: map[string]string{ + "LatestAnswer_": "LatestAnswer", + "LatestTimestamp_": "LatestTimestamp", + }, + }, + }, + }, + "LatestRoundRequested": { + ChainSpecificName: "RoundRequested", + ReadType: evmtypes.Event, + }, + }, + }, + }, + }, + "codec": evmtypes.CodecConfig{ + Configs: map[string]evmtypes.ChainCodecConfig{ + "MedianReport": { + TypeABI: `[ + { + "Name": "Timestamp", + "Type": "uint32" + }, + { + "Name": "Observers", + "Type": "bytes32" + }, + { + "Name": "Observations", + "Type": "int192[]" + }, + { + "Name": "JuelsPerFeeCoin", + "Type": "int192" + } +] +`, + }, + }, + }, + }, + PluginConfig: map[string]interface{}{"juelsPerFeeCoinSource": ` // data source 1 + ds1 [type=bridge name="%s"]; + ds1_parse [type=jsonparse path="data"]; + ds1_multiply [type=multiply times=2]; + + // data source 2 + ds2 [type=http method=GET url="%s"]; + ds2_parse [type=jsonparse path="data"]; + ds2_multiply [type=multiply times=2]; + + ds1 -> ds1_parse -> ds1_multiply -> answer1; + ds2 -> ds2_parse -> ds2_multiply -> answer1; + + answer1 [type=median index=0]; +`, + }, + } + + t.Run("marshal", func(t *testing.T) { + gotB, err := toml.Marshal(val) + require.NoError(t, err) + t.Log("marshaled:", string(gotB)) + require.Equal(t, compact, string(gotB)) + }) + + t.Run("round-trip", func(t *testing.T) { + var gotVal OCR2OracleSpec + require.NoError(t, toml.Unmarshal([]byte(compact), &gotVal)) + gotB, err := toml.Marshal(gotVal) + require.NoError(t, err) + require.Equal(t, compact, string(gotB)) + t.Run("pretty", func(t *testing.T) { + var gotVal OCR2OracleSpec + require.NoError(t, toml.Unmarshal([]byte(pretty), &gotVal)) + gotB, err := toml.Marshal(gotVal) + require.NoError(t, err) + t.Log("marshaled compact:", string(gotB)) + require.Equal(t, compact, string(gotB)) + }) + }) +} diff --git a/core/services/job/orm.go b/core/services/job/orm.go index c5f533c3d20..82c6be2963c 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/null" @@ -32,7 +33,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -52,7 +52,7 @@ type ORM interface { FindJobTx(ctx context.Context, id int32) (Job, error) FindJob(ctx context.Context, id int32) (Job, error) FindJobByExternalJobID(uuid uuid.UUID, qopts ...pg.QOpt) (Job, error) - FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils.Big, qopts ...pg.QOpt) (int32, error) + FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (int32, error) FindOCR2JobIDByAddress(contractID string, feedID *common.Hash, qopts ...pg.QOpt) (int32, error) FindJobIDsWithBridge(name string) ([]int32, error) DeleteJob(id int32, qopts ...pg.QOpt) error @@ -212,10 +212,10 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { return errors.Errorf("a job with contract address %s already exists for chain ID %s", jb.OCROracleSpec.ContractAddress, newChainID) } - sql := `INSERT INTO ocr_oracle_specs (contract_address, p2p_bootstrap_peers, p2pv2_bootstrappers, is_bootstrap_peer, encrypted_ocr_key_bundle_id, transmitter_address, + sql := `INSERT INTO ocr_oracle_specs (contract_address, p2pv2_bootstrappers, is_bootstrap_peer, encrypted_ocr_key_bundle_id, transmitter_address, observation_timeout, blockchain_timeout, contract_config_tracker_subscribe_interval, contract_config_tracker_poll_interval, contract_config_confirmations, evm_chain_id, created_at, updated_at, database_timeout, observation_grace_period, contract_transmitter_transmit_timeout) - VALUES (:contract_address, :p2p_bootstrap_peers, :p2pv2_bootstrappers, :is_bootstrap_peer, :encrypted_ocr_key_bundle_id, :transmitter_address, + VALUES (:contract_address, :p2pv2_bootstrappers, :is_bootstrap_peer, :encrypted_ocr_key_bundle_id, :transmitter_address, :observation_timeout, :blockchain_timeout, :contract_config_tracker_subscribe_interval, :contract_config_tracker_poll_interval, :contract_config_confirmations, :evm_chain_id, NOW(), NOW(), :database_timeout, :observation_grace_period, :contract_transmitter_transmit_timeout) RETURNING id;` @@ -326,14 +326,14 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { evm_chain_id, from_addresses, poll_period, requested_confs_delay, request_timeout, chunk_size, batch_coordinator_address, batch_fulfillment_enabled, batch_fulfillment_gas_multiplier, backoff_initial_delay, backoff_max_delay, gas_lane_price, - vrf_owner_address, + vrf_owner_address, custom_reverts_pipeline_enabled, created_at, updated_at) VALUES ( :coordinator_address, :public_key, :min_incoming_confirmations, :evm_chain_id, :from_addresses, :poll_period, :requested_confs_delay, :request_timeout, :chunk_size, :batch_coordinator_address, :batch_fulfillment_enabled, :batch_fulfillment_gas_multiplier, :backoff_initial_delay, :backoff_max_delay, :gas_lane_price, - :vrf_owner_address, + :vrf_owner_address, :custom_reverts_pipeline_enabled, NOW(), NOW()) RETURNING id;` @@ -440,6 +440,8 @@ func (o *orm) CreateJob(jb *Job, qopts ...pg.QOpt) error { return errors.Wrap(err, "failed to create GatewaySpec for jobSpec") } jb.GatewaySpecID = &specID + case Stream: + // 'stream' type has no associated spec, nothing to do here default: o.lggr.Panicf("Unsupported jb.Type: %v", jb.Type) } @@ -695,7 +697,7 @@ func (o *orm) FindJobs(offset, limit int) (jobs []Job, count int, err error) { return nil }) - return jobs, int(count), err + return jobs, count, err } func LoadDefaultVRFPollPeriod(vrfs VRFSpec) *VRFSpec { @@ -832,7 +834,7 @@ func (o *orm) FindJobByExternalJobID(externalJobID uuid.UUID, qopts ...pg.QOpt) } // FindJobIDByAddress - finds a job id by contract address. Currently only OCR and FM jobs are supported -func (o *orm) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *utils.Big, qopts ...pg.QOpt) (jobID int32, err error) { +func (o *orm) FindJobIDByAddress(address ethkey.EIP55Address, evmChainID *big.Big, qopts ...pg.QOpt) (jobID int32, err error) { q := o.q.WithOpts(qopts...) err = q.Transaction(func(tx pg.Queryer) error { stmt := ` diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index eb6af3607f3..fb671982ec5 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -14,6 +14,7 @@ import ( "time" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/pelletier/go-toml" "github.com/pkg/errors" "github.com/shopspring/decimal" @@ -22,6 +23,10 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -39,11 +44,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "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/srvctest" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" ) @@ -58,19 +61,16 @@ func TestRunner(t *testing.T) { require.NoError(t, keyStore.OCR().Add(cltest.DefaultOCRKey)) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) - c.P2P.V1.DefaultBootstrapPeers = &[]string{ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", - "/dns4/chain.link/tcp/1235/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", - } + 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() require.NoError(t, err) kbid := models.MustSha256HashFromHex(kb.ID()) c.OCR.KeyBundleID = &kbid taddress := ethkey.EIP55AddressFromAddress(transmitterAddress) c.OCR.TransmitterAddress = &taddress - c.OCR2.DatabaseTimeout = models.MustNewDuration(time.Second) - c.OCR2.ContractTransmitterTransmitTimeout = models.MustNewDuration(time.Second) + c.OCR2.DatabaseTimeout = commonconfig.MustNewDuration(time.Second) + c.OCR2.ContractTransmitterTransmitTimeout = commonconfig.MustNewDuration(time.Second) c.Insecure.OCRDevelopmentMode = ptr(true) }) @@ -78,7 +78,10 @@ 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()) + require.NoError(t, pipelineORM.Start(ctx)) + t.Cleanup(func() { assert.NoError(t, pipelineORM.Close()) }) btORM := bridges.NewORM(db, logger.TestLogger(t), config.Database()) relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, Client: ethClient, GeneralConfig: config, KeyStore: ethKeyStore}) legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) @@ -86,11 +89,11 @@ func TestRunner(t *testing.T) { runner := pipeline.NewRunner(pipelineORM, btORM, config.JobPipeline(), config.WebServer(), legacyChains, nil, nil, logger.TestLogger(t), c, c) jobORM := NewTestORM(t, db, pipelineORM, btORM, keyStore, config.Database()) + t.Cleanup(func() { assert.NoError(t, jobORM.Close()) }) _, placeHolderAddress := cltest.MustInsertRandomKey(t, keyStore.Eth()) - require.NoError(t, runner.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, runner.Close()) }) + servicetest.Run(t, runner) t.Run("gets the election result winner", func(t *testing.T) { var httpURL string @@ -449,8 +452,7 @@ answer1 [type=median index=0]; _, err = keyStore.P2P().Create() assert.NoError(t, err) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, pw.Close()) }) + servicetest.Run(t, pw) sd := ocr.NewDelegate( db, jobORM, @@ -461,7 +463,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, mailboxtest.NewMonitor(t)), ) _, err = sd.ServicesForSpec(jb) require.NoError(t, err) @@ -484,8 +486,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, pw.Close()) }) + servicetest.Run(t, pw) sd := ocr.NewDelegate( db, jobORM, @@ -496,7 +497,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, mailboxtest.NewMonitor(t)), ) _, err = sd.ServicesForSpec(jb) require.NoError(t, err) @@ -513,8 +514,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, pw.Close()) }) + servicetest.Run(t, pw) sd := ocr.NewDelegate( db, jobORM, @@ -525,7 +525,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, mailboxtest.NewMonitor(t)), ) _, err = sd.ServicesForSpec(jb) require.NoError(t, err) @@ -545,7 +545,8 @@ answer1 [type=median index=0]; for _, tc := range testCases { config = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.OCR.CaptureEATelemetry = ptr(tc.specCaptureEATelemetry) }) @@ -568,8 +569,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, pw.Close()) }) + servicetest.Run(t, pw) sd := ocr.NewDelegate( db, jobORM, @@ -580,7 +580,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, mailboxtest.NewMonitor(t)), ) jb.OCROracleSpec.CaptureEATelemetry = tc.jbCaptureEATelemetry @@ -613,8 +613,7 @@ answer1 [type=median index=0]; lggr := logger.TestLogger(t) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, config.P2P(), config.OCR(), config.Database(), db, lggr) - require.NoError(t, pw.Start(testutils.Context(t))) - t.Cleanup(func() { assert.NoError(t, pw.Close()) }) + servicetest.Run(t, pw) sd := ocr.NewDelegate( db, jobORM, @@ -625,7 +624,7 @@ answer1 [type=median index=0]; legacyChains, lggr, config.Database(), - srvctest.Start(t, utils.NewMailboxMonitor(t.Name())), + servicetest.Run(t, mailboxtest.NewMonitor(t)), ) services, err := sd.ServicesForSpec(*jb) require.NoError(t, err) @@ -748,7 +747,7 @@ func TestRunner_Success_Callback_AsyncJob(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { t := true c.JobPipeline.ExternalInitiatorsEnabled = &t - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(10 * time.Millisecond) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient, cltest.UseRealExternalInitiatorManager) @@ -927,7 +926,7 @@ func TestRunner_Error_Callback_AsyncJob(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { t := true c.JobPipeline.ExternalInitiatorsEnabled = &t - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(10 * time.Millisecond) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient, cltest.UseRealExternalInitiatorManager) diff --git a/core/services/job/spawner.go b/core/services/job/spawner.go index 5ed017b8743..1d44cedaad9 100644 --- a/core/services/job/spawner.go +++ b/core/services/job/spawner.go @@ -12,10 +12,10 @@ import ( "github.com/jmoiron/sqlx" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name Spawner --output ./mocks/ --case=underscore diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 0ad76491438..3e8ccbab848 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -13,6 +13,9 @@ 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/utils" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" "github.com/smartcontractkit/chainlink/v2/core/bridges" mocklp "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" @@ -28,13 +31,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "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/core/services/srvctest" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -128,7 +128,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceA2 := mocks.NewServiceCtx(t) serviceA1.On("Start", mock.Anything).Return(nil).Once() serviceA2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventuallyA.ItHappened() }) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) dA := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, make(chan struct{}), dA} @@ -187,7 +187,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { lggr := logger.TestLogger(t) orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ @@ -221,7 +221,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { lggr := logger.TestLogger(t) orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.Database(), config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db, lggr, config.Database()), keyStore, config.Database()) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config.Database(), mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ @@ -284,10 +284,9 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { chain := evmtest.MustGetDefaultChain(t, legacyChains) evmRelayer, err := evmrelayer.NewRelayer(lggr, chain, evmrelayer.RelayerOpts{ - DB: db, - QConfig: testopts.GeneralConfig.Database(), - CSAETHKeystore: keyStore, - EventBroadcaster: pg.NewNullEventBroadcaster(), + DB: db, + QConfig: testopts.GeneralConfig.Database(), + CSAETHKeystore: keyStore, }) assert.NoError(t, err) @@ -299,13 +298,13 @@ 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, lggr, config.Database()), keyStore, config.Database()) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) processConfig := plugins.NewRegistrarConfig(loop.GRPCOpts{}, func(name string) (*plugins.RegisteredLoop, error) { return nil, nil }) ocr2DelegateConfig := ocr2.NewDelegateConfig(config.OCR2(), config.Mercury(), config.Threshold(), config.Insecure(), config.JobPipeline(), config.Database(), processConfig) d := ocr2.NewDelegate(nil, orm, nil, nil, nil, nil, monitoringEndpoint, legacyChains, lggr, ocr2DelegateConfig, - keyStore.OCR2(), keyStore.DKGSign(), keyStore.DKGEncrypt(), ethKeyStore, testRelayGetter, mailMon, nil) + keyStore.OCR2(), keyStore.DKGSign(), keyStore.DKGEncrypt(), ethKeyStore, testRelayGetter, mailMon) delegateOCR2 := &delegate{jobOCR2VRF.Type, []job.ServiceCtx{}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ diff --git a/core/services/job/testdata/compact.toml b/core/services/job/testdata/compact.toml new file mode 100644 index 00000000000..9f0f54027d2 --- /dev/null +++ b/core/services/job/testdata/compact.toml @@ -0,0 +1,34 @@ +contractID = 'foo' +relay = 'evm' +chainID = '' +p2pv2Bootstrappers = [] +ocrKeyBundleID = 'bar' +monitoringEndpoint = '' +transmitterID = 'baz' +blockchainTimeout = '0s' +contractConfigTrackerPollInterval = '1s' +contractConfigConfirmations = 1 +pluginType = 'median' +captureEATelemetry = false +captureAutomationCustomTelemetry = false + +[relayConfig] +chainID = 1337 +fromBlock = 42 + +[relayConfig.chainReader] +[relayConfig.chainReader.contracts] +[relayConfig.chainReader.contracts.median] +contractABI = "[\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"requester\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"bytes32\",\n \"name\": \"configDigest\",\n \"type\": \"bytes32\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint32\",\n \"name\": \"epoch\",\n \"type\": \"uint32\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint8\",\n \"name\": \"round\",\n \"type\": \"uint8\"\n }\n ],\n \"name\": \"RoundRequested\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [],\n \"name\": \"latestTransmissionDetails\",\n \"outputs\": [\n {\n \"internalType\": \"bytes32\",\n \"name\": \"configDigest\",\n \"type\": \"bytes32\"\n },\n {\n \"internalType\": \"uint32\",\n \"name\": \"epoch\",\n \"type\": \"uint32\"\n },\n {\n \"internalType\": \"uint8\",\n \"name\": \"round\",\n \"type\": \"uint8\"\n },\n {\n \"internalType\": \"int192\",\n \"name\": \"latestAnswer_\",\n \"type\": \"int192\"\n },\n {\n \"internalType\": \"uint64\",\n \"name\": \"latestTimestamp_\",\n \"type\": \"uint64\"\n }\n ],\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n }\n]\n" + +[relayConfig.chainReader.contracts.median.configs] +LatestRoundRequested = "{\n \"chainSpecificName\": \"RoundRequested\",\n \"readType\": \"event\"\n}\n" +LatestTransmissionDetails = "{\n \"chainSpecificName\": \"latestTransmissionDetails\",\n \"outputModifications\": [\n {\n \"Fields\": [\n \"LatestTimestamp_\"\n ],\n \"Type\": \"epoch to time\"\n },\n {\n \"Fields\": {\n \"LatestAnswer_\": \"LatestAnswer\",\n \"LatestTimestamp_\": \"LatestTimestamp\"\n },\n \"Type\": \"rename\"\n }\n ]\n}\n" + +[relayConfig.codec] +[relayConfig.codec.configs] +[relayConfig.codec.configs.MedianReport] +typeABI = "[\n {\n \"Name\": \"Timestamp\",\n \"Type\": \"uint32\"\n },\n {\n \"Name\": \"Observers\",\n \"Type\": \"bytes32\"\n },\n {\n \"Name\": \"Observations\",\n \"Type\": \"int192[]\"\n },\n {\n \"Name\": \"JuelsPerFeeCoin\",\n \"Type\": \"int192\"\n }\n]\n" + +[pluginConfig] +juelsPerFeeCoinSource = " // data source 1\n ds1 [type=bridge name=\"%s\"];\n ds1_parse [type=jsonparse path=\"data\"];\n ds1_multiply [type=multiply times=2];\n\n // data source 2\n ds2 [type=http method=GET url=\"%s\"];\n ds2_parse [type=jsonparse path=\"data\"];\n ds2_multiply [type=multiply times=2];\n\n ds1 -> ds1_parse -> ds1_multiply -> answer1;\n ds2 -> ds2_parse -> ds2_multiply -> answer1;\n\n answer1 [type=median index=0];\n" diff --git a/core/services/job/testdata/pretty.toml b/core/services/job/testdata/pretty.toml new file mode 100644 index 00000000000..88bacff7db2 --- /dev/null +++ b/core/services/job/testdata/pretty.toml @@ -0,0 +1,149 @@ +relay = "evm" +pluginType = "median" +contractID = "foo" +ocrKeyBundleID = "bar" +transmitterID = "baz" +contractConfigConfirmations = 1 +contractConfigTrackerPollInterval = "1s" + +[relayConfig] +chainID = 1337 +fromBlock = 42 + +[relayConfig.chainReader.contracts.median] +contractABI = ''' +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "round", + "type": "uint8" + } + ], + "name": "RoundRequested", + "type": "event" + }, + { + "inputs": [], + "name": "latestTransmissionDetails", + "outputs": [ + { + "internalType": "bytes32", + "name": "configDigest", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "epoch", + "type": "uint32" + }, + { + "internalType": "uint8", + "name": "round", + "type": "uint8" + }, + { + "internalType": "int192", + "name": "latestAnswer_", + "type": "int192" + }, + { + "internalType": "uint64", + "name": "latestTimestamp_", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + } +] +''' + +[relayConfig.chainReader.contracts.median.configs] +LatestRoundRequested = ''' +{ + "chainSpecificName": "RoundRequested", + "readType": "event" +} +''' +LatestTransmissionDetails = ''' +{ + "chainSpecificName": "latestTransmissionDetails", + "outputModifications": [ + { + "Fields": [ + "LatestTimestamp_" + ], + "Type": "epoch to time" + }, + { + "Fields": { + "LatestAnswer_": "LatestAnswer", + "LatestTimestamp_": "LatestTimestamp" + }, + "Type": "rename" + } + ] +} +''' + +[relayConfig.codec.configs.MedianReport] +typeABI = ''' +[ + { + "Name": "Timestamp", + "Type": "uint32" + }, + { + "Name": "Observers", + "Type": "bytes32" + }, + { + "Name": "Observations", + "Type": "int192[]" + }, + { + "Name": "JuelsPerFeeCoin", + "Type": "int192" + } +] +''' + +[pluginConfig] +juelsPerFeeCoinSource = """ + // data source 1 + ds1 [type=bridge name="%s"]; + ds1_parse [type=jsonparse path="data"]; + ds1_multiply [type=multiply times=2]; + + // data source 2 + ds2 [type=http method=GET url="%s"]; + ds2_parse [type=jsonparse path="data"]; + ds2_multiply [type=multiply times=2]; + + ds1 -> ds1_parse -> ds1_multiply -> answer1; + ds2 -> ds2_parse -> ds2_multiply -> answer1; + + answer1 [type=median index=0]; +""" \ No newline at end of file diff --git a/core/services/job/validate.go b/core/services/job/validate.go index 8f559fdb02d..f108031f72e 100644 --- a/core/services/job/validate.go +++ b/core/services/job/validate.go @@ -12,20 +12,21 @@ var ( ErrInvalidJobType = errors.New("invalid job type") ErrInvalidSchemaVersion = errors.New("invalid schema version") jobTypes = map[Type]struct{}{ + BlockHeaderFeeder: {}, + BlockhashStore: {}, + Bootstrap: {}, Cron: {}, DirectRequest: {}, FluxMonitor: {}, - OffchainReporting: {}, - OffchainReporting2: {}, - Keeper: {}, - VRF: {}, - Webhook: {}, - BlockhashStore: {}, - Bootstrap: {}, - BlockHeaderFeeder: {}, Gateway: {}, + Keeper: {}, LegacyGasStationServer: {}, LegacyGasStationSidecar: {}, + OffchainReporting2: {}, + OffchainReporting: {}, + Stream: {}, + VRF: {}, + Webhook: {}, } ) @@ -63,6 +64,7 @@ func ValidateSpec(ts string) (Type, error) { if jb.Pipeline.RequiresPreInsert() && !jb.Type.SupportsAsync() { return "", errors.Errorf("async=true tasks are not supported for %v", jb.Type) } + // spec.CustomRevertsPipelineEnabled == false, default is custom reverted txns pipeline disabled if strings.Contains(ts, "<{}>") { return "", errors.Errorf("'<{}>' syntax is not supported. Please use \"{}\" instead") diff --git a/core/services/keeper/delegate.go b/core/services/keeper/delegate.go index 0dbf584c56f..4418bea670a 100644 --- a/core/services/keeper/delegate.go +++ b/core/services/keeper/delegate.go @@ -5,12 +5,12 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "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" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // To make sure Delegate struct implements job.Delegate interface @@ -22,7 +22,7 @@ type Delegate struct { jrm job.ORM pr pipeline.Runner legacyChains legacyevm.LegacyChainContainer - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } // NewDelegate is the constructor of Delegate @@ -32,7 +32,7 @@ func NewDelegate( pr pipeline.Runner, logger logger.Logger, legacyChains legacyevm.LegacyChainContainer, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, ) *Delegate { return &Delegate{ logger: logger, diff --git a/core/services/keeper/integration_test.go b/core/services/keeper/integration_test.go index 29a0b68702d..af95788029f 100644 --- a/core/services/keeper/integration_test.go +++ b/core/services/keeper/integration_test.go @@ -16,9 +16,11 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers/link_token_interface" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/basic_upkeep_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_logic1_3" @@ -35,8 +37,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" webpresenters "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -238,8 +238,8 @@ func TestKeeperEthIntegration(t *testing.T) { // setup app config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 - c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps - c.Keeper.Registry.SyncInterval = models.MustNewDuration(24 * time.Hour) // disable full sync ticker for test + c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps + c.Keeper.Registry.SyncInterval = commonconfig.MustNewDuration(24 * time.Hour) // disable full sync ticker for test c.Keeper.TurnLookBack = ptr[int64](0) // testing doesn't need to do far look back @@ -396,8 +396,8 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.Feature.LogPoller = ptr(true) c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) - c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps - c.Keeper.Registry.SyncInterval = models.MustNewDuration(24 * time.Hour) // disable full sync ticker for test + c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps + c.Keeper.Registry.SyncInterval = commonconfig.MustNewDuration(24 * time.Hour) // disable full sync ticker for test c.Keeper.TurnLookBack = ptr[int64](0) // testing doesn't need to do far look back @@ -405,7 +405,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) // disable reorg protection for this test c.EVM[0].HeadTracker.MaxBufferSize = ptr[uint32](100) // helps prevent missed heads c.EVM[0].Transactions.ForwardersEnabled = ptr(true) // Enable Operator Forwarder flow - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) scopedConfig := evmtest.NewChainScopedConfig(t, config) korm := keeper.NewORM(db, logger.TestLogger(t), scopedConfig.Database()) @@ -414,7 +414,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { require.NoError(t, app.Start(testutils.Context(t))) forwarderORM := forwarders.NewORM(db, logger.TestLogger(t), config.Database()) - chainID := utils.Big(*backend.ConfiguredChainID()) + chainID := ubig.Big(*backend.ConfiguredChainID()) _, err = forwarderORM.CreateForwarder(fwdrAddress, chainID) require.NoError(t, err) @@ -431,7 +431,7 @@ func TestKeeperForwarderEthIntegration(t *testing.T) { KeeperSpec: &job.KeeperSpec{ FromAddress: nodeAddressEIP55, ContractAddress: regAddrEIP55, - EVMChainID: (*utils.Big)(testutils.SimulatedChainID), + EVMChainID: (*ubig.Big)(testutils.SimulatedChainID), }, SchemaVersion: 1, ForwardingAllowed: true, @@ -541,9 +541,9 @@ func TestMaxPerformDataSize(t *testing.T) { // setup app config, db := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps - c.Keeper.Registry.SyncInterval = models.MustNewDuration(24 * time.Hour) // disable full sync ticker for test - c.Keeper.Registry.MaxPerformDataSize = ptr(uint32(maxPerformDataSize)) // set the max perform data size + c.Keeper.MaxGracePeriod = ptr[int64](0) // avoid waiting to re-submit for upkeeps + c.Keeper.Registry.SyncInterval = commonconfig.MustNewDuration(24 * time.Hour) // disable full sync ticker for test + c.Keeper.Registry.MaxPerformDataSize = ptr(uint32(maxPerformDataSize)) // set the max perform data size c.Keeper.TurnLookBack = ptr[int64](0) // testing doesn't need to do far look back diff --git a/core/services/keeper/models.go b/core/services/keeper/models.go index fd5538b6047..fe034bcc505 100644 --- a/core/services/keeper/models.go +++ b/core/services/keeper/models.go @@ -8,9 +8,10 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type KeeperIndexMap map[ethkey.EIP55Address]int32 @@ -34,7 +35,7 @@ type UpkeepRegistration struct { LastRunBlockHeight int64 RegistryID int64 Registry Registry - UpkeepID *utils.Big + UpkeepID *big.Big LastKeeperIndex null.Int64 PositioningConstant int32 } @@ -60,16 +61,16 @@ func (upkeep UpkeepRegistration) PrettyID() string { return NewUpkeepIdentifier(upkeep.UpkeepID).String() } -func NewUpkeepIdentifier(i *utils.Big) *UpkeepIdentifier { +func NewUpkeepIdentifier(i *big.Big) *UpkeepIdentifier { val := UpkeepIdentifier(*i) return &val } -type UpkeepIdentifier utils.Big +type UpkeepIdentifier big.Big // String produces a hex encoded value, zero padded, prefixed with UpkeepPrefix func (ui UpkeepIdentifier) String() string { - val := utils.Big(ui) + val := big.Big(ui) result, err := utils.Uint256ToBytes(val.ToInt()) if err != nil { panic(errors.Wrap(err, "invariant, invalid upkeepID")) diff --git a/core/services/keeper/models_test.go b/core/services/keeper/models_test.go index ad81f47d8ee..729d1bbf231 100644 --- a/core/services/keeper/models_test.go +++ b/core/services/keeper/models_test.go @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) func TestUpkeepIdentifer_String(t *testing.T) { @@ -26,7 +26,7 @@ func TestUpkeepIdentifer_String(t *testing.T) { return } - result := NewUpkeepIdentifier(utils.NewBig(o)).String() + result := NewUpkeepIdentifier(ubig.New(o)).String() require.Equal(t, test.hex, result) }) } diff --git a/core/services/keeper/orm.go b/core/services/keeper/orm.go index 91883f8056c..fc8770cd864 100644 --- a/core/services/keeper/orm.go +++ b/core/services/keeper/orm.go @@ -7,10 +7,10 @@ import ( "github.com/lib/pq" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "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" ) // ORM implements ORM layer using PostgreSQL @@ -86,7 +86,7 @@ RETURNING * } // UpdateUpkeepLastKeeperIndex updates the last keeper index for an upkeep -func (korm ORM) UpdateUpkeepLastKeeperIndex(jobID int32, upkeepID *utils.Big, fromAddress ethkey.EIP55Address) error { +func (korm ORM) UpdateUpkeepLastKeeperIndex(jobID int32, upkeepID *big.Big, fromAddress ethkey.EIP55Address) error { _, err := korm.q.Exec(` UPDATE upkeep_registrations SET @@ -98,7 +98,7 @@ func (korm ORM) UpdateUpkeepLastKeeperIndex(jobID int32, upkeepID *utils.Big, fr } // BatchDeleteUpkeepsForJob deletes all upkeeps by the given IDs for the job with the given ID -func (korm ORM) BatchDeleteUpkeepsForJob(jobID int32, upkeepIDs []utils.Big) (int64, error) { +func (korm ORM) BatchDeleteUpkeepsForJob(jobID int32, upkeepIDs []big.Big) (int64, error) { strIds := []string{} for _, upkeepID := range upkeepIDs { strIds = append(strIds, upkeepID.String()) @@ -202,7 +202,7 @@ func loadUpkeepsRegistry(q pg.Queryer, upkeeps []UpkeepRegistration) error { return nil } -func (korm ORM) AllUpkeepIDsForRegistry(regID int64) (upkeeps []utils.Big, err error) { +func (korm ORM) AllUpkeepIDsForRegistry(regID int64) (upkeeps []big.Big, err error) { err = korm.q.Select(&upkeeps, ` SELECT upkeep_id FROM upkeep_registrations @@ -212,7 +212,7 @@ WHERE registry_id = $1 } // SetLastRunInfoForUpkeepOnJob sets the last run block height and the associated keeper index only if the new block height is greater than the previous. -func (korm ORM) SetLastRunInfoForUpkeepOnJob(jobID int32, upkeepID *utils.Big, height int64, fromAddress ethkey.EIP55Address, qopts ...pg.QOpt) (int64, error) { +func (korm ORM) SetLastRunInfoForUpkeepOnJob(jobID int32, upkeepID *big.Big, height int64, fromAddress ethkey.EIP55Address, qopts ...pg.QOpt) (int64, error) { res, err := korm.q.WithOpts(qopts...).Exec(` UPDATE upkeep_registrations SET last_run_block_height = $1, diff --git a/core/services/keeper/orm_test.go b/core/services/keeper/orm_test.go index d67baa09a06..2ce459886ae 100644 --- a/core/services/keeper/orm_test.go +++ b/core/services/keeper/orm_test.go @@ -15,6 +15,8 @@ import ( "github.com/jmoiron/sqlx" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + 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/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" @@ -45,7 +47,7 @@ func setupKeeperDB(t *testing.T) ( func newUpkeep(registry keeper.Registry, upkeepID int64) keeper.UpkeepRegistration { return keeper.UpkeepRegistration{ - UpkeepID: utils.NewBigI(upkeepID), + UpkeepID: ubig.NewI(upkeepID), ExecuteGas: executeGas, Registry: registry, RegistryID: registry.ID, @@ -103,7 +105,7 @@ func TestKeeperDB_UpsertUpkeep(t *testing.T) { registry, _ := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) upkeep := keeper.UpkeepRegistration{ - UpkeepID: utils.NewBigI(0), + UpkeepID: ubig.NewI(0), ExecuteGas: executeGas, Registry: registry, RegistryID: registry.ID, @@ -139,7 +141,7 @@ func TestKeeperDB_BatchDeleteUpkeepsForJob(t *testing.T) { registry, job := cltest.MustInsertKeeperRegistry(t, db, orm, ethKeyStore, 0, 1, 20) expectedUpkeepID := cltest.MustInsertUpkeepForRegistry(t, db, config.Database(), registry).UpkeepID - var upkeepIDs []utils.Big + var upkeepIDs []ubig.Big for i := 0; i < 2; i++ { upkeep := cltest.MustInsertUpkeepForRegistry(t, db, config.Database(), registry) upkeepIDs = append(upkeepIDs, *upkeep.UpkeepID) @@ -176,11 +178,11 @@ func TestKeeperDB_EligibleUpkeeps_Shuffle(t *testing.T) { } cltest.AssertCount(t, db, "upkeep_registrations", 100) - eligibleUpkeeps, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, blockheight, gracePeriod, fmt.Sprintf("%b", utils.NewHash().Big())) + eligibleUpkeeps, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, blockheight, gracePeriod, fmt.Sprintf("%b", evmutils.NewHash().Big())) assert.NoError(t, err) require.Len(t, eligibleUpkeeps, 100) - shuffled := [100]*utils.Big{} + shuffled := [100]*ubig.Big{} for i := 0; i < 100; i++ { shuffled[i] = eligibleUpkeeps[i].UpkeepID } @@ -204,12 +206,12 @@ func TestKeeperDB_NewEligibleUpkeeps_GracePeriod(t *testing.T) { // if current keeper index = 0 and all upkeeps last perform was done by index = 0 and still within grace period upkeep := keeper.UpkeepRegistration{} require.NoError(t, db.Get(&upkeep, `UPDATE upkeep_registrations SET last_keeper_index = 0, last_run_block_height = 10 RETURNING *`)) - list0, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 21, 100, fmt.Sprintf("%b", utils.NewHash().Big())) // none eligible + list0, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 21, 100, fmt.Sprintf("%b", evmutils.NewHash().Big())) // none eligible require.NoError(t, err) require.Equal(t, 0, len(list0), "should be 0 as all last perform was done by current node") // once passed grace period - list1, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 121, 100, fmt.Sprintf("%b", utils.NewHash().Big())) // none eligible + list1, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 121, 100, fmt.Sprintf("%b", evmutils.NewHash().Big())) // none eligible require.NoError(t, err) require.NotEqual(t, 0, len(list1), "should get some eligible upkeeps now that they are outside grace period") } @@ -229,13 +231,13 @@ func TestKeeperDB_EligibleUpkeeps_TurnsRandom(t *testing.T) { cltest.AssertCount(t, db, "upkeep_registrations", 1000) // 3 keepers 10 block turns should be different every turn - list1, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 20, 100, fmt.Sprintf("%b", utils.NewHash().Big())) + list1, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 20, 100, fmt.Sprintf("%b", evmutils.NewHash().Big())) require.NoError(t, err) - list2, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 31, 100, fmt.Sprintf("%b", utils.NewHash().Big())) + list2, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 31, 100, fmt.Sprintf("%b", evmutils.NewHash().Big())) require.NoError(t, err) - list3, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 42, 100, fmt.Sprintf("%b", utils.NewHash().Big())) + list3, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 42, 100, fmt.Sprintf("%b", evmutils.NewHash().Big())) require.NoError(t, err) - list4, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 53, 100, fmt.Sprintf("%b", utils.NewHash().Big())) + list4, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 53, 100, fmt.Sprintf("%b", evmutils.NewHash().Big())) require.NoError(t, err) // sort before compare @@ -274,7 +276,7 @@ func TestKeeperDB_NewEligibleUpkeeps_SkipIfLastPerformedByCurrentKeeper(t *testi // if current keeper index = 0 and all upkeeps last perform was done by index = 0 then skip as it would not pass required turn taking upkeep := keeper.UpkeepRegistration{} require.NoError(t, db.Get(&upkeep, `UPDATE upkeep_registrations SET last_keeper_index = 0 RETURNING *`)) - list0, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 21, 100, fmt.Sprintf("%b", utils.NewHash().Big())) // none eligible + list0, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 21, 100, fmt.Sprintf("%b", evmutils.NewHash().Big())) // none eligible require.NoError(t, err) require.Equal(t, 0, len(list0), "should be 0 as all last perform was done by current node") } @@ -294,7 +296,7 @@ func TestKeeperDB_NewEligibleUpkeeps_CoverBuddy(t *testing.T) { cltest.AssertCount(t, db, "upkeep_registrations", 100) upkeep := keeper.UpkeepRegistration{} - binaryHash := fmt.Sprintf("%b", utils.NewHash().Big()) + binaryHash := fmt.Sprintf("%b", evmutils.NewHash().Big()) listBefore, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 21, 100, binaryHash) // normal require.NoError(t, err) require.NoError(t, db.Get(&upkeep, `UPDATE upkeep_registrations SET last_keeper_index = 0 RETURNING *`)) @@ -317,7 +319,7 @@ func TestKeeperDB_NewEligibleUpkeeps_FirstTurn(t *testing.T) { cltest.AssertCount(t, db, "keeper_registries", 1) cltest.AssertCount(t, db, "upkeep_registrations", 100) - binaryHash := fmt.Sprintf("%b", utils.NewHash().Big()) + binaryHash := fmt.Sprintf("%b", evmutils.NewHash().Big()) // last keeper index is null to simulate a normal first run listKpr0, err := orm.EligibleUpkeepsForRegistry(registry.ContractAddress, 21, 100, binaryHash) // someone eligible only kpr0 turn require.NoError(t, err) @@ -338,7 +340,7 @@ func TestKeeperDB_NewEligibleUpkeeps_FiltersByRegistry(t *testing.T) { cltest.AssertCount(t, db, "keeper_registries", 2) cltest.AssertCount(t, db, "upkeep_registrations", 2) - binaryHash := fmt.Sprintf("%b", utils.NewHash().Big()) + binaryHash := fmt.Sprintf("%b", evmutils.NewHash().Big()) list1, err := orm.EligibleUpkeepsForRegistry(registry1.ContractAddress, 20, 100, binaryHash) require.NoError(t, err) list2, err := orm.EligibleUpkeepsForRegistry(registry2.ContractAddress, 20, 100, binaryHash) @@ -372,8 +374,8 @@ func TestKeeperDB_AllUpkeepIDsForRegistry(t *testing.T) { require.NoError(t, err) // No upkeeps returned require.Len(t, upkeepIDs, 2) - require.Contains(t, upkeepIDs, *utils.NewBig(big.NewInt(3))) - require.Contains(t, upkeepIDs, *utils.NewBig(big.NewInt(8))) + require.Contains(t, upkeepIDs, *ubig.New(big.NewInt(3))) + require.Contains(t, upkeepIDs, *ubig.New(big.NewInt(8))) } func TestKeeperDB_UpdateUpkeepLastKeeperIndex(t *testing.T) { @@ -399,8 +401,8 @@ func TestKeeperDB_NewSetLastRunInfoForUpkeepOnJob(t *testing.T) { upkeep := cltest.MustInsertUpkeepForRegistry(t, db, config.Database(), registry) registry.NumKeepers = 2 registry.KeeperIndexMap = map[ethkey.EIP55Address]int32{ - registry.FromAddress: 0, - ethkey.EIP55AddressFromAddress(utils.ZeroAddress): 1, + registry.FromAddress: 0, + ethkey.EIP55AddressFromAddress(evmutils.ZeroAddress): 1, } err := orm.UpsertRegistry(®istry) require.NoError(t, err, "UPDATE keeper_registries") @@ -416,7 +418,7 @@ func TestKeeperDB_NewSetLastRunInfoForUpkeepOnJob(t *testing.T) { require.Equal(t, rowsAffected, int64(0)) assertLastRunHeight(t, db, upkeep, 100, 0) // update to same block height allowed - rowsAffected, err = orm.SetLastRunInfoForUpkeepOnJob(j.ID, upkeep.UpkeepID, 100, ethkey.EIP55AddressFromAddress(utils.ZeroAddress)) + rowsAffected, err = orm.SetLastRunInfoForUpkeepOnJob(j.ID, upkeep.UpkeepID, 100, ethkey.EIP55AddressFromAddress(evmutils.ZeroAddress)) require.NoError(t, err) require.Equal(t, rowsAffected, int64(1)) assertLastRunHeight(t, db, upkeep, 100, 1) @@ -488,11 +490,11 @@ func TestKeeperDB_Uint256ToBit(t *testing.T) { }, { name: "max", - input: utils.MaxUint256, + input: evmutils.MaxUint256, }, { name: "rand", - input: utils.RandUint256(), + input: evmutils.RandUint256(), }, { name: "needs pading", @@ -500,7 +502,7 @@ func TestKeeperDB_Uint256ToBit(t *testing.T) { }, { name: "overflow", - input: bigmath.Add(utils.MaxUint256, big.NewInt(1)), + input: bigmath.Add(evmutils.MaxUint256, big.NewInt(1)), errorExpected: true, }, } { diff --git a/core/services/keeper/registry1_1_synchronizer_test.go b/core/services/keeper/registry1_1_synchronizer_test.go index 031b7a59074..a4f03d4d34a 100644 --- a/core/services/keeper/registry1_1_synchronizer_test.go +++ b/core/services/keeper/registry1_1_synchronizer_test.go @@ -12,9 +12,11 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" registry1_1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_1" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -23,7 +25,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/keeper" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var registryConfig1_1 = registry1_1.GetConfig{ @@ -122,7 +123,7 @@ func Test_RegistrySynchronizer1_1_Start(t *testing.T) { func Test_RegistrySynchronizer_CalcPositioningConstant(t *testing.T) { t.Parallel() for _, upkeepID := range []int64{0, 1, 100, 10_000} { - _, err := keeper.CalcPositioningConstant(utils.NewBigI(upkeepID), cltest.NewEIP55Address()) + _, err := keeper.CalcPositioningConstant(ubig.NewI(upkeepID), cltest.NewEIP55Address()) require.NoError(t, err) } } @@ -217,8 +218,7 @@ func Test_RegistrySynchronizer1_1_ConfigSetLog(t *testing.T) { upkeepConfig1_1, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -266,8 +266,7 @@ func Test_RegistrySynchronizer1_1_KeepersUpdatedLog(t *testing.T) { upkeepConfig1_1, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -313,8 +312,7 @@ func Test_RegistrySynchronizer1_1_UpkeepCanceledLog(t *testing.T) { upkeepConfig1_1, 3) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) @@ -352,8 +350,7 @@ func Test_RegistrySynchronizer1_1_UpkeepRegisteredLog(t *testing.T) { upkeepConfig1_1, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -396,8 +393,7 @@ func Test_RegistrySynchronizer1_1_UpkeepPerformedLog(t *testing.T) { upkeepConfig1_1, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) diff --git a/core/services/keeper/registry1_2_synchronizer_test.go b/core/services/keeper/registry1_2_synchronizer_test.go index e7d8d6a48a2..b7456ad94e4 100644 --- a/core/services/keeper/registry1_2_synchronizer_test.go +++ b/core/services/keeper/registry1_2_synchronizer_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -237,8 +238,7 @@ func Test_RegistrySynchronizer1_2_ConfigSetLog(t *testing.T) { 2, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -290,8 +290,7 @@ func Test_RegistrySynchronizer1_2_KeepersUpdatedLog(t *testing.T) { 2, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -342,8 +341,7 @@ func Test_RegistrySynchronizer1_2_UpkeepCanceledLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) @@ -382,8 +380,7 @@ func Test_RegistrySynchronizer1_2_UpkeepRegisteredLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -427,8 +424,7 @@ func Test_RegistrySynchronizer1_2_UpkeepPerformedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -482,8 +478,7 @@ func Test_RegistrySynchronizer1_2_UpkeepGasLimitSetLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -535,8 +530,7 @@ func Test_RegistrySynchronizer1_2_UpkeepReceivedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -578,8 +572,7 @@ func Test_RegistrySynchronizer1_2_UpkeepMigratedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) diff --git a/core/services/keeper/registry1_3_synchronizer_test.go b/core/services/keeper/registry1_3_synchronizer_test.go index a0522fd717e..77bb873e1d0 100644 --- a/core/services/keeper/registry1_3_synchronizer_test.go +++ b/core/services/keeper/registry1_3_synchronizer_test.go @@ -12,15 +12,16 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" - registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" "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" @@ -242,8 +243,7 @@ func Test_RegistrySynchronizer1_3_ConfigSetLog(t *testing.T) { 2, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -295,8 +295,7 @@ func Test_RegistrySynchronizer1_3_KeepersUpdatedLog(t *testing.T) { 2, 0) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) var registry keeper.Registry require.NoError(t, db.Get(®istry, `SELECT * FROM keeper_registries`)) @@ -347,8 +346,7 @@ func Test_RegistrySynchronizer1_3_UpkeepCanceledLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) @@ -387,8 +385,7 @@ func Test_RegistrySynchronizer1_3_UpkeepRegisteredLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -432,8 +429,7 @@ func Test_RegistrySynchronizer1_3_UpkeepPerformedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -487,8 +483,7 @@ func Test_RegistrySynchronizer1_3_UpkeepGasLimitSetLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -540,8 +535,7 @@ func Test_RegistrySynchronizer1_3_UpkeepReceivedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -583,8 +577,7 @@ func Test_RegistrySynchronizer1_3_UpkeepMigratedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) @@ -625,8 +618,7 @@ func Test_RegistrySynchronizer1_3_UpkeepPausedLog_UpkeepUnpausedLog(t *testing.T 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { require.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 3) @@ -662,7 +654,7 @@ func Test_RegistrySynchronizer1_3_UpkeepPausedLog_UpkeepUnpausedLog(t *testing.T cltest.WaitForCount(t, db, "upkeep_registrations", 3) var upkeep keeper.UpkeepRegistration - err := db.Get(&upkeep, `SELECT * FROM upkeep_registrations WHERE upkeep_id = $1`, utils.NewBig(upkeepId)) + err := db.Get(&upkeep, `SELECT * FROM upkeep_registrations WHERE upkeep_id = $1`, ubig.New(upkeepId)) require.NoError(t, err) require.Equal(t, upkeepId.String(), upkeep.UpkeepID.String()) @@ -695,8 +687,7 @@ func Test_RegistrySynchronizer1_3_UpkeepCheckDataUpdatedLog(t *testing.T) { 2, 1) - require.NoError(t, synchronizer.Start(testutils.Context(t))) - defer func() { assert.NoError(t, synchronizer.Close()) }() + servicetest.Run(t, synchronizer) cltest.WaitForCount(t, db, "keeper_registries", 1) cltest.WaitForCount(t, db, "upkeep_registrations", 1) @@ -723,7 +714,7 @@ func Test_RegistrySynchronizer1_3_UpkeepCheckDataUpdatedLog(t *testing.T) { g.Eventually(func() []byte { var upkeep keeper.UpkeepRegistration - err := db.Get(&upkeep, `SELECT * FROM upkeep_registrations WHERE upkeep_id = $1`, utils.NewBig(upkeepId)) + err := db.Get(&upkeep, `SELECT * FROM upkeep_registrations WHERE upkeep_id = $1`, ubig.New(upkeepId)) require.NoError(t, err) return upkeep.CheckData }, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal(newCheckData)) diff --git a/core/services/keeper/registry_synchronizer_core.go b/core/services/keeper/registry_synchronizer_core.go index db7cca1763f..f26c38fc2e1 100644 --- a/core/services/keeper/registry_synchronizer_core.go +++ b/core/services/keeper/registry_synchronizer_core.go @@ -10,6 +10,8 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -28,7 +30,7 @@ type RegistrySynchronizerOptions struct { ORM ORM JRM job.ORM LogBroadcaster log.Broadcaster - MailMon *utils.MailboxMonitor + MailMon *mailbox.Monitor SyncInterval time.Duration MinIncomingConfirmations uint32 Logger logger.Logger @@ -44,14 +46,14 @@ type RegistrySynchronizer struct { job job.Job jrm job.ORM logBroadcaster log.Broadcaster - mbLogs *utils.Mailbox[log.Broadcast] + mbLogs *mailbox.Mailbox[log.Broadcast] minIncomingConfirmations uint32 effectiveKeeperAddress common.Address orm ORM logger logger.SugaredLogger wgDone sync.WaitGroup syncUpkeepQueueSize uint32 //Represents the max number of upkeeps that can be synced in parallel - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } // NewRegistrySynchronizer is the constructor of RegistrySynchronizer @@ -63,7 +65,7 @@ func NewRegistrySynchronizer(opts RegistrySynchronizerOptions) *RegistrySynchron job: opts.Job, jrm: opts.JRM, logBroadcaster: opts.LogBroadcaster, - mbLogs: utils.NewMailbox[log.Broadcast](5_000), // Arbitrary limit, better to have excess capacity + mbLogs: mailbox.New[log.Broadcast](5_000), // Arbitrary limit, better to have excess capacity minIncomingConfirmations: opts.MinIncomingConfirmations, orm: opts.ORM, effectiveKeeperAddress: opts.EffectiveKeeperAddress, diff --git a/core/services/keeper/registry_synchronizer_helper_test.go b/core/services/keeper/registry_synchronizer_helper_test.go index 966366b1069..19ba2eedbbb 100644 --- a/core/services/keeper/registry_synchronizer_helper_test.go +++ b/core/services/keeper/registry_synchronizer_helper_test.go @@ -10,6 +10,9 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" logmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" @@ -21,8 +24,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const syncInterval = 1000 * time.Hour // prevents sync timer from triggering during test @@ -72,7 +73,7 @@ func setupRegistrySync(t *testing.T, version keeper.RegistryVersion) ( })).Maybe().Return(func() {}) lbMock.On("IsConnected").Return(true).Maybe() - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) orm := keeper.NewORM(db, logger.TestLogger(t), ch.Config().Database()) synchronizer := keeper.NewRegistrySynchronizer(keeper.RegistrySynchronizerOptions{ diff --git a/core/services/keeper/registry_synchronizer_process_logs.go b/core/services/keeper/registry_synchronizer_process_logs.go index 9e1aa3b410b..7b82f49ae4c 100644 --- a/core/services/keeper/registry_synchronizer_process_logs.go +++ b/core/services/keeper/registry_synchronizer_process_logs.go @@ -7,11 +7,11 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" registry1_1 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_1" registry1_2 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_2" registry1_3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registry_wrapper1_3" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func (rs *RegistrySynchronizer) processLogs() { @@ -109,7 +109,7 @@ func (rs *RegistrySynchronizer) handleUpkeepCancelled(broadcast log.Broadcast) e return errors.Wrap(err, "Unable to fetch cancelled upkeep ID from log") } - affected, err := rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []utils.Big{*utils.NewBig(cancelledID)}) + affected, err := rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []big.Big{*big.New(cancelledID)}) if err != nil { return errors.Wrap(err, "unable to batch delete upkeeps") } @@ -130,7 +130,7 @@ func (rs *RegistrySynchronizer) handleUpkeepRegistered(broadcast log.Broadcast) return errors.Wrap(err, "Unable to fetch upkeep ID from registration log") } - err = rs.syncUpkeep(&rs.registryWrapper, registry, utils.NewBig(upkeepID)) + err = rs.syncUpkeep(&rs.registryWrapper, registry, big.New(upkeepID)) if err != nil { return errors.Wrapf(err, "failed to sync upkeep, log: %v", broadcast.String()) } @@ -144,7 +144,7 @@ func (rs *RegistrySynchronizer) handleUpkeepPerformed(broadcast log.Broadcast) e if err != nil { return errors.Wrap(err, "Unable to fetch upkeep ID from performed log") } - rowsAffected, err := rs.orm.SetLastRunInfoForUpkeepOnJob(rs.job.ID, utils.NewBig(log.UpkeepID), int64(broadcast.RawLog().BlockNumber), ethkey.EIP55AddressFromAddress(log.FromKeeper)) + rowsAffected, err := rs.orm.SetLastRunInfoForUpkeepOnJob(rs.job.ID, big.New(log.UpkeepID), int64(broadcast.RawLog().BlockNumber), ethkey.EIP55AddressFromAddress(log.FromKeeper)) if err != nil { return errors.Wrap(err, "failed to set last run to 0") } @@ -171,7 +171,7 @@ func (rs *RegistrySynchronizer) handleUpkeepGasLimitSet(broadcast log.Broadcast) return errors.Wrap(err, "Unable to fetch upkeep ID from gas limit set log") } - err = rs.syncUpkeep(&rs.registryWrapper, registry, utils.NewBig(upkeepID)) + err = rs.syncUpkeep(&rs.registryWrapper, registry, big.New(upkeepID)) if err != nil { return errors.Wrapf(err, "failed to sync upkeep, log: %v", broadcast.String()) } @@ -191,7 +191,7 @@ func (rs *RegistrySynchronizer) handleUpkeepReceived(broadcast log.Broadcast) er return errors.Wrap(err, "Unable to fetch upkeep ID from received log") } - err = rs.syncUpkeep(&rs.registryWrapper, registry, utils.NewBig(upkeepID)) + err = rs.syncUpkeep(&rs.registryWrapper, registry, big.New(upkeepID)) if err != nil { return errors.Wrapf(err, "failed to sync upkeep, log: %v", broadcast.String()) } @@ -206,7 +206,7 @@ func (rs *RegistrySynchronizer) handleUpkeepMigrated(broadcast log.Broadcast) er return errors.Wrap(err, "Unable to fetch migrated upkeep ID from log") } - affected, err := rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []utils.Big{*utils.NewBig(migratedID)}) + affected, err := rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []big.Big{*big.New(migratedID)}) if err != nil { return errors.Wrap(err, "unable to batch delete upkeeps") } @@ -222,7 +222,7 @@ func (rs *RegistrySynchronizer) handleUpkeepPaused(broadcast log.Broadcast) erro return errors.Wrap(err, "Unable to fetch upkeep ID from upkeep paused log") } - _, err = rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []utils.Big{*utils.NewBig(pausedUpkeepId)}) + _, err = rs.orm.BatchDeleteUpkeepsForJob(rs.job.ID, []big.Big{*big.New(pausedUpkeepId)}) if err != nil { return errors.Wrap(err, "unable to batch delete upkeeps") } @@ -243,7 +243,7 @@ func (rs *RegistrySynchronizer) handleUpkeepUnpaused(broadcast log.Broadcast) er return errors.Wrap(err, "Unable to fetch upkeep ID from upkeep unpaused log") } - err = rs.syncUpkeep(&rs.registryWrapper, registry, utils.NewBig(unpausedUpkeepId)) + err = rs.syncUpkeep(&rs.registryWrapper, registry, big.New(unpausedUpkeepId)) if err != nil { return errors.Wrapf(err, "failed to sync upkeep, log: %s", broadcast.String()) } @@ -264,7 +264,7 @@ func (rs *RegistrySynchronizer) handleUpkeepCheckDataUpdated(broadcast log.Broad return errors.Wrap(err, "Unable to parse update log from upkeep check data updated log") } - err = rs.syncUpkeep(&rs.registryWrapper, registry, utils.NewBig(updateLog.UpkeepID)) + err = rs.syncUpkeep(&rs.registryWrapper, registry, big.New(updateLog.UpkeepID)) if err != nil { return errors.Wrapf(err, "unable to update check data for upkeep %s", updateLog.UpkeepID.String()) } diff --git a/core/services/keeper/registry_synchronizer_sync.go b/core/services/keeper/registry_synchronizer_sync.go index 649ccd94066..7614ed15edb 100644 --- a/core/services/keeper/registry_synchronizer_sync.go +++ b/core/services/keeper/registry_synchronizer_sync.go @@ -7,8 +7,9 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func (rs *RegistrySynchronizer) fullSync() { @@ -53,15 +54,15 @@ func (rs *RegistrySynchronizer) fullSyncUpkeeps(reg Registry) error { } activeSet := make(map[string]bool) - allActiveUpkeeps := make([]utils.Big, 0) + allActiveUpkeeps := make([]big.Big, 0) for _, upkeepID := range activeUpkeepIDs { activeSet[upkeepID.String()] = true - allActiveUpkeeps = append(allActiveUpkeeps, *utils.NewBig(upkeepID)) + allActiveUpkeeps = append(allActiveUpkeeps, *big.New(upkeepID)) } rs.batchSyncUpkeepsOnRegistry(reg, allActiveUpkeeps) // All upkeeps in existingUpkeepIDs, not in activeUpkeepIDs should be deleted - canceled := make([]utils.Big, 0) + canceled := make([]big.Big, 0) for _, upkeepID := range existingUpkeepIDs { if _, found := activeSet[upkeepID.ToInt().String()]; !found { canceled = append(canceled, upkeepID) @@ -75,7 +76,7 @@ func (rs *RegistrySynchronizer) fullSyncUpkeeps(reg Registry) error { // batchSyncUpkeepsOnRegistry syncs upkeeps at a time in parallel // for all the IDs within newUpkeeps slice -func (rs *RegistrySynchronizer) batchSyncUpkeepsOnRegistry(reg Registry, newUpkeeps []utils.Big) { +func (rs *RegistrySynchronizer) batchSyncUpkeepsOnRegistry(reg Registry, newUpkeeps []big.Big) { wg := sync.WaitGroup{} wg.Add(len(newUpkeeps)) chSyncUpkeepQueue := make(chan struct{}, rs.syncUpkeepQueueSize) @@ -93,7 +94,7 @@ func (rs *RegistrySynchronizer) batchSyncUpkeepsOnRegistry(reg Registry, newUpke wg.Wait() } -func (rs *RegistrySynchronizer) syncUpkeepWithCallback(getter upkeepGetter, registry Registry, upkeepID *utils.Big, doneCallback func()) { +func (rs *RegistrySynchronizer) syncUpkeepWithCallback(getter upkeepGetter, registry Registry, upkeepID *big.Big, doneCallback func()) { defer doneCallback() if err := rs.syncUpkeep(getter, registry, upkeepID); err != nil { @@ -104,7 +105,7 @@ func (rs *RegistrySynchronizer) syncUpkeepWithCallback(getter upkeepGetter, regi } } -func (rs *RegistrySynchronizer) syncUpkeep(getter upkeepGetter, registry Registry, upkeepID *utils.Big) error { +func (rs *RegistrySynchronizer) syncUpkeep(getter upkeepGetter, registry Registry, upkeepID *big.Big) error { upkeep, err := getter.GetUpkeep(nil, upkeepID.ToInt()) if err != nil { return errors.Wrap(err, "failed to get upkeep config") @@ -173,9 +174,9 @@ func (rs *RegistrySynchronizer) newRegistryFromChain() (Registry, error) { // CalcPositioningConstant calculates a positioning constant. // The positioning constant is fixed because upkeepID and registryAddress are immutable -func CalcPositioningConstant(upkeepID *utils.Big, registryAddress ethkey.EIP55Address) (int32, error) { +func CalcPositioningConstant(upkeepID *big.Big, registryAddress ethkey.EIP55Address) (int32, error) { upkeepBytes := make([]byte, binary.MaxVarintLen64) - binary.PutVarint(upkeepBytes, upkeepID.Mod(utils.NewBigI(math.MaxInt64)).Int64()) + binary.PutVarint(upkeepBytes, upkeepID.Mod(big.NewI(math.MaxInt64)).Int64()) bytesToHash := utils.ConcatBytes(upkeepBytes, registryAddress.Bytes()) checksum, err := utils.Keccak256(bytesToHash) if err != nil { diff --git a/core/services/keeper/registry_synchronizer_sync_test.go b/core/services/keeper/registry_synchronizer_sync_test.go index 10a51679c5e..e6f42a83201 100644 --- a/core/services/keeper/registry_synchronizer_sync_test.go +++ b/core/services/keeper/registry_synchronizer_sync_test.go @@ -10,10 +10,10 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // GetUpkeepFailure implements the upkeepGetter interface with an induced error and nil @@ -42,7 +42,7 @@ func TestSyncUpkeepWithCallback_UpkeepNotFound(t *testing.T) { t.FailNow() } - id := utils.NewBig(o) + id := ubig.New(o) count := 0 doneFunc := func() { count++ diff --git a/core/services/keeper/upkeep_executer.go b/core/services/keeper/upkeep_executer.go index 84349ba2dca..bab2f73edfc 100644 --- a/core/services/keeper/upkeep_executer.go +++ b/core/services/keeper/upkeep_executer.go @@ -13,6 +13,8 @@ import ( "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "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" @@ -23,7 +25,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/utils" ) const ( @@ -62,7 +63,7 @@ type UpkeepExecuter struct { headBroadcaster httypes.HeadBroadcasterRegistry gasEstimator gas.EvmFeeEstimator job job.Job - mailbox *utils.Mailbox[*evmtypes.Head] + mailbox *mailbox.Mailbox[*evmtypes.Head] orm ORM pr pipeline.Runner logger logger.Logger @@ -89,7 +90,7 @@ func NewUpkeepExecuter( headBroadcaster: headBroadcaster, gasEstimator: gasEstimator, job: job, - mailbox: utils.NewSingleMailbox[*evmtypes.Head](), + mailbox: mailbox.NewSingle[*evmtypes.Head](), config: config, orm: orm, pr: pr, diff --git a/core/services/keeper/upkeep_executer_test.go b/core/services/keeper/upkeep_executer_test.go index 7bbecafa22d..590c9720cb2 100644 --- a/core/services/keeper/upkeep_executer_test.go +++ b/core/services/keeper/upkeep_executer_test.go @@ -15,6 +15,7 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" @@ -22,6 +23,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/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" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -34,11 +37,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keeper" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func newHead() evmtypes.Head { - return evmtypes.NewHead(big.NewInt(20), utils.NewHash(), utils.NewHash(), 1000, utils.NewBigI(0)) + return evmtypes.NewHead(big.NewInt(20), utils.NewHash(), utils.NewHash(), 1000, ubig.NewI(0)) } func mockEstimator(t *testing.T) gas.EvmFeeEstimator { @@ -88,8 +90,7 @@ func setup(t *testing.T, estimator gas.EvmFeeEstimator, overrideFn func(c *chain lggr := logger.TestLogger(t) executer := keeper.NewUpkeepExecuter(job, orm, jpv2.Pr, ethClient, ch.HeadBroadcaster(), ch.GasEstimator(), lggr, ch.Config().Keeper(), job.KeeperSpec.FromAddress.Address()) upkeep := cltest.MustInsertUpkeepForRegistry(t, db, ch.Config().Database(), registry) - require.NoError(t, executer.Start(testutils.Context(t))) - t.Cleanup(func() { executer.Close() }) + servicetest.Run(t, executer) return db, cfg, ethClient, executer, registry, upkeep, job, jpv2, txm, keyStore, ch, orm } @@ -128,7 +129,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { t.Run("runs upkeep on triggering block number", func(t *testing.T) { db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) gasLimit := 5_000_000 + config.Keeper().Registry().PerformGasOverhead() @@ -173,7 +174,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { runTest := func(t *testing.T, eip1559 bool) { db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &eip1559 - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) gasLimit := 5_000_000 + config.Keeper().Registry().PerformGasOverhead() @@ -226,7 +227,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { t.Run("errors if submission key not found", func(t *testing.T) { _, _, ethMock, executer, registry, _, job, jpv2, _, keyStore, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) // replace expected key with random one @@ -263,7 +264,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { registry, jb := cltest.MustInsertKeeperRegistry(t, db, orm, keyStore.Eth(), 0, 1, 20) // change chain ID to non-configured chain - jb.KeeperSpec.EVMChainID = (*utils.Big)(big.NewInt(999)) + jb.KeeperSpec.EVMChainID = (*ubig.Big)(big.NewInt(999)) cltest.MustInsertUpkeepForRegistry(t, db, ch.Config().Database(), 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()) @@ -278,7 +279,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Happy(t *testing.T) { t.Run("triggers if heads are skipped but later heads arrive within range", func(t *testing.T) { db, config, ethMock, executer, registry, upkeep, job, jpv2, txm, _, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) etxs := []cltest.Awaiter{ @@ -321,7 +322,7 @@ func Test_UpkeepExecuter_PerformsUpkeep_Error(t *testing.T) { db, _, ethMock, executer, registry, _, _, _, _, _, _, _ := setup(t, mockEstimator(t), func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) var wasCalled atomic.Bool @@ -334,7 +335,12 @@ func Test_UpkeepExecuter_PerformsUpkeep_Error(t *testing.T) { executer.OnNewLongestChain(testutils.Context(t), &head) g.Eventually(wasCalled.Load).Should(gomega.Equal(true)) - cltest.AssertCountStays(t, db, "evm.txes", 0) + + cfg := pgtest.NewQConfig(false) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + txes, err := txStore.GetAllTxes(testutils.Context(t)) + require.NoError(t, err) + require.Len(t, txes, 0) } func ptr[T any](t T) *T { return &t } diff --git a/core/services/keeper/upkeep_executer_unit_test.go b/core/services/keeper/upkeep_executer_unit_test.go index a8fc46319cd..8589720ca5f 100644 --- a/core/services/keeper/upkeep_executer_unit_test.go +++ b/core/services/keeper/upkeep_executer_unit_test.go @@ -7,11 +7,11 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type registry struct { @@ -34,7 +34,7 @@ func TestBuildJobSpec(t *testing.T) { ContractAddress: contract, }} - upkeepID := utils.NewBigI(4) + upkeepID := big.NewI(4) upkeep := UpkeepRegistration{ Registry: Registry{ FromAddress: from, diff --git a/core/services/keystore/cosmos_test.go b/core/services/keystore/cosmos_test.go index 3c33f16282d..30c669f7545 100644 --- a/core/services/keystore/cosmos_test.go +++ b/core/services/keystore/cosmos_test.go @@ -6,12 +6,12 @@ import ( "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/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/cosmoskey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_CosmosKeyStore_E2E(t *testing.T) { diff --git a/core/services/keystore/eth_test.go b/core/services/keystore/eth_test.go index 42d6c575376..dd42f4049c3 100644 --- a/core/services/keystore/eth_test.go +++ b/core/services/keystore/eth_test.go @@ -9,18 +9,19 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + 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" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_EthKeyStore(t *testing.T) { @@ -35,8 +36,8 @@ func Test_EthKeyStore(t *testing.T) { ethKeyStore := keyStore.Eth() reset := func() { keyStore.ResetXXXTestOnly() - require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) - require.NoError(t, utils.JustError(db.Exec("DELETE FROM evm.key_states"))) + 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)) } const statesTableName = "evm.key_states" @@ -336,7 +337,7 @@ func Test_EthKeyStore_SignTx(t *testing.T) { k, _ := cltest.MustInsertRandomKey(t, ethKeyStore) chainID := big.NewInt(evmclient.NullClientChainID) - tx := types.NewTransaction(0, testutils.NewAddress(), big.NewInt(53), 21000, big.NewInt(1000000000), []byte{1, 2, 3, 4}) + tx := cltest.NewLegacyTransaction(0, testutils.NewAddress(), big.NewInt(53), 21000, big.NewInt(1000000000), []byte{1, 2, 3, 4}) randomAddress := testutils.NewAddress() _, err := ethKeyStore.SignTx(randomAddress, tx, chainID) @@ -360,8 +361,8 @@ func Test_EthKeyStore_E2E(t *testing.T) { ks := keyStore.Eth() reset := func() { keyStore.ResetXXXTestOnly() - require.NoError(t, utils.JustError(db.Exec("DELETE FROM encrypted_key_rings"))) - require.NoError(t, utils.JustError(db.Exec("DELETE FROM evm.key_states"))) + 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)) } @@ -673,7 +674,7 @@ func Test_EthKeyStore_Delete(t *testing.T) { _, addr1 := cltest.MustInsertRandomKey(t, ks) _, addr2 := cltest.MustInsertRandomKey(t, ks) - cltest.MustInsertRandomKey(t, ks, *utils.NewBig(testutils.SimulatedChainID)) + cltest.MustInsertRandomKey(t, ks, *ubig.New(testutils.SimulatedChainID)) require.NoError(t, ks.Add(addr1, testutils.SimulatedChainID)) require.NoError(t, ks.Enable(addr1, testutils.SimulatedChainID)) diff --git a/core/services/keystore/keys/cosmoskey/export.go b/core/services/keystore/keys/cosmoskey/export.go index a327b60e80a..05061ddb014 100644 --- a/core/services/keystore/keys/cosmoskey/export.go +++ b/core/services/keystore/keys/cosmoskey/export.go @@ -33,12 +33,12 @@ func (key Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) password, scryptParams, adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: hex.EncodeToString(key.PublicKey().Bytes()), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/csakey/export.go b/core/services/keystore/keys/csakey/export.go index a1ad499e0e4..bd0e0229edf 100644 --- a/core/services/keystore/keys/csakey/export.go +++ b/core/services/keystore/keys/csakey/export.go @@ -29,12 +29,12 @@ func (k KeyV2) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) password, scryptParams, adulteratedPassword, - func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: key.PublicKeyString(), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/dkgencryptkey/export.go b/core/services/keystore/keys/dkgencryptkey/export.go index c689c29f661..3bccf1a07ba 100644 --- a/core/services/keystore/keys/dkgencryptkey/export.go +++ b/core/services/keystore/keys/dkgencryptkey/export.go @@ -30,12 +30,12 @@ func (k Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) ( password, scryptParams, adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: key.PublicKeyString(), Crypto: cryptoJSON, - }, nil + } }) } diff --git a/core/services/keystore/keys/dkgsignkey/export.go b/core/services/keystore/keys/dkgsignkey/export.go index 7ecada8ddc0..3c421760d63 100644 --- a/core/services/keystore/keys/dkgsignkey/export.go +++ b/core/services/keystore/keys/dkgsignkey/export.go @@ -31,12 +31,12 @@ func (key Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) password, scryptParams, adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: key.PublicKeyString(), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/ethkey/address.go b/core/services/keystore/keys/ethkey/address.go index 1b26413f634..0d93a4cdb29 100644 --- a/core/services/keystore/keys/ethkey/address.go +++ b/core/services/keystore/keys/ethkey/address.go @@ -53,10 +53,10 @@ func EIP55AddressFromAddress(a common.Address) EIP55Address { func (a EIP55Address) Bytes() []byte { return a.Address().Bytes() } // Big returns a big.Int representation -func (a EIP55Address) Big() *big.Int { return a.Address().Hash().Big() } +func (a EIP55Address) Big() *big.Int { return a.Address().Big() } // Hash returns the Hash -func (a EIP55Address) Hash() common.Hash { return a.Address().Hash() } +func (a EIP55Address) Hash() common.Hash { return common.BytesToHash(a.Bytes()) } // Address returns EIP55Address as a go-ethereum Address type func (a EIP55Address) Address() common.Address { return common.HexToAddress(a.String()) } diff --git a/core/services/keystore/keys/ethkey/models.go b/core/services/keystore/keys/ethkey/models.go index b90503c3ed6..df4c474b7b9 100644 --- a/core/services/keystore/keys/ethkey/models.go +++ b/core/services/keystore/keys/ethkey/models.go @@ -3,13 +3,13 @@ package ethkey import ( "time" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) type State struct { ID int32 Address EIP55Address - EVMChainID utils.Big + EVMChainID big.Big Disabled bool CreatedAt time.Time UpdatedAt time.Time diff --git a/core/services/keystore/keys/exportutils.go b/core/services/keystore/keys/exportutils.go index 0c3e782a9a4..5d75b5076e6 100644 --- a/core/services/keystore/keys/exportutils.go +++ b/core/services/keystore/keys/exportutils.go @@ -3,7 +3,7 @@ package keys import ( "encoding/json" - keystore "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/pkg/errors" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -62,7 +62,7 @@ func ToEncryptedJSON[E Encrypted, K any]( password string, scryptParams utils.ScryptParams, passwordFunc func(string) string, - buildExport func(id string, key K, cryptoJSON keystore.CryptoJSON) (E, error), + buildExport func(id string, key K, cryptoJSON keystore.CryptoJSON) E, ) (export []byte, err error) { // encrypt data using prefixed password @@ -77,10 +77,7 @@ func ToEncryptedJSON[E Encrypted, K any]( } // build [E] export struct using encrypted key, identifier, and original key [K] - encryptedKeyExport, err := buildExport(identifier, key, cryptoJSON) - if err != nil { - return nil, errors.Wrapf(err, "could not build encrypted export for %s key", identifier) - } + encryptedKeyExport := buildExport(identifier, key, cryptoJSON) return json.Marshal(encryptedKeyExport) } diff --git a/core/services/keystore/keys/ocr2key/export.go b/core/services/keystore/keys/ocr2key/export.go index 54e73ecf98f..5487e310462 100644 --- a/core/services/keystore/keys/ocr2key/export.go +++ b/core/services/keystore/keys/ocr2key/export.go @@ -66,7 +66,7 @@ func ToEncryptedJSON(key KeyBundle, password string, scryptParams utils.ScryptPa password, scryptParams, adulteratedPassword, - func(id string, key KeyBundle, cryptoJSON keystore.CryptoJSON) (EncryptedOCRKeyExport, error) { + func(id string, key KeyBundle, cryptoJSON keystore.CryptoJSON) EncryptedOCRKeyExport { pubKeyConfig := key.ConfigEncryptionPublicKey() pubKey := key.OffchainPublicKey() return EncryptedOCRKeyExport{ @@ -77,7 +77,7 @@ func ToEncryptedJSON(key KeyBundle, password string, scryptParams utils.ScryptPa OffChainPublicKey: hex.EncodeToString(pubKey[:]), ConfigPublicKey: hex.EncodeToString(pubKeyConfig[:]), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/ocr2key/offchain_keyring.go b/core/services/keystore/keys/ocr2key/offchain_keyring.go index 9e6d8f64e03..36fc1cfd02a 100644 --- a/core/services/keystore/keys/ocr2key/offchain_keyring.go +++ b/core/services/keystore/keys/ocr2key/offchain_keyring.go @@ -68,7 +68,7 @@ func (ok *OffchainKeyring) NaclBoxOpenAnonymous(ciphertext []byte) (plaintext [] // OffchainSign signs message using private key func (ok *OffchainKeyring) OffchainSign(msg []byte) (signature []byte, err error) { - return ed25519.Sign(ed25519.PrivateKey(ok.signingKey), msg), nil + return ed25519.Sign(ok.signingKey, msg), nil } // ConfigDiffieHellman returns the shared point obtained by multiplying someone's diff --git a/core/services/keystore/keys/ocrkey/export.go b/core/services/keystore/keys/ocrkey/export.go index 9f63a3c2d9c..363f38b20ab 100644 --- a/core/services/keystore/keys/ocrkey/export.go +++ b/core/services/keystore/keys/ocrkey/export.go @@ -42,7 +42,7 @@ func (key KeyV2) ToEncryptedJSON(password string, scryptParams utils.ScryptParam password, scryptParams, adulteratedPassword, - func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) (EncryptedOCRKeyExport, error) { + func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) EncryptedOCRKeyExport { return EncryptedOCRKeyExport{ KeyType: id, ID: key.ID(), @@ -50,7 +50,7 @@ func (key KeyV2) ToEncryptedJSON(password string, scryptParams utils.ScryptParam OffChainPublicKey: key.OffChainSigning.PublicKey(), ConfigPublicKey: key.PublicKeyConfig(), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/p2pkey/export.go b/core/services/keystore/keys/p2pkey/export.go index b81cf1d02d2..0db73167c4b 100644 --- a/core/services/keystore/keys/p2pkey/export.go +++ b/core/services/keystore/keys/p2pkey/export.go @@ -1,9 +1,7 @@ package p2pkey import ( - keystore "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" + "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -42,17 +40,13 @@ func (key KeyV2) ToEncryptedJSON(password string, scryptParams utils.ScryptParam password, scryptParams, adulteratedPassword, - func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) (EncryptedP2PKeyExport, error) { - rawPubKey, err := key.GetPublic().Bytes() - if err != nil { - return EncryptedP2PKeyExport{}, errors.Wrapf(err, "could not get raw public key") - } + func(id string, key KeyV2, cryptoJSON keystore.CryptoJSON) EncryptedP2PKeyExport { return EncryptedP2PKeyExport{ KeyType: id, - PublicKey: hexutil.Encode(rawPubKey), + PublicKey: key.PublicKeyHex(), PeerID: key.PeerID(), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/p2pkey/key.go b/core/services/keystore/keys/p2pkey/key.go index 6a96103dacb..abf4f70294c 100644 --- a/core/services/keystore/keys/p2pkey/key.go +++ b/core/services/keystore/keys/p2pkey/key.go @@ -1,6 +1,7 @@ package p2pkey import ( + "crypto/ed25519" "database/sql/driver" "encoding/hex" "encoding/json" @@ -8,14 +9,14 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/keystore" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" - "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" + + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" ) -// Key represents a libp2p private key +// Key represents a p2p private key type Key struct { - cryptop2p.PrivKey + PrivKey ed25519.PrivateKey } func (k Key) ToV2() KeyV2 { @@ -25,7 +26,7 @@ func (k Key) ToV2() KeyV2 { } } -// PublicKeyBytes is generated using cryptop2p.PubKey.Raw() +// PublicKeyBytes is a [ed25519.PublicKey] type PublicKeyBytes []byte func (pkb PublicKeyBytes) String() string { @@ -47,7 +48,7 @@ func (pkb *PublicKeyBytes) UnmarshalJSON(input []byte) error { return err } - *pkb = PublicKeyBytes(result) + *pkb = result return nil } @@ -66,19 +67,19 @@ func (pkb PublicKeyBytes) Value() (driver.Value, error) { } func (k Key) GetPeerID() (PeerID, error) { - peerID, err := peer.IDFromPrivateKey(k) + peerID, err := ragep2ptypes.PeerIDFromPrivateKey(k.PrivKey) if err != nil { - return "", errors.WithStack(err) + return PeerID{}, errors.WithStack(err) } return PeerID(peerID), err } func (k Key) PeerID() PeerID { - peerID, err := peer.IDFromPrivateKey(k) + peerID, err := k.GetPeerID() if err != nil { panic(err) } - return PeerID(peerID) + return peerID } type EncryptedP2PKey struct { @@ -113,7 +114,8 @@ func (ep2pk EncryptedP2PKey) Decrypt(auth string) (k Key, err error) { if err != nil { return k, errors.Wrapf(err, "could not decrypt P2P key %s (0x%x)", ep2pk.PeerID.String(), ep2pk.PubKey) } - privK, err := cryptop2p.UnmarshalPrivateKey(marshalledPrivK) + + privK, err := UnmarshalPrivateKey(marshalledPrivK) if err != nil { return k, errors.Wrapf(err, "could not unmarshal P2P private key for %s (0x%x)", ep2pk.PeerID.String(), ep2pk.PubKey) } diff --git a/core/services/keystore/keys/p2pkey/key_test.go b/core/services/keystore/keys/p2pkey/key_test.go index fc111f14219..57490483e86 100644 --- a/core/services/keystore/keys/p2pkey/key_test.go +++ b/core/services/keystore/keys/p2pkey/key_test.go @@ -1,13 +1,13 @@ package p2pkey import ( + "crypto/ed25519" "crypto/rand" "encoding/hex" "encoding/json" "testing" "github.com/ethereum/go-ethereum/accounts/keystore" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -15,7 +15,7 @@ import ( ) func TestP2PKeys_KeyStruct(t *testing.T) { - pk, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) + _, pk, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) k := Key{PrivKey: pk} @@ -37,12 +37,10 @@ func TestP2PKeys_KeyStruct(t *testing.T) { } func TestP2PKeys_PublicKeyBytes(t *testing.T) { - _, pk, err := cryptop2p.GenerateEd25519Key(rand.Reader) - require.NoError(t, err) - r, err := pk.Raw() + pk, _, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - pkb := PublicKeyBytes(r) + pkb := PublicKeyBytes(pk) assert.Equal(t, hex.EncodeToString(pkb), pkb.String()) b, err := pkb.MarshalJSON() @@ -55,7 +53,7 @@ func TestP2PKeys_PublicKeyBytes(t *testing.T) { err = pkb.UnmarshalJSON([]byte("")) assert.Error(t, err) - err = pkb.Scan(r) + err = pkb.Scan([]byte(pk)) assert.NoError(t, err) err = pkb.Scan("invalid-type") @@ -67,16 +65,15 @@ func TestP2PKeys_PublicKeyBytes(t *testing.T) { } func TestP2PKeys_EncryptedP2PKey(t *testing.T) { - privk, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) + _, privk, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) k := Key{PrivKey: privk} - pubkr, err := k.GetPublic().Raw() - require.NoError(t, err) + pubkr := k.PrivKey.Public().(ed25519.PublicKey) var marshalledPrivK []byte - marshalledPrivK, err = cryptop2p.MarshalPrivateKey(k) + marshalledPrivK, err = MarshalPrivateKey(k.PrivKey) require.NoError(t, err) cryptoJSON, err := keystore.EncryptDataV3(marshalledPrivK, []byte(adulteratedPassword("password")), utils.FastScryptParams.N, utils.FastScryptParams.P) require.NoError(t, err) @@ -86,7 +83,7 @@ func TestP2PKeys_EncryptedP2PKey(t *testing.T) { p2pk := EncryptedP2PKey{ ID: 1, PeerID: k.PeerID(), - PubKey: pubkr, + PubKey: []byte(pubkr), EncryptedPrivKey: encryptedPrivKey, } diff --git a/core/services/keystore/keys/p2pkey/key_v2.go b/core/services/keystore/keys/p2pkey/key_v2.go index d92302cf5f9..6af71d5e2d7 100644 --- a/core/services/keystore/keys/p2pkey/key_v2.go +++ b/core/services/keystore/keys/p2pkey/key_v2.go @@ -1,20 +1,24 @@ package p2pkey import ( + "bytes" "crypto/ed25519" "crypto/rand" "encoding/hex" + "errors" "fmt" "math/big" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" - peer "github.com/libp2p/go-libp2p-core/peer" + "github.com/smartcontractkit/libocr/ragep2p/types" ) +var libp2pPBPrefix = []byte{0x08, 0x01, 0x12, 0x40} + +// Raw is an encoded protocol buffer. type Raw []byte func (raw Raw) Key() KeyV2 { - privKey, err := cryptop2p.UnmarshalPrivateKey(raw) + privKey, err := UnmarshalPrivateKey(raw) if err != nil { panic(err) } @@ -25,6 +29,17 @@ func (raw Raw) Key() KeyV2 { return key } +func UnmarshalPrivateKey(raw Raw) (ed25519.PrivateKey, error) { + if !bytes.HasPrefix(raw, libp2pPBPrefix) { + return nil, errors.New("invalid key: missing libp2p protobuf prefix") + } + return ed25519.PrivateKey(raw[len(libp2pPBPrefix):]), nil +} + +func MarshalPrivateKey(key ed25519.PrivateKey) ([]byte, error) { + return bytes.Join([][]byte{libp2pPBPrefix, key}, nil), nil +} + func (raw Raw) String() string { return "" } @@ -36,12 +51,12 @@ func (raw Raw) GoString() string { var _ fmt.GoStringer = &KeyV2{} type KeyV2 struct { - cryptop2p.PrivKey - peerID PeerID + PrivKey ed25519.PrivateKey + peerID PeerID } func NewV2() (KeyV2, error) { - privKey, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) + _, privKey, err := ed25519.GenerateKey(rand.Reader) if err != nil { return KeyV2{}, err } @@ -52,11 +67,7 @@ func MustNewV2XXXTestingOnly(k *big.Int) KeyV2 { seed := make([]byte, ed25519.SeedSize) copy(seed, k.Bytes()) pk := ed25519.NewKeyFromSeed(seed[:]) - p2pPrivKey, err := cryptop2p.UnmarshalEd25519PrivateKey(pk[:]) - if err != nil { - panic(err) - } - key, err := fromPrivkey(p2pPrivKey) + key, err := fromPrivkey(pk) if err != nil { panic(err) } @@ -64,11 +75,11 @@ func MustNewV2XXXTestingOnly(k *big.Int) KeyV2 { } func (key KeyV2) ID() string { - return peer.ID(key.peerID).String() + return types.PeerID(key.peerID).String() } func (key KeyV2) Raw() Raw { - marshalledPrivK, err := cryptop2p.MarshalPrivateKey(key.PrivKey) + marshalledPrivK, err := MarshalPrivateKey(key.PrivKey) if err != nil { panic(err) } @@ -80,10 +91,7 @@ func (key KeyV2) PeerID() PeerID { } func (key KeyV2) PublicKeyHex() string { - pubKeyBytes, err := key.GetPublic().Raw() - if err != nil { - panic(err) - } + pubKeyBytes := key.PrivKey.Public().(ed25519.PublicKey) return hex.EncodeToString(pubKeyBytes) } @@ -95,8 +103,8 @@ func (key KeyV2) GoString() string { return key.String() } -func fromPrivkey(privKey cryptop2p.PrivKey) (KeyV2, error) { - peerID, err := peer.IDFromPrivateKey(privKey) +func fromPrivkey(privKey ed25519.PrivateKey) (KeyV2, error) { + peerID, err := types.PeerIDFromPrivateKey(privKey) if err != nil { return KeyV2{}, err } diff --git a/core/services/keystore/keys/p2pkey/key_v2_test.go b/core/services/keystore/keys/p2pkey/key_v2_test.go index 53c3c302384..d93678b8f2d 100644 --- a/core/services/keystore/keys/p2pkey/key_v2_test.go +++ b/core/services/keystore/keys/p2pkey/key_v2_test.go @@ -1,38 +1,36 @@ package p2pkey import ( + "crypto/ed25519" "crypto/rand" "encoding/hex" "testing" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" - "github.com/libp2p/go-libp2p-core/peer" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestP2PKeys_Raw(t *testing.T) { - pk, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) - require.NoError(t, err) - pkr, err := pk.Raw() + _, pk, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - r := Raw(pkr) + r := Raw(pk) assert.Equal(t, r.String(), r.GoString()) assert.Equal(t, "", r.String()) } func TestP2PKeys_KeyV2(t *testing.T) { - pk, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) + _, pk, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) k := Key{PrivKey: pk} kv2 := k.ToV2() - pkv2, err := kv2.GetPublic().Raw() - require.NoError(t, err) + + pkv2 := kv2.PrivKey.Public().(ed25519.PublicKey) assert.Equal(t, kv2.String(), kv2.GoString()) - assert.Equal(t, peer.ID(k.PeerID()).String(), kv2.ID()) + assert.Equal(t, ragep2ptypes.PeerID(k.PeerID()).String(), kv2.ID()) assert.Equal(t, hex.EncodeToString(pkv2), kv2.PublicKeyHex()) } diff --git a/core/services/keystore/keys/p2pkey/peer_id.go b/core/services/keystore/keys/p2pkey/peer_id.go index 2147fa97744..38fbc471b59 100644 --- a/core/services/keystore/keys/p2pkey/peer_id.go +++ b/core/services/keystore/keys/p2pkey/peer_id.go @@ -6,13 +6,14 @@ import ( "fmt" "strings" - "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" + + "github.com/smartcontractkit/libocr/ragep2p/types" ) const peerIDPrefix = "p2p_" -type PeerID peer.ID +type PeerID types.PeerID func MakePeerID(s string) (PeerID, error) { var peerID PeerID @@ -22,15 +23,14 @@ func MakePeerID(s string) (PeerID, error) { func (p PeerID) String() string { // Handle a zero peerID more gracefully, i.e. print it as empty string rather // than `p2p_` - raw := p.Raw() - if raw == "" { + if p == (PeerID{}) { return "" } - return fmt.Sprintf("%s%s", peerIDPrefix, raw) + return fmt.Sprintf("%s%s", peerIDPrefix, p.Raw()) } func (p PeerID) Raw() string { - return peer.ID(p).String() + return types.PeerID(p).String() } func (p *PeerID) UnmarshalString(s string) error { @@ -38,6 +38,9 @@ func (p *PeerID) UnmarshalString(s string) error { } func (p *PeerID) MarshalText() ([]byte, error) { + if *p == (PeerID{}) { + return nil, nil + } return []byte(p.Raw()), nil } @@ -51,7 +54,8 @@ func (p *PeerID) UnmarshalText(bs []byte) error { return nil } - peerID, err := peer.Decode(input) + var peerID types.PeerID + err := peerID.UnmarshalText([]byte(input)) if err != nil { return errors.Wrapf(err, `PeerID#UnmarshalText("%v")`, input) } @@ -60,7 +64,7 @@ func (p *PeerID) UnmarshalText(bs []byte) error { } func (p *PeerID) Scan(value interface{}) error { - *p = PeerID("") + *p = PeerID{} switch s := value.(type) { case string: if s != "" { @@ -74,7 +78,8 @@ func (p *PeerID) Scan(value interface{}) error { } func (p PeerID) Value() (driver.Value, error) { - return peer.Encode(peer.ID(p)), nil + b, err := types.PeerID(p).MarshalText() + return string(b), err } func (p PeerID) MarshalJSON() ([]byte, error) { diff --git a/core/services/keystore/keys/p2pkey/peer_id_test.go b/core/services/keystore/keys/p2pkey/peer_id_test.go index 197c54624fb..c648fec8de8 100644 --- a/core/services/keystore/keys/p2pkey/peer_id_test.go +++ b/core/services/keystore/keys/p2pkey/peer_id_test.go @@ -10,16 +10,16 @@ import ( func TestP2PKeys_PeerID(t *testing.T) { t.Run("make peer ID", func(t *testing.T) { - id, err := MakePeerID("11") + id, err := MakePeerID("12D3KooWM1111111111111111111111111111111111111111111") require.NoError(t, err) _, err = MakePeerID("invalid") assert.Error(t, err) - assert.Equal(t, "p2p_11", id.String()) + assert.Equal(t, "p2p_12D3KooWM1111111111111111111111111111111111111111111", id.String()) }) t.Run("unmarshals new ID", func(t *testing.T) { - id, err := MakePeerID("11") + id, err := MakePeerID("12D3KooWM1111111111111111111111111111111111111111111") require.NoError(t, err) fakeKey := MustNewV2XXXTestingOnly(big.NewInt(1)) @@ -30,7 +30,7 @@ func TestP2PKeys_PeerID(t *testing.T) { }) t.Run("scans new ID", func(t *testing.T) { - id, err := MakePeerID("11") + id, err := MakePeerID("12D3KooWM1111111111111111111111111111111111111111111") require.NoError(t, err) fakeKey := MustNewV2XXXTestingOnly(big.NewInt(1)) diff --git a/core/services/keystore/keys/solkey/export.go b/core/services/keystore/keys/solkey/export.go index 27f19fb5ed5..59e84136bc6 100644 --- a/core/services/keystore/keys/solkey/export.go +++ b/core/services/keystore/keys/solkey/export.go @@ -33,12 +33,12 @@ func (key Key) ToEncryptedJSON(password string, scryptParams utils.ScryptParams) password, scryptParams, adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: hex.EncodeToString(key.pubKey), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/starkkey/export.go b/core/services/keystore/keys/starkkey/export.go index 366243a8da2..26770028ca9 100644 --- a/core/services/keystore/keys/starkkey/export.go +++ b/core/services/keystore/keys/starkkey/export.go @@ -31,12 +31,12 @@ func ToEncryptedJSON(key Key, password string, scryptParams utils.ScryptParams) password, scryptParams, adulteratedPassword, - func(id string, key Key, cryptoJSON keystore.CryptoJSON) (keys.EncryptedKeyExport, error) { + func(id string, key Key, cryptoJSON keystore.CryptoJSON) keys.EncryptedKeyExport { return keys.EncryptedKeyExport{ KeyType: id, PublicKey: key.StarkKeyStr(), Crypto: cryptoJSON, - }, nil + } }, ) } diff --git a/core/services/keystore/keys/vrfkey/crypto.go b/core/services/keystore/keys/vrfkey/crypto.go index a3792b98075..fe105d13f11 100644 --- a/core/services/keystore/keys/vrfkey/crypto.go +++ b/core/services/keystore/keys/vrfkey/crypto.go @@ -7,8 +7,9 @@ import ( "github.com/ethereum/go-ethereum/common" "go.dedis.ch/kyber/v3" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - "github.com/smartcontractkit/chainlink/v2/core/utils" bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) @@ -19,7 +20,7 @@ import ( var ( // FieldSize is number of elements in secp256k1's base field, i.e. GF(FieldSize) - FieldSize = utils.HexToBig( + FieldSize = mustParseBig( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", ) Secp256k1Curve = &secp256k1.Secp256k1{} @@ -176,3 +177,11 @@ func ScalarFromCurvePoints( msg = append(msg, uWitness[:]...) return bm.I().SetBytes(utils.MustHash(string(msg)).Bytes()) } + +func mustParseBig(hx string) *big.Int { + n, err := hex.ParseBig(hx) + if err != nil { + panic(fmt.Errorf(`failed to convert "%s" as hex to big.Int`, hx)) + } + return n +} diff --git a/core/services/keystore/keys/vrfkey/key_v2.go b/core/services/keystore/keys/vrfkey/key_v2.go index 49c5a4999d8..786bd39b3f0 100644 --- a/core/services/keystore/keys/vrfkey/key_v2.go +++ b/core/services/keystore/keys/vrfkey/key_v2.go @@ -9,8 +9,8 @@ import ( "github.com/pkg/errors" "go.dedis.ch/kyber/v3" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - "github.com/smartcontractkit/chainlink/v2/core/utils" bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) diff --git a/core/services/keystore/keys/vrfkey/proof.go b/core/services/keystore/keys/vrfkey/proof.go index d4ee9b160b7..b7f9032255b 100644 --- a/core/services/keystore/keys/vrfkey/proof.go +++ b/core/services/keystore/keys/vrfkey/proof.go @@ -6,8 +6,8 @@ import ( "go.dedis.ch/kyber/v3" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - "github.com/smartcontractkit/chainlink/v2/core/utils" bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) diff --git a/core/services/keystore/mocks/cosmos.go b/core/services/keystore/mocks/cosmos.go index b8d5d56c373..40ba12d15d7 100644 --- a/core/services/keystore/mocks/cosmos.go +++ b/core/services/keystore/mocks/cosmos.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type Cosmos struct { func (_m *Cosmos) Add(key cosmoskey.Key) error { ret := _m.Called(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) @@ -31,6 +35,10 @@ func (_m *Cosmos) Add(key cosmoskey.Key) error { func (_m *Cosmos) Create() (cosmoskey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 cosmoskey.Key var r1 error if rf, ok := ret.Get(0).(func() (cosmoskey.Key, error)); ok { @@ -55,6 +63,10 @@ func (_m *Cosmos) Create() (cosmoskey.Key, error) { func (_m *Cosmos) Delete(id string) (cosmoskey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 cosmoskey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (cosmoskey.Key, error)); ok { @@ -79,6 +91,10 @@ func (_m *Cosmos) Delete(id string) (cosmoskey.Key, error) { func (_m *Cosmos) EnsureKey() error { ret := _m.Called() + 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() @@ -93,6 +109,10 @@ func (_m *Cosmos) EnsureKey() error { func (_m *Cosmos) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -119,6 +139,10 @@ func (_m *Cosmos) Export(id string, password string) ([]byte, error) { func (_m *Cosmos) Get(id string) (cosmoskey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 cosmoskey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (cosmoskey.Key, error)); ok { @@ -143,6 +167,10 @@ func (_m *Cosmos) Get(id string) (cosmoskey.Key, error) { func (_m *Cosmos) GetAll() ([]cosmoskey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []cosmoskey.Key var r1 error if rf, ok := ret.Get(0).(func() ([]cosmoskey.Key, error)); ok { @@ -169,6 +197,10 @@ func (_m *Cosmos) GetAll() ([]cosmoskey.Key, error) { func (_m *Cosmos) Import(keyJSON []byte, password string) (cosmoskey.Key, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 cosmoskey.Key var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (cosmoskey.Key, error)); ok { diff --git a/core/services/keystore/mocks/csa.go b/core/services/keystore/mocks/csa.go index 4f4e02a2fe6..ad5b25a27bd 100644 --- a/core/services/keystore/mocks/csa.go +++ b/core/services/keystore/mocks/csa.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type CSA struct { func (_m *CSA) Add(key csakey.KeyV2) error { ret := _m.Called(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) @@ -31,6 +35,10 @@ func (_m *CSA) Add(key csakey.KeyV2) error { func (_m *CSA) Create() (csakey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 csakey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() (csakey.KeyV2, error)); ok { @@ -55,6 +63,10 @@ func (_m *CSA) Create() (csakey.KeyV2, error) { func (_m *CSA) Delete(id string) (csakey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 csakey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (csakey.KeyV2, error)); ok { @@ -79,6 +91,10 @@ func (_m *CSA) Delete(id string) (csakey.KeyV2, error) { func (_m *CSA) EnsureKey() error { ret := _m.Called() + 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() @@ -93,6 +109,10 @@ func (_m *CSA) EnsureKey() error { func (_m *CSA) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -119,6 +139,10 @@ func (_m *CSA) Export(id string, password string) ([]byte, error) { func (_m *CSA) Get(id string) (csakey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 csakey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (csakey.KeyV2, error)); ok { @@ -143,6 +167,10 @@ func (_m *CSA) Get(id string) (csakey.KeyV2, error) { func (_m *CSA) GetAll() ([]csakey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []csakey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() ([]csakey.KeyV2, error)); ok { @@ -169,6 +197,10 @@ func (_m *CSA) GetAll() ([]csakey.KeyV2, error) { func (_m *CSA) Import(keyJSON []byte, password string) (csakey.KeyV2, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 csakey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (csakey.KeyV2, error)); ok { diff --git a/core/services/keystore/mocks/dkg_encrypt.go b/core/services/keystore/mocks/dkg_encrypt.go index e1f83888c48..e7e52bada25 100644 --- a/core/services/keystore/mocks/dkg_encrypt.go +++ b/core/services/keystore/mocks/dkg_encrypt.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type DKGEncrypt struct { func (_m *DKGEncrypt) Add(key dkgencryptkey.Key) error { ret := _m.Called(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) @@ -31,6 +35,10 @@ func (_m *DKGEncrypt) Add(key dkgencryptkey.Key) error { func (_m *DKGEncrypt) Create() (dkgencryptkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 dkgencryptkey.Key var r1 error if rf, ok := ret.Get(0).(func() (dkgencryptkey.Key, error)); ok { @@ -55,6 +63,10 @@ func (_m *DKGEncrypt) Create() (dkgencryptkey.Key, error) { func (_m *DKGEncrypt) Delete(id string) (dkgencryptkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 dkgencryptkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (dkgencryptkey.Key, error)); ok { @@ -79,6 +91,10 @@ func (_m *DKGEncrypt) Delete(id string) (dkgencryptkey.Key, error) { func (_m *DKGEncrypt) EnsureKey() error { ret := _m.Called() + 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() @@ -93,6 +109,10 @@ func (_m *DKGEncrypt) EnsureKey() error { func (_m *DKGEncrypt) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -119,6 +139,10 @@ func (_m *DKGEncrypt) Export(id string, password string) ([]byte, error) { func (_m *DKGEncrypt) Get(id string) (dkgencryptkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 dkgencryptkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (dkgencryptkey.Key, error)); ok { @@ -143,6 +167,10 @@ func (_m *DKGEncrypt) Get(id string) (dkgencryptkey.Key, error) { func (_m *DKGEncrypt) GetAll() ([]dkgencryptkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []dkgencryptkey.Key var r1 error if rf, ok := ret.Get(0).(func() ([]dkgencryptkey.Key, error)); ok { @@ -169,6 +197,10 @@ func (_m *DKGEncrypt) GetAll() ([]dkgencryptkey.Key, error) { func (_m *DKGEncrypt) Import(keyJSON []byte, password string) (dkgencryptkey.Key, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 dkgencryptkey.Key var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (dkgencryptkey.Key, error)); ok { diff --git a/core/services/keystore/mocks/dkg_sign.go b/core/services/keystore/mocks/dkg_sign.go index ed1aa756a6d..e5c6434d90d 100644 --- a/core/services/keystore/mocks/dkg_sign.go +++ b/core/services/keystore/mocks/dkg_sign.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type DKGSign struct { func (_m *DKGSign) Add(key dkgsignkey.Key) error { ret := _m.Called(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) @@ -31,6 +35,10 @@ func (_m *DKGSign) Add(key dkgsignkey.Key) error { func (_m *DKGSign) Create() (dkgsignkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 dkgsignkey.Key var r1 error if rf, ok := ret.Get(0).(func() (dkgsignkey.Key, error)); ok { @@ -55,6 +63,10 @@ func (_m *DKGSign) Create() (dkgsignkey.Key, error) { func (_m *DKGSign) Delete(id string) (dkgsignkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 dkgsignkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (dkgsignkey.Key, error)); ok { @@ -79,6 +91,10 @@ func (_m *DKGSign) Delete(id string) (dkgsignkey.Key, error) { func (_m *DKGSign) EnsureKey() error { ret := _m.Called() + 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() @@ -93,6 +109,10 @@ func (_m *DKGSign) EnsureKey() error { func (_m *DKGSign) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -119,6 +139,10 @@ func (_m *DKGSign) Export(id string, password string) ([]byte, error) { func (_m *DKGSign) Get(id string) (dkgsignkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 dkgsignkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (dkgsignkey.Key, error)); ok { @@ -143,6 +167,10 @@ func (_m *DKGSign) Get(id string) (dkgsignkey.Key, error) { func (_m *DKGSign) GetAll() ([]dkgsignkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []dkgsignkey.Key var r1 error if rf, ok := ret.Get(0).(func() ([]dkgsignkey.Key, error)); ok { @@ -169,6 +197,10 @@ func (_m *DKGSign) GetAll() ([]dkgsignkey.Key, error) { func (_m *DKGSign) Import(keyJSON []byte, password string) (dkgsignkey.Key, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 dkgsignkey.Key var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (dkgsignkey.Key, error)); ok { diff --git a/core/services/keystore/mocks/eth.go b/core/services/keystore/mocks/eth.go index 6a076e130d1..b3827398fd5 100644 --- a/core/services/keystore/mocks/eth.go +++ b/core/services/keystore/mocks/eth.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -31,6 +31,10 @@ func (_m *Eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) e _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Add") + } + var r0 error if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { r0 = rf(address, chainID, qopts...) @@ -45,6 +49,10 @@ func (_m *Eth) Add(address common.Address, chainID *big.Int, qopts ...pg.QOpt) e func (_m *Eth) CheckEnabled(address common.Address, chainID *big.Int) error { ret := _m.Called(address, chainID) + if len(ret) == 0 { + panic("no return value specified for CheckEnabled") + } + var r0 error if rf, ok := ret.Get(0).(func(common.Address, *big.Int) error); ok { r0 = rf(address, chainID) @@ -65,6 +73,10 @@ func (_m *Eth) Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(...*big.Int) (ethkey.KeyV2, error)); ok { @@ -89,6 +101,10 @@ func (_m *Eth) Create(chainIDs ...*big.Int) (ethkey.KeyV2, error) { func (_m *Eth) Delete(id string) (ethkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (ethkey.KeyV2, error)); ok { @@ -120,6 +136,10 @@ func (_m *Eth) Disable(address common.Address, chainID *big.Int, qopts ...pg.QOp _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Disable") + } + var r0 error if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { r0 = rf(address, chainID, qopts...) @@ -141,6 +161,10 @@ func (_m *Eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Enable") + } + var r0 error if rf, ok := ret.Get(0).(func(common.Address, *big.Int, ...pg.QOpt) error); ok { r0 = rf(address, chainID, qopts...) @@ -155,6 +179,10 @@ func (_m *Eth) Enable(address common.Address, chainID *big.Int, qopts ...pg.QOpt func (_m *Eth) EnabledAddressesForChain(chainID *big.Int) ([]common.Address, error) { ret := _m.Called(chainID) + if len(ret) == 0 { + panic("no return value specified for EnabledAddressesForChain") + } + var r0 []common.Address var r1 error if rf, ok := ret.Get(0).(func(*big.Int) ([]common.Address, error)); ok { @@ -181,6 +209,10 @@ func (_m *Eth) EnabledAddressesForChain(chainID *big.Int) ([]common.Address, err func (_m *Eth) EnabledKeysForChain(chainID *big.Int) ([]ethkey.KeyV2, error) { ret := _m.Called(chainID) + if len(ret) == 0 { + panic("no return value specified for EnabledKeysForChain") + } + var r0 []ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(*big.Int) ([]ethkey.KeyV2, error)); ok { @@ -213,6 +245,10 @@ func (_m *Eth) EnsureKeys(chainIDs ...*big.Int) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for EnsureKeys") + } + var r0 error if rf, ok := ret.Get(0).(func(...*big.Int) error); ok { r0 = rf(chainIDs...) @@ -227,6 +263,10 @@ func (_m *Eth) EnsureKeys(chainIDs ...*big.Int) error { func (_m *Eth) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -253,6 +293,10 @@ func (_m *Eth) Export(id string, password string) ([]byte, error) { func (_m *Eth) Get(id string) (ethkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (ethkey.KeyV2, error)); ok { @@ -277,6 +321,10 @@ func (_m *Eth) Get(id string) (ethkey.KeyV2, error) { func (_m *Eth) GetAll() ([]ethkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() ([]ethkey.KeyV2, error)); ok { @@ -310,6 +358,10 @@ func (_m *Eth) GetRoundRobinAddress(chainID *big.Int, addresses ...common.Addres _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetRoundRobinAddress") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*big.Int, ...common.Address) (common.Address, error)); ok { @@ -336,6 +388,10 @@ func (_m *Eth) GetRoundRobinAddress(chainID *big.Int, addresses ...common.Addres func (_m *Eth) GetState(id string, chainID *big.Int) (ethkey.State, error) { ret := _m.Called(id, chainID) + if len(ret) == 0 { + panic("no return value specified for GetState") + } + var r0 ethkey.State var r1 error if rf, ok := ret.Get(0).(func(string, *big.Int) (ethkey.State, error)); ok { @@ -360,6 +416,10 @@ func (_m *Eth) GetState(id string, chainID *big.Int) (ethkey.State, error) { func (_m *Eth) GetStateForKey(_a0 ethkey.KeyV2) (ethkey.State, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetStateForKey") + } + var r0 ethkey.State var r1 error if rf, ok := ret.Get(0).(func(ethkey.KeyV2) (ethkey.State, error)); ok { @@ -384,6 +444,10 @@ func (_m *Eth) GetStateForKey(_a0 ethkey.KeyV2) (ethkey.State, error) { func (_m *Eth) GetStatesForChain(chainID *big.Int) ([]ethkey.State, error) { ret := _m.Called(chainID) + if len(ret) == 0 { + panic("no return value specified for GetStatesForChain") + } + var r0 []ethkey.State var r1 error if rf, ok := ret.Get(0).(func(*big.Int) ([]ethkey.State, error)); ok { @@ -410,6 +474,10 @@ func (_m *Eth) GetStatesForChain(chainID *big.Int) ([]ethkey.State, error) { func (_m *Eth) GetStatesForKeys(_a0 []ethkey.KeyV2) ([]ethkey.State, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetStatesForKeys") + } + var r0 []ethkey.State var r1 error if rf, ok := ret.Get(0).(func([]ethkey.KeyV2) ([]ethkey.State, error)); ok { @@ -443,6 +511,10 @@ func (_m *Eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (et _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 ethkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func([]byte, string, ...*big.Int) (ethkey.KeyV2, error)); ok { @@ -467,6 +539,10 @@ func (_m *Eth) Import(keyJSON []byte, password string, chainIDs ...*big.Int) (et func (_m *Eth) SignTx(fromAddress common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) { ret := _m.Called(fromAddress, tx, chainID) + if len(ret) == 0 { + panic("no return value specified for SignTx") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(common.Address, *types.Transaction, *big.Int) (*types.Transaction, error)); ok { @@ -493,6 +569,10 @@ func (_m *Eth) SignTx(fromAddress common.Address, tx *types.Transaction, chainID func (_m *Eth) SubscribeToKeyChanges() (chan struct{}, func()) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for SubscribeToKeyChanges") + } + var r0 chan struct{} var r1 func() if rf, ok := ret.Get(0).(func() (chan struct{}, func())); ok { diff --git a/core/services/keystore/mocks/master.go b/core/services/keystore/mocks/master.go index d29d2fa4692..3025f5b103a 100644 --- a/core/services/keystore/mocks/master.go +++ b/core/services/keystore/mocks/master.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type Master struct { func (_m *Master) CSA() keystore.CSA { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CSA") + } + var r0 keystore.CSA if rf, ok := ret.Get(0).(func() keystore.CSA); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *Master) CSA() keystore.CSA { func (_m *Master) Cosmos() keystore.Cosmos { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Cosmos") + } + var r0 keystore.Cosmos if rf, ok := ret.Get(0).(func() keystore.Cosmos); ok { r0 = rf() @@ -48,6 +56,10 @@ func (_m *Master) Cosmos() keystore.Cosmos { func (_m *Master) DKGEncrypt() keystore.DKGEncrypt { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DKGEncrypt") + } + var r0 keystore.DKGEncrypt if rf, ok := ret.Get(0).(func() keystore.DKGEncrypt); ok { r0 = rf() @@ -64,6 +76,10 @@ func (_m *Master) DKGEncrypt() keystore.DKGEncrypt { func (_m *Master) DKGSign() keystore.DKGSign { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DKGSign") + } + var r0 keystore.DKGSign if rf, ok := ret.Get(0).(func() keystore.DKGSign); ok { r0 = rf() @@ -80,6 +96,10 @@ func (_m *Master) DKGSign() keystore.DKGSign { func (_m *Master) Eth() keystore.Eth { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Eth") + } + var r0 keystore.Eth if rf, ok := ret.Get(0).(func() keystore.Eth); ok { r0 = rf() @@ -96,6 +116,10 @@ func (_m *Master) Eth() keystore.Eth { func (_m *Master) IsEmpty() (bool, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsEmpty") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func() (bool, error)); ok { @@ -120,6 +144,10 @@ func (_m *Master) IsEmpty() (bool, error) { func (_m *Master) OCR() keystore.OCR { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OCR") + } + var r0 keystore.OCR if rf, ok := ret.Get(0).(func() keystore.OCR); ok { r0 = rf() @@ -136,6 +164,10 @@ func (_m *Master) OCR() keystore.OCR { func (_m *Master) OCR2() keystore.OCR2 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for OCR2") + } + var r0 keystore.OCR2 if rf, ok := ret.Get(0).(func() keystore.OCR2); ok { r0 = rf() @@ -152,6 +184,10 @@ func (_m *Master) OCR2() keystore.OCR2 { func (_m *Master) P2P() keystore.P2P { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for P2P") + } + var r0 keystore.P2P if rf, ok := ret.Get(0).(func() keystore.P2P); ok { r0 = rf() @@ -168,6 +204,10 @@ func (_m *Master) P2P() keystore.P2P { func (_m *Master) Solana() keystore.Solana { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Solana") + } + var r0 keystore.Solana if rf, ok := ret.Get(0).(func() keystore.Solana); ok { r0 = rf() @@ -184,6 +224,10 @@ func (_m *Master) Solana() keystore.Solana { func (_m *Master) StarkNet() keystore.StarkNet { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for StarkNet") + } + var r0 keystore.StarkNet if rf, ok := ret.Get(0).(func() keystore.StarkNet); ok { r0 = rf() @@ -200,6 +244,10 @@ func (_m *Master) StarkNet() keystore.StarkNet { func (_m *Master) Unlock(password string) error { ret := _m.Called(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) @@ -214,6 +262,10 @@ func (_m *Master) Unlock(password string) error { func (_m *Master) VRF() keystore.VRF { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for VRF") + } + var r0 keystore.VRF if rf, ok := ret.Get(0).(func() keystore.VRF); ok { r0 = rf() diff --git a/core/services/keystore/mocks/ocr.go b/core/services/keystore/mocks/ocr.go index 505eaa0e46e..e1c4d588330 100644 --- a/core/services/keystore/mocks/ocr.go +++ b/core/services/keystore/mocks/ocr.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type OCR struct { func (_m *OCR) Add(key ocrkey.KeyV2) error { ret := _m.Called(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) @@ -30,6 +34,10 @@ func (_m *OCR) Add(key ocrkey.KeyV2) error { func (_m *OCR) Create() (ocrkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 ocrkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() (ocrkey.KeyV2, error)); ok { @@ -54,6 +62,10 @@ func (_m *OCR) Create() (ocrkey.KeyV2, error) { func (_m *OCR) Delete(id string) (ocrkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 ocrkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (ocrkey.KeyV2, error)); ok { @@ -78,6 +90,10 @@ func (_m *OCR) Delete(id string) (ocrkey.KeyV2, error) { func (_m *OCR) EnsureKey() error { ret := _m.Called() + 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() @@ -92,6 +108,10 @@ func (_m *OCR) EnsureKey() error { func (_m *OCR) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -118,6 +138,10 @@ func (_m *OCR) Export(id string, password string) ([]byte, error) { func (_m *OCR) Get(id string) (ocrkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 ocrkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (ocrkey.KeyV2, error)); ok { @@ -142,6 +166,10 @@ func (_m *OCR) Get(id string) (ocrkey.KeyV2, error) { func (_m *OCR) GetAll() ([]ocrkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []ocrkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() ([]ocrkey.KeyV2, error)); ok { @@ -168,6 +196,10 @@ func (_m *OCR) GetAll() ([]ocrkey.KeyV2, error) { func (_m *OCR) Import(keyJSON []byte, password string) (ocrkey.KeyV2, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 ocrkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (ocrkey.KeyV2, error)); ok { diff --git a/core/services/keystore/mocks/ocr2.go b/core/services/keystore/mocks/ocr2.go index 30d870dcdc7..d44e739deed 100644 --- a/core/services/keystore/mocks/ocr2.go +++ b/core/services/keystore/mocks/ocr2.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type OCR2 struct { func (_m *OCR2) Add(key ocr2key.KeyBundle) error { ret := _m.Called(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) @@ -33,6 +37,10 @@ func (_m *OCR2) Add(key ocr2key.KeyBundle) error { func (_m *OCR2) Create(_a0 chaintype.ChainType) (ocr2key.KeyBundle, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 ocr2key.KeyBundle var r1 error if rf, ok := ret.Get(0).(func(chaintype.ChainType) (ocr2key.KeyBundle, error)); ok { @@ -59,6 +67,10 @@ func (_m *OCR2) Create(_a0 chaintype.ChainType) (ocr2key.KeyBundle, error) { func (_m *OCR2) Delete(id string) error { ret := _m.Called(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) @@ -79,6 +91,10 @@ func (_m *OCR2) EnsureKeys(enabledChains ...chaintype.ChainType) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for EnsureKeys") + } + var r0 error if rf, ok := ret.Get(0).(func(...chaintype.ChainType) error); ok { r0 = rf(enabledChains...) @@ -93,6 +109,10 @@ func (_m *OCR2) EnsureKeys(enabledChains ...chaintype.ChainType) error { func (_m *OCR2) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -119,6 +139,10 @@ func (_m *OCR2) Export(id string, password string) ([]byte, error) { func (_m *OCR2) Get(id string) (ocr2key.KeyBundle, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 ocr2key.KeyBundle var r1 error if rf, ok := ret.Get(0).(func(string) (ocr2key.KeyBundle, error)); ok { @@ -145,6 +169,10 @@ func (_m *OCR2) Get(id string) (ocr2key.KeyBundle, error) { func (_m *OCR2) GetAll() ([]ocr2key.KeyBundle, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []ocr2key.KeyBundle var r1 error if rf, ok := ret.Get(0).(func() ([]ocr2key.KeyBundle, error)); ok { @@ -171,6 +199,10 @@ func (_m *OCR2) GetAll() ([]ocr2key.KeyBundle, error) { func (_m *OCR2) GetAllOfType(_a0 chaintype.ChainType) ([]ocr2key.KeyBundle, error) { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for GetAllOfType") + } + var r0 []ocr2key.KeyBundle var r1 error if rf, ok := ret.Get(0).(func(chaintype.ChainType) ([]ocr2key.KeyBundle, error)); ok { @@ -197,6 +229,10 @@ func (_m *OCR2) GetAllOfType(_a0 chaintype.ChainType) ([]ocr2key.KeyBundle, erro func (_m *OCR2) Import(keyJSON []byte, password string) (ocr2key.KeyBundle, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 ocr2key.KeyBundle var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (ocr2key.KeyBundle, error)); ok { diff --git a/core/services/keystore/mocks/p2p.go b/core/services/keystore/mocks/p2p.go index c91be5a4a92..fa2a1b6ceeb 100644 --- a/core/services/keystore/mocks/p2p.go +++ b/core/services/keystore/mocks/p2p.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type P2P struct { func (_m *P2P) Add(key p2pkey.KeyV2) error { ret := _m.Called(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) @@ -30,6 +34,10 @@ func (_m *P2P) Add(key p2pkey.KeyV2) error { func (_m *P2P) Create() (p2pkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() (p2pkey.KeyV2, error)); ok { @@ -54,6 +62,10 @@ func (_m *P2P) Create() (p2pkey.KeyV2, error) { func (_m *P2P) Delete(id p2pkey.PeerID) (p2pkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(p2pkey.PeerID) (p2pkey.KeyV2, error)); ok { @@ -78,6 +90,10 @@ func (_m *P2P) Delete(id p2pkey.PeerID) (p2pkey.KeyV2, error) { func (_m *P2P) EnsureKey() error { ret := _m.Called() + 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() @@ -92,6 +108,10 @@ func (_m *P2P) EnsureKey() error { func (_m *P2P) Export(id p2pkey.PeerID, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(p2pkey.PeerID, string) ([]byte, error)); ok { @@ -118,6 +138,10 @@ func (_m *P2P) Export(id p2pkey.PeerID, password string) ([]byte, error) { func (_m *P2P) Get(id p2pkey.PeerID) (p2pkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(p2pkey.PeerID) (p2pkey.KeyV2, error)); ok { @@ -142,6 +166,10 @@ func (_m *P2P) Get(id p2pkey.PeerID) (p2pkey.KeyV2, error) { func (_m *P2P) GetAll() ([]p2pkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() ([]p2pkey.KeyV2, error)); ok { @@ -168,6 +196,10 @@ func (_m *P2P) GetAll() ([]p2pkey.KeyV2, error) { func (_m *P2P) GetOrFirst(id p2pkey.PeerID) (p2pkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for GetOrFirst") + } + var r0 p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(p2pkey.PeerID) (p2pkey.KeyV2, error)); ok { @@ -192,6 +224,10 @@ func (_m *P2P) GetOrFirst(id p2pkey.PeerID) (p2pkey.KeyV2, error) { func (_m *P2P) Import(keyJSON []byte, password string) (p2pkey.KeyV2, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 p2pkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (p2pkey.KeyV2, error)); ok { diff --git a/core/services/keystore/mocks/solana.go b/core/services/keystore/mocks/solana.go index 66357e32b93..c2cc4139bab 100644 --- a/core/services/keystore/mocks/solana.go +++ b/core/services/keystore/mocks/solana.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type Solana struct { func (_m *Solana) Add(key solkey.Key) error { ret := _m.Called(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) @@ -33,6 +37,10 @@ func (_m *Solana) Add(key solkey.Key) error { func (_m *Solana) Create() (solkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 solkey.Key var r1 error if rf, ok := ret.Get(0).(func() (solkey.Key, error)); ok { @@ -57,6 +65,10 @@ func (_m *Solana) Create() (solkey.Key, error) { func (_m *Solana) Delete(id string) (solkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 solkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (solkey.Key, error)); ok { @@ -81,6 +93,10 @@ func (_m *Solana) Delete(id string) (solkey.Key, error) { func (_m *Solana) EnsureKey() error { ret := _m.Called() + 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() @@ -95,6 +111,10 @@ func (_m *Solana) EnsureKey() error { func (_m *Solana) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -121,6 +141,10 @@ func (_m *Solana) Export(id string, password string) ([]byte, error) { func (_m *Solana) Get(id string) (solkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 solkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (solkey.Key, error)); ok { @@ -145,6 +169,10 @@ func (_m *Solana) Get(id string) (solkey.Key, error) { func (_m *Solana) GetAll() ([]solkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []solkey.Key var r1 error if rf, ok := ret.Get(0).(func() ([]solkey.Key, error)); ok { @@ -171,6 +199,10 @@ func (_m *Solana) GetAll() ([]solkey.Key, error) { func (_m *Solana) Import(keyJSON []byte, password string) (solkey.Key, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 solkey.Key var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (solkey.Key, error)); ok { @@ -195,6 +227,10 @@ func (_m *Solana) Import(keyJSON []byte, password string) (solkey.Key, error) { func (_m *Solana) Sign(ctx context.Context, id string, msg []byte) ([]byte, error) { ret := _m.Called(ctx, id, msg) + if len(ret) == 0 { + panic("no return value specified for Sign") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, string, []byte) ([]byte, error)); ok { diff --git a/core/services/keystore/mocks/starknet.go b/core/services/keystore/mocks/starknet.go index ff9b52d7136..c3d74a8389f 100644 --- a/core/services/keystore/mocks/starknet.go +++ b/core/services/keystore/mocks/starknet.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type StarkNet struct { func (_m *StarkNet) Add(key starkkey.Key) error { ret := _m.Called(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) @@ -30,6 +34,10 @@ func (_m *StarkNet) Add(key starkkey.Key) error { func (_m *StarkNet) Create() (starkkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 starkkey.Key var r1 error if rf, ok := ret.Get(0).(func() (starkkey.Key, error)); ok { @@ -54,6 +62,10 @@ func (_m *StarkNet) Create() (starkkey.Key, error) { func (_m *StarkNet) Delete(id string) (starkkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 starkkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (starkkey.Key, error)); ok { @@ -78,6 +90,10 @@ func (_m *StarkNet) Delete(id string) (starkkey.Key, error) { func (_m *StarkNet) EnsureKey() error { ret := _m.Called() + 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() @@ -92,6 +108,10 @@ func (_m *StarkNet) EnsureKey() error { func (_m *StarkNet) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -118,6 +138,10 @@ func (_m *StarkNet) Export(id string, password string) ([]byte, error) { func (_m *StarkNet) Get(id string) (starkkey.Key, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 starkkey.Key var r1 error if rf, ok := ret.Get(0).(func(string) (starkkey.Key, error)); ok { @@ -142,6 +166,10 @@ func (_m *StarkNet) Get(id string) (starkkey.Key, error) { func (_m *StarkNet) GetAll() ([]starkkey.Key, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []starkkey.Key var r1 error if rf, ok := ret.Get(0).(func() ([]starkkey.Key, error)); ok { @@ -168,6 +196,10 @@ func (_m *StarkNet) GetAll() ([]starkkey.Key, error) { func (_m *StarkNet) Import(keyJSON []byte, password string) (starkkey.Key, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 starkkey.Key var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (starkkey.Key, error)); ok { diff --git a/core/services/keystore/mocks/vrf.go b/core/services/keystore/mocks/vrf.go index 5aa15dca59e..ab730ebec67 100644 --- a/core/services/keystore/mocks/vrf.go +++ b/core/services/keystore/mocks/vrf.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type VRF struct { func (_m *VRF) Add(key vrfkey.KeyV2) error { ret := _m.Called(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) @@ -33,6 +37,10 @@ func (_m *VRF) Add(key vrfkey.KeyV2) error { func (_m *VRF) Create() (vrfkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Create") + } + var r0 vrfkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() (vrfkey.KeyV2, error)); ok { @@ -57,6 +65,10 @@ func (_m *VRF) Create() (vrfkey.KeyV2, error) { func (_m *VRF) Delete(id string) (vrfkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Delete") + } + var r0 vrfkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (vrfkey.KeyV2, error)); ok { @@ -81,6 +93,10 @@ func (_m *VRF) Delete(id string) (vrfkey.KeyV2, error) { func (_m *VRF) Export(id string, password string) ([]byte, error) { ret := _m.Called(id, password) + if len(ret) == 0 { + panic("no return value specified for Export") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(string, string) ([]byte, error)); ok { @@ -107,6 +123,10 @@ func (_m *VRF) Export(id string, password string) ([]byte, error) { func (_m *VRF) GenerateProof(id string, seed *big.Int) (vrfkey.Proof, error) { ret := _m.Called(id, seed) + if len(ret) == 0 { + panic("no return value specified for GenerateProof") + } + var r0 vrfkey.Proof var r1 error if rf, ok := ret.Get(0).(func(string, *big.Int) (vrfkey.Proof, error)); ok { @@ -131,6 +151,10 @@ func (_m *VRF) GenerateProof(id string, seed *big.Int) (vrfkey.Proof, error) { func (_m *VRF) Get(id string) (vrfkey.KeyV2, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 vrfkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func(string) (vrfkey.KeyV2, error)); ok { @@ -155,6 +179,10 @@ func (_m *VRF) Get(id string) (vrfkey.KeyV2, error) { func (_m *VRF) GetAll() ([]vrfkey.KeyV2, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAll") + } + var r0 []vrfkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func() ([]vrfkey.KeyV2, error)); ok { @@ -181,6 +209,10 @@ func (_m *VRF) GetAll() ([]vrfkey.KeyV2, error) { func (_m *VRF) Import(keyJSON []byte, password string) (vrfkey.KeyV2, error) { ret := _m.Called(keyJSON, password) + if len(ret) == 0 { + panic("no return value specified for Import") + } + var r0 vrfkey.KeyV2 var r1 error if rf, ok := ret.Get(0).(func([]byte, string) (vrfkey.KeyV2, error)); ok { diff --git a/core/services/keystore/models_test.go b/core/services/keystore/models_test.go index f124f16d9b3..93c0f5fcb25 100644 --- a/core/services/keystore/models_test.go +++ b/core/services/keystore/models_test.go @@ -98,9 +98,9 @@ func TestKeyRing_Encrypt_Decrypt(t *testing.T) { } // compare p2p keys require.Equal(t, 2, len(decryptedKeyRing.P2P)) - require.Equal(t, originalKeyRing.P2P[p2p1.ID()].GetPublic(), decryptedKeyRing.P2P[p2p1.ID()].GetPublic()) + require.Equal(t, originalKeyRing.P2P[p2p1.ID()].PublicKeyHex(), decryptedKeyRing.P2P[p2p1.ID()].PublicKeyHex()) require.Equal(t, originalKeyRing.P2P[p2p1.ID()].PeerID(), decryptedKeyRing.P2P[p2p1.ID()].PeerID()) - require.Equal(t, originalKeyRing.P2P[p2p2.ID()].GetPublic(), decryptedKeyRing.P2P[p2p2.ID()].GetPublic()) + require.Equal(t, originalKeyRing.P2P[p2p2.ID()].PublicKeyHex(), decryptedKeyRing.P2P[p2p2.ID()].PublicKeyHex()) require.Equal(t, originalKeyRing.P2P[p2p2.ID()].PeerID(), decryptedKeyRing.P2P[p2p2.ID()].PeerID()) // compare solana keys require.Equal(t, 2, len(decryptedKeyRing.Solana)) diff --git a/core/services/keystore/ocr_test.go b/core/services/keystore/ocr_test.go index 200d62415eb..c65d576c452 100644 --- a/core/services/keystore/ocr_test.go +++ b/core/services/keystore/ocr_test.go @@ -6,12 +6,12 @@ import ( "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/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/ocrkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_OCRKeyStore_E2E(t *testing.T) { diff --git a/core/services/keystore/p2p.go b/core/services/keystore/p2p.go index 657dfbc8973..ee2c64c021d 100644 --- a/core/services/keystore/p2p.go +++ b/core/services/keystore/p2p.go @@ -160,7 +160,7 @@ func (ks *p2p) GetOrFirst(id p2pkey.PeerID) (p2pkey.KeyV2, error) { if ks.isLocked() { return p2pkey.KeyV2{}, ErrLocked } - if id != "" { + if id != (p2pkey.PeerID{}) { return ks.getByID(id) } else if len(ks.keyRing.P2P) == 1 { ks.logger.Warn("No P2P.PeerID set, defaulting to first key in database") diff --git a/core/services/keystore/p2p_test.go b/core/services/keystore/p2p_test.go index 89cab3e1621..4dc44651473 100644 --- a/core/services/keystore/p2p_test.go +++ b/core/services/keystore/p2p_test.go @@ -1,20 +1,21 @@ package keystore_test import ( + "crypto/rand" "fmt" "testing" + "time" "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/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" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_P2PKeyStore_E2E(t *testing.T) { @@ -39,7 +40,10 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("errors when getting non-existent ID", func(t *testing.T) { defer reset() - _, err := ks.Get("non-existent-id") + var nonExistent p2pkey.PeerID + _, err := rand.Read(nonExistent[:]) + require.NoError(t, err) + _, err = ks.Get(nonExistent) require.Error(t, err) }) @@ -58,7 +62,10 @@ func Test_P2PKeyStore_E2E(t *testing.T) { require.NoError(t, err) exportJSON, err := ks.Export(key.PeerID(), cltest.Password) require.NoError(t, err) - _, err = ks.Export("non-existent", cltest.Password) + var nonExistent p2pkey.PeerID + _, err = rand.Read(nonExistent[:]) + require.NoError(t, err) + _, err = ks.Export(nonExistent, cltest.Password) assert.Error(t, err) _, err = ks.Delete(key.PeerID()) require.NoError(t, err) @@ -117,14 +124,14 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("GetOrFirst", func(t *testing.T) { defer reset() - _, err := ks.GetOrFirst("") + _, err := ks.GetOrFirst(p2pkey.PeerID{}) require.Contains(t, err.Error(), "no p2p keys exist") - id := p2pkey.PeerID("a0") + 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() require.NoError(t, err) - k2, err := ks.GetOrFirst("") + k2, err := ks.GetOrFirst(p2pkey.PeerID{}) require.NoError(t, err) require.Equal(t, k1, k2) k3, err := ks.GetOrFirst(k1.PeerID()) @@ -132,7 +139,7 @@ func Test_P2PKeyStore_E2E(t *testing.T) { require.Equal(t, k1, k3) _, err = ks.Create() require.NoError(t, err) - _, err = ks.GetOrFirst("") + _, err = ks.GetOrFirst(p2pkey.PeerID{}) require.Contains(t, err.Error(), "multiple p2p keys found") //Check for possible keys in error message require.Contains(t, err.Error(), k1.ID()) @@ -147,12 +154,19 @@ func Test_P2PKeyStore_E2E(t *testing.T) { t.Run("clears p2p_peers on delete", func(t *testing.T) { key, err := ks.Create() require.NoError(t, err) - p2pPeer1 := ocrcommon.P2PPeer{ + type P2PPeer struct { + ID string + Addr string + PeerID string + CreatedAt time.Time + UpdatedAt time.Time + } + p2pPeer1 := P2PPeer{ ID: cltest.NewPeerID().String(), Addr: testutils.NewAddress().Hex(), PeerID: cltest.DefaultPeerID, // different p2p key } - p2pPeer2 := ocrcommon.P2PPeer{ + p2pPeer2 := P2PPeer{ ID: cltest.NewPeerID().String(), Addr: testutils.NewAddress().Hex(), PeerID: key.PeerID().Raw(), @@ -163,6 +177,7 @@ func Test_P2PKeyStore_E2E(t *testing.T) { RETURNING *;`, p2pTableName) stmt, err := db.PrepareNamed(sql) require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, stmt.Close()) }) require.NoError(t, stmt.Get(&p2pPeer1, &p2pPeer1)) require.NoError(t, stmt.Get(&p2pPeer2, &p2pPeer2)) cltest.AssertCount(t, db, p2pTableName, 2) diff --git a/core/services/keystore/solana_test.go b/core/services/keystore/solana_test.go index 6e895a56117..cf2515f5f70 100644 --- a/core/services/keystore/solana_test.go +++ b/core/services/keystore/solana_test.go @@ -6,13 +6,13 @@ import ( "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/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" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_SolanaKeyStore_E2E(t *testing.T) { diff --git a/core/services/keystore/starknet_test.go b/core/services/keystore/starknet_test.go index 7fc5718bac0..a007b01f120 100644 --- a/core/services/keystore/starknet_test.go +++ b/core/services/keystore/starknet_test.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/caigo" + "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" @@ -20,7 +21,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" starktxm "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/txm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_StarkNetKeyStore_E2E(t *testing.T) { diff --git a/core/services/keystore/vrf_test.go b/core/services/keystore/vrf_test.go index 7a2e91ffec3..77fccd865ff 100644 --- a/core/services/keystore/vrf_test.go +++ b/core/services/keystore/vrf_test.go @@ -7,12 +7,12 @@ import ( "github.com/stretchr/testify/assert" + "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/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/require" ) diff --git a/core/services/mocks/checker.go b/core/services/mocks/checker.go index e0c209d8afb..2572efb1822 100644 --- a/core/services/mocks/checker.go +++ b/core/services/mocks/checker.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type Checker struct { func (_m *Checker) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -30,6 +34,10 @@ func (_m *Checker) Close() error { func (_m *Checker) IsHealthy() (bool, map[string]error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsHealthy") + } + var r0 bool var r1 map[string]error if rf, ok := ret.Get(0).(func() (bool, map[string]error)); ok { @@ -56,6 +64,10 @@ func (_m *Checker) IsHealthy() (bool, map[string]error) { func (_m *Checker) IsReady() (bool, map[string]error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for IsReady") + } + var r0 bool var r1 map[string]error if rf, ok := ret.Get(0).(func() (bool, map[string]error)); ok { @@ -82,6 +94,10 @@ func (_m *Checker) IsReady() (bool, map[string]error) { func (_m *Checker) Register(service pkgservices.HealthReporter) error { ret := _m.Called(service) + if len(ret) == 0 { + panic("no return value specified for Register") + } + var r0 error if rf, ok := ret.Get(0).(func(pkgservices.HealthReporter) error); ok { r0 = rf(service) @@ -96,6 +112,10 @@ func (_m *Checker) Register(service pkgservices.HealthReporter) error { func (_m *Checker) Start() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -110,6 +130,10 @@ func (_m *Checker) Start() error { func (_m *Checker) Unregister(name string) error { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for Unregister") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(name) diff --git a/core/services/nurse.go b/core/services/nurse.go index 3d896a80ff3..1b44beea21c 100644 --- a/core/services/nurse.go +++ b/core/services/nurse.go @@ -17,9 +17,9 @@ import ( "github.com/google/pprof/profile" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -40,14 +40,14 @@ type Nurse struct { type Config interface { BlockProfileRate() int CPUProfileRate() int - GatherDuration() models.Duration - GatherTraceDuration() models.Duration + GatherDuration() commonconfig.Duration + GatherTraceDuration() commonconfig.Duration GoroutineThreshold() int MaxProfileSize() utils.FileSize MemProfileRate() int MemThreshold() utils.FileSize MutexProfileFraction() int - PollInterval() models.Duration + PollInterval() commonconfig.Duration ProfileRoot() string } diff --git a/core/services/nurse_test.go b/core/services/nurse_test.go index 4e68501b74b..7521168aa3f 100644 --- a/core/services/nurse_test.go +++ b/core/services/nurse_test.go @@ -9,18 +9,18 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) type mockConfig struct { t *testing.T root string - pollInterval *models.Duration - gatherDuration *models.Duration - traceDuration *models.Duration + pollInterval *commonconfig.Duration + gatherDuration *commonconfig.Duration + traceDuration *commonconfig.Duration profileSize utils.FileSize cpuProfileRate int memProfileRate int @@ -31,8 +31,8 @@ type mockConfig struct { } var ( - testInterval = time.Duration(50 * time.Millisecond) - testDuration = time.Duration(20 * time.Millisecond) + testInterval = 50 * time.Millisecond + testDuration = 20 * time.Millisecond testRate = 100 testSize = 16 * 1024 * 1024 ) @@ -40,9 +40,9 @@ var ( func newMockConfig(t *testing.T) *mockConfig { return &mockConfig{ root: t.TempDir(), - pollInterval: models.MustNewDuration(testInterval), - gatherDuration: models.MustNewDuration(testDuration), - traceDuration: models.MustNewDuration(testDuration), + pollInterval: commonconfig.MustNewDuration(testInterval), + gatherDuration: commonconfig.MustNewDuration(testDuration), + traceDuration: commonconfig.MustNewDuration(testDuration), profileSize: utils.FileSize(testSize), memProfileRate: runtime.MemProfileRate, blockProfileRate: testRate, @@ -57,15 +57,15 @@ func (c mockConfig) ProfileRoot() string { return c.root } -func (c mockConfig) PollInterval() models.Duration { +func (c mockConfig) PollInterval() commonconfig.Duration { return *c.pollInterval } -func (c mockConfig) GatherDuration() models.Duration { +func (c mockConfig) GatherDuration() commonconfig.Duration { return *c.gatherDuration } -func (c mockConfig) GatherTraceDuration() models.Duration { +func (c mockConfig) GatherTraceDuration() commonconfig.Duration { return *c.traceDuration } @@ -128,7 +128,6 @@ func TestNurse(t *testing.T) { n2, err := nrse.totalProfileBytes() require.NoError(t, err) require.Greater(t, n2, uint64(0)) - } func profileExists(t *testing.T, nrse *Nurse, typ string) bool { diff --git a/core/services/ocr/config_overrider_test.go b/core/services/ocr/config_overrider_test.go index 245d6348765..e01102a62f8 100644 --- a/core/services/ocr/config_overrider_test.go +++ b/core/services/ocr/config_overrider_test.go @@ -14,9 +14,10 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" @@ -72,7 +73,7 @@ func TestIntegration_OCRConfigOverrider_EntersHibernation(t *testing.T) { Run(checkFlagsAddress(t, uni.contractAddress)). Return([]bool{true, true}, nil) - require.NoError(t, uni.overrider.Start(testutils.Context(t))) + servicetest.Run(t, uni.overrider) // not hibernating initially require.Nil(t, uni.overrider.ConfigOverride()) @@ -102,7 +103,7 @@ func Test_OCRConfigOverrider(t *testing.T) { Run(checkFlagsAddress(t, uni.contractAddress)). Return([]bool{true, true}, nil) - require.NoError(t, uni.overrider.Start(testutils.Context(t))) + servicetest.Run(t, uni.overrider) // not hibernating initially require.Nil(t, uni.overrider.ConfigOverride()) @@ -130,7 +131,7 @@ func Test_OCRConfigOverrider(t *testing.T) { Run(checkFlagsAddress(t, uni.contractAddress)). Return([]bool{true, false}, nil) - require.NoError(t, uni.overrider.Start(testutils.Context(t))) + servicetest.Run(t, uni.overrider) // initially enters hibernation expectedOverride := &ocrtypes.ConfigOverride{AlphaPPB: math.MaxUint64, DeltaC: uni.overrider.DeltaCFromAddress} @@ -187,7 +188,7 @@ func Test_OCRConfigOverrider(t *testing.T) { func checkFlagsAddress(t *testing.T, contractAddress ethkey.EIP55Address) func(args mock.Arguments) { return func(args mock.Arguments) { require.Equal(t, []common.Address{ - utils.ZeroAddress, + evmutils.ZeroAddress, contractAddress.Address(), }, args.Get(1).([]common.Address)) } diff --git a/core/services/ocr/contract_tracker.go b/core/services/ocr/contract_tracker.go index 4f79bcfc31a..9eabf93a834 100644 --- a/core/services/ocr/contract_tracker.go +++ b/core/services/ocr/contract_tracker.go @@ -21,6 +21,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/common/config" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -31,7 +32,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // configMailboxSanityLimit is the maximum number of configs that can be held @@ -67,7 +67,7 @@ type ( q pg.Q blockTranslator ocrcommon.BlockTranslator cfg ocrcommon.Config - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor // HeadBroadcaster headBroadcaster httypes.HeadBroadcaster @@ -83,7 +83,7 @@ type ( lrrMu sync.RWMutex // ContractConfig - configsMB *utils.Mailbox[ocrtypes.ContractConfig] + configsMB *mailbox.Mailbox[ocrtypes.ContractConfig] chConfigs chan ocrtypes.ContractConfig // LatestBlockHeight @@ -117,7 +117,7 @@ func NewOCRContractTracker( cfg ocrcommon.Config, q pg.QConfig, headBroadcaster httypes.HeadBroadcaster, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, ) (o *OCRContractTracker) { logger = logger.Named("OCRContractTracker") return &OCRContractTracker{ @@ -136,7 +136,7 @@ func NewOCRContractTracker( headBroadcaster: headBroadcaster, chStop: make(services.StopChan), latestRoundRequested: offchainaggregator.OffchainAggregatorRoundRequested{}, - configsMB: utils.NewMailbox[ocrtypes.ContractConfig](configMailboxSanityLimit), + configsMB: mailbox.New[ocrtypes.ContractConfig](configMailboxSanityLimit), chConfigs: make(chan ocrtypes.ContractConfig), latestBlockHeight: -1, } @@ -402,7 +402,7 @@ func (t *OCRContractTracker) LatestBlockHeight(ctx context.Context) (blockheight // care about the block height; we have no way of getting the L1 block // height anyway return 0, nil - case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai, config.ChainKroma, config.ChainWeMix, config.ChainZkSync: + case "", config.ChainArbitrum, config.ChainCelo, config.ChainOptimismBedrock, config.ChainXDai, config.ChainKroma, config.ChainWeMix, config.ChainZkSync, config.ChainScroll: // continue } latestBlockHeight := t.getLatestBlockHeight() diff --git a/core/services/ocr/contract_tracker_test.go b/core/services/ocr/contract_tracker_test.go index 5684219cf16..185a9cd3197 100644 --- a/core/services/ocr/contract_tracker_test.go +++ b/core/services/ocr/contract_tracker_test.go @@ -15,6 +15,9 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" @@ -29,8 +32,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" ocrmocks "github.com/smartcontractkit/chainlink/v2/core/services/ocr/mocks" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func mustNewContract(t *testing.T, address gethCommon.Address) *offchain_aggregator_wrapper.OffchainAggregator { @@ -83,7 +84,7 @@ func newContractTrackerUni(t *testing.T, opts ...interface{}) (uni contractTrack uni.hb = commonmocks.NewHeadBroadcaster[*evmtypes.Head, common.Hash](t) uni.ec = evmtest.NewEthClientMock(t) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) db := pgtest.NewSqlxDB(t) uni.tracker = ocr.NewOCRContractTracker( contract, @@ -148,13 +149,12 @@ func Test_OCRContractTracker_LatestBlockHeight(t *testing.T) { uni.db.On("LoadLatestRoundRequested").Return(offchainaggregator.OffchainAggregatorRoundRequested{}, nil) uni.lb.On("Register", uni.tracker, mock.Anything).Return(func() {}) - require.NoError(t, uni.tracker.Start(testutils.Context(t))) + servicetest.Run(t, uni.tracker) l, err := uni.tracker.LatestBlockHeight(testutils.Context(t)) require.NoError(t, err) assert.Equal(t, uint64(42), l) - require.NoError(t, uni.tracker.Close()) }) } diff --git a/core/services/ocr/database.go b/core/services/ocr/database.go index 524dfa0e7bb..977c371c15d 100644 --- a/core/services/ocr/database.go +++ b/core/services/ocr/database.go @@ -15,9 +15,9 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "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" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type db struct { @@ -161,7 +161,7 @@ func (d *db) WriteConfig(ctx context.Context, c ocrtypes.ContractConfig) error { } func (d *db) StorePendingTransmission(ctx context.Context, k ocrtypes.ReportTimestamp, p ocrtypes.PendingTransmission) error { - median := utils.NewBig(p.Median) + median := big.New(p.Median) var rs [][]byte var ss [][]byte // Note: p.Rs and p.Ss are of type [][32]byte. @@ -207,6 +207,7 @@ func (d *db) StorePendingTransmission(ctx context.Context, k ocrtypes.ReportTime } 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, ` SELECT config_digest, @@ -232,7 +233,7 @@ WHERE ocr_oracle_spec_id = $1 AND config_digest = $2 k := ocrtypes.ReportTimestamp{} p := ocrtypes.PendingTransmission{} - var median utils.Big + var median big.Big var rs [][]byte var ss [][]byte var vs []byte @@ -317,6 +318,7 @@ LIMIT 1 if err != nil { return rr, errors.Wrap(err, "LoadLatestRoundRequested failed to query rows") } + defer func() { err = multierr.Combine(err, rows.Close()) }() for rows.Next() { var configDigest []byte @@ -337,7 +339,5 @@ LIMIT 1 return } - err = multierr.Combine(err, rows.Close()) - return } diff --git a/core/services/ocr/database_test.go b/core/services/ocr/database_test.go index 6a72c27aa65..5ccf257b2bb 100644 --- a/core/services/ocr/database_test.go +++ b/core/services/ocr/database_test.go @@ -13,12 +13,12 @@ import ( "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" + "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" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_DB_ReadWriteState(t *testing.T) { diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index f473c93b1f0..0eed680a3d8 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -12,9 +12,9 @@ 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" - ocrnetworking "github.com/smartcontractkit/libocr/networking" ocr "github.com/smartcontractkit/libocr/offchainreporting" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting/types" @@ -44,7 +44,7 @@ type Delegate struct { legacyChains legacyevm.LegacyChainContainer lggr logger.Logger cfg Config - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } var _ job.Delegate = (*Delegate)(nil) @@ -61,7 +61,7 @@ func NewDelegate( legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, cfg Config, - mailMon *utils.MailboxMonitor, + mailMon *mailbox.Monitor, ) *Delegate { return &Delegate{ db: db, @@ -146,16 +146,6 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e return nil, errors.New("peerWrapper is not started. OCR jobs require a started and running p2p peer") } - var v1BootstrapPeers []string - if concreteSpec.P2PBootstrapPeers != nil { - v1BootstrapPeers = concreteSpec.P2PBootstrapPeers - } else { - v1BootstrapPeers, err = chain.Config().P2P().V1().DefaultBootstrapPeers() - if err != nil { - return nil, err - } - } - v2Bootstrappers, err := ocrcommon.ParseBootstrapPeers(concreteSpec.P2PV2Bootstrappers) if err != nil { return nil, err @@ -181,7 +171,6 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e var bootstrapper *ocr.BootstrapNode bootstrapper, err = ocr.NewBootstrapNode(ocr.BootstrapNodeArgs{ BootstrapperFactory: peerWrapper.Peer1, - V1Bootstrappers: v1BootstrapPeers, V2Bootstrappers: v2Bootstrappers, ContractConfigTracker: tracker, Database: ocrDB, @@ -194,20 +183,9 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e bootstrapperCtx := job.NewServiceAdapter(bootstrapper) services = append(services, bootstrapperCtx) } else { - // In V1 or V1V2 mode, p2pv1BootstrapPeers must be defined either in - // node config or in job spec - if peerWrapper.P2PConfig().NetworkStack() != ocrnetworking.NetworkingStackV2 { - if len(v1BootstrapPeers) < 1 { - return nil, errors.New("Need at least one v1 bootstrap peer defined") - } - } - - // In V1V2 or V2 mode, p2pv2Bootstrappers must be defined either in - // node config or in job spec - if peerWrapper.P2PConfig().NetworkStack() != ocrnetworking.NetworkingStackV1 { - if len(v2Bootstrappers) < 1 { - return nil, errors.New("Need at least one v2 bootstrap peer defined") - } + // p2pv2Bootstrappers must be defined either in node config or in job spec + if len(v2Bootstrappers) < 1 { + return nil, errors.New("Need at least one v2 bootstrap peer defined") } ocrkey, err := d.keyStore.OCR().Get(concreteSpec.EncryptedOCRKeyBundleID.String()) @@ -325,7 +303,6 @@ func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err e PrivateKeys: ocrkey, BinaryNetworkEndpointFactory: peerWrapper.Peer1, Logger: ocrLogger, - V1Bootstrappers: v1BootstrapPeers, V2Bootstrappers: v2Bootstrappers, MonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint("EVM", chain.ID().String(), concreteSpec.ContractAddress.String(), synchronization.OCR), ConfigOverrider: configOverrider, diff --git a/core/services/ocr/example-job-spec.toml b/core/services/ocr/example-job-spec.toml index f8854a0a0b2..7622c45f212 100644 --- a/core/services/ocr/example-job-spec.toml +++ b/core/services/ocr/example-job-spec.toml @@ -2,9 +2,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" diff --git a/core/services/ocr/flags.go b/core/services/ocr/flags.go index 8e4eb802e5e..6a18d73cd7e 100644 --- a/core/services/ocr/flags.go +++ b/core/services/ocr/flags.go @@ -5,8 +5,8 @@ import ( "github.com/pkg/errors" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/flags_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ContractFlags wraps the a contract diff --git a/core/services/ocr/flags_test.go b/core/services/ocr/flags_test.go index 9e57b8489ed..bcce1ed2f96 100644 --- a/core/services/ocr/flags_test.go +++ b/core/services/ocr/flags_test.go @@ -7,10 +7,10 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/fluxmonitorv2" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestFlags_IsLowered(t *testing.T) { diff --git a/core/services/ocr/mocks/ocr_contract_tracker_db.go b/core/services/ocr/mocks/ocr_contract_tracker_db.go index a1d2f523ccb..6724e418014 100644 --- a/core/services/ocr/mocks/ocr_contract_tracker_db.go +++ b/core/services/ocr/mocks/ocr_contract_tracker_db.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -19,6 +19,10 @@ type OCRContractTrackerDB struct { func (_m *OCRContractTrackerDB) LoadLatestRoundRequested() (offchainaggregator.OffchainAggregatorRoundRequested, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LoadLatestRoundRequested") + } + var r0 offchainaggregator.OffchainAggregatorRoundRequested var r1 error if rf, ok := ret.Get(0).(func() (offchainaggregator.OffchainAggregatorRoundRequested, error)); ok { @@ -43,6 +47,10 @@ func (_m *OCRContractTrackerDB) LoadLatestRoundRequested() (offchainaggregator.O func (_m *OCRContractTrackerDB) SaveLatestRoundRequested(tx pg.Queryer, rr offchainaggregator.OffchainAggregatorRoundRequested) error { ret := _m.Called(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) diff --git a/core/services/ocr/validate.go b/core/services/ocr/validate.go index a780ebb0821..0524ed24d0b 100644 --- a/core/services/ocr/validate.go +++ b/core/services/ocr/validate.go @@ -5,9 +5,9 @@ import ( "time" "github.com/lib/pq" - "github.com/multiformats/go-multiaddr" "github.com/pelletier/go-toml" "github.com/pkg/errors" + "github.com/smartcontractkit/libocr/offchainreporting" "github.com/smartcontractkit/chainlink/v2/common/config" @@ -77,11 +77,6 @@ func ValidatedOracleSpecTomlCfg(configFn func(id *big.Int) (evmconfig.ChainScope if !tree.Has("isBootstrapPeer") { return jb, errors.New("isBootstrapPeer is not defined") } - for i := range spec.P2PBootstrapPeers { - if _, err = multiaddr.NewMultiaddr(spec.P2PBootstrapPeers[i]); err != nil { - return jb, errors.Wrapf(err, "p2p bootstrap peer %v is invalid", spec.P2PBootstrapPeers[i]) - } - } if len(spec.P2PV2Bootstrappers) > 0 { _, err = ocrcommon.ParseBootstrapPeers(spec.P2PV2Bootstrappers) diff --git a/core/services/ocr/validate_test.go b/core/services/ocr/validate_test.go index 0164fd82c54..e55c5d1a484 100644 --- a/core/services/ocr/validate_test.go +++ b/core/services/ocr/validate_test.go @@ -11,13 +11,13 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" evmconfig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestValidateOracleSpec(t *testing.T) { @@ -60,9 +60,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" @@ -92,7 +90,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = true `, assertion: func(t *testing.T, os job.Job, err error) { @@ -108,9 +106,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = true keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" @@ -136,7 +132,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false `, assertion: func(t *testing.T, os job.Job, err error) { @@ -150,28 +146,11 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false observationSource = """ -> """ -`, - assertion: func(t *testing.T, os job.Job, err error) { - require.Error(t, err) - }, - }, - { - name: "invalid v1 bootstrap peer address", - toml: ` -type = "offchainreporting" -schemaVersion = 1 -contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" -p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/invalid/peer/address"] -isBootstrapPeer = false -observationSource = """ -blah -""" `, assertion: func(t *testing.T, os job.Job, err error) { require.Error(t, err) @@ -184,9 +163,6 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] p2pv2Bootstrappers = ["invalid bootstrapper /#@ address"] isBootstrapPeer = false observationSource = """ @@ -204,7 +180,6 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] p2pv2Bootstrappers = [ "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001", ] @@ -225,7 +200,6 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] p2pv2Bootstrappers = [ "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001", ] @@ -246,7 +220,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false observationGracePeriod = "0s" observationSource = """ @@ -264,7 +238,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false contractTransmitterTransmitTimeout = "0s" observationSource = """ @@ -282,7 +256,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = ["/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju"] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false contractConfigTrackerSubscribeInterval = "0s" observationSource = """ @@ -300,13 +274,12 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [] -p2pv2Bootstrappers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = true monitoringEndpoint = "\t/fd\2ff )(*&^%$#@" `, assertion: func(t *testing.T, os job.Job, err error) { - require.EqualError(t, err, "toml error on load: (9, 23): invalid escape sequence: \\2") + require.EqualError(t, err, "toml error on load: (8, 23): invalid escape sequence: \\2") }, }, { @@ -317,9 +290,7 @@ maxTaskDuration = "30s" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" @@ -341,9 +312,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" @@ -372,9 +341,7 @@ type = "offchainreporting" schemaVersion = 1 contractAddress = "0x613a38AC1659769640aaE063C651F48E0250454C" p2pPeerID = "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq" -p2pBootstrapPeers = [ -"/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "73e8966a78ca09bb912e9565cfb79fbe8a6048fab1f0cf49b18047c3895e0447" monitoringEndpoint = "chain.link:4321" @@ -392,7 +359,7 @@ answer1 [type=median index=0]; require.Contains(t, err.Error(), "data source timeout must be between 1s and 20s, but is currently 20m0s") }, overrides: func(c *chainlink.Config, s *chainlink.Secrets) { - c.OCR.ObservationTimeout = models.MustNewDuration(20 * time.Minute) + c.OCR.ObservationTimeout = commonconfig.MustNewDuration(20 * time.Minute) }, }, } diff --git a/core/services/ocr2/database.go b/core/services/ocr2/database.go index 5591f33fd40..1d449047578 100644 --- a/core/services/ocr2/database.go +++ b/core/services/ocr2/database.go @@ -279,7 +279,7 @@ func (d *db) PendingTransmissionsWithConfigDigest(ctx context.Context, cd ocrtyp FROM ocr2_pending_transmissions WHERE ocr2_oracle_spec_id = $1 AND config_digest = $2 ` - rows, err := d.q.QueryxContext(ctx, stmt, d.oracleSpecID, cd) + rows, err := d.q.QueryxContext(ctx, stmt, d.oracleSpecID, cd) //nolint sqlclosecheck false positive if err != nil { return nil, errors.Wrap(err, "PendingTransmissionsWithConfigDigest failed to query rows") } diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 16f02282afb..c838316b1cc 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -25,6 +25,7 @@ import ( ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner" ocr2keepers21config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" + "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink-vrf/altbn_128" dkgpkg "github.com/smartcontractkit/chainlink-vrf/dkg" @@ -34,6 +35,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/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -42,7 +44,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/keystore/keys/ocr2key" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/dkg/persistence" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions" @@ -70,7 +71,6 @@ import ( evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -116,7 +116,7 @@ type Delegate struct { ethKs keystore.Eth RelayGetter isNewlyCreatedJob bool // Set to true if this is a new job freshly added, false if job was present already on node boot. - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor legacyChains legacyevm.LegacyChainContainer // legacy: use relayers instead } @@ -188,8 +188,9 @@ type jobPipelineConfig interface { } type mercuryConfig interface { - Credentials(credName string) *models.MercuryCredentials + Credentials(credName string) *types.MercuryCredentials Cache() coreconfig.MercuryCache + TLS() coreconfig.MercuryTLS } type thresholdConfig interface { @@ -226,8 +227,7 @@ func NewDelegate( dkgEncryptKs keystore.DKGEncrypt, ethKs keystore.Eth, relayers RelayGetter, - mailMon *utils.MailboxMonitor, - eventBroadcaster pg.EventBroadcaster, + mailMon *mailbox.Monitor, ) *Delegate { return &Delegate{ db: db, @@ -441,7 +441,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { return d.newServicesOCR2VRF(lggr, jb, bootstrapPeers, kb, ocrDB, lc) case types.OCR2Keeper: - return d.newServicesOCR2Keepers(lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) + return d.newServicesOCR2Keepers(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger) case types.Functions: const ( @@ -505,12 +505,6 @@ type connProvider interface { ClientConn() grpc.ClientConnInterface } -func defaultPathFromPluginName(pluginName string) string { - // By default we install the command on the system path, in the - // form: `chainlink-` - return fmt.Sprintf("chainlink-%s", pluginName) -} - func (d *Delegate) newServicesGenericPlugin( ctx context.Context, lggr logger.SugaredLogger, @@ -531,9 +525,11 @@ func (d *Delegate) newServicesGenericPlugin( return nil, err } + plugEnv := env.NewPlugin(p.PluginName) + command := p.Command if command == "" { - command = defaultPathFromPluginName(p.PluginName) + command = plugEnv.Cmd.Get() } // Add the default pipeline to the pluginConfig @@ -588,8 +584,22 @@ func (d *Delegate) newServicesGenericPlugin( OffchainConfigDigester: provider.OffchainConfigDigester(), } + envVars, err := plugins.ParseEnvFile(plugEnv.Env.Get()) + if err != nil { + return nil, fmt.Errorf("failed to parse median env file: %w", err) + } + if len(p.EnvVars) > 0 { + for k, v := range p.EnvVars { + envVars = append(envVars, k+"="+v) + } + } + pluginLggr := lggr.Named(p.PluginName).Named(spec.ContractID).Named(spec.GetID()) - cmdFn, grpcOpts, err := d.cfg.RegisterLOOP(fmt.Sprintf("%s-%s-%s", p.PluginName, spec.ContractID, spec.GetID()), command) + cmdFn, grpcOpts, err := d.cfg.RegisterLOOP(plugins.CmdConfig{ + ID: fmt.Sprintf("%s-%s-%s", p.PluginName, spec.ContractID, spec.GetID()), + Cmd: command, + Env: envVars, + }) if err != nil { return nil, fmt.Errorf("failed to register loop: %w", err) } @@ -1026,6 +1036,7 @@ func (d *Delegate) newServicesOCR2VRF( } func (d *Delegate) newServicesOCR2Keepers( + ctx context.Context, lggr logger.SugaredLogger, jb job.Job, bootstrapPeers []commontypes.BootstrapperLocator, @@ -1046,7 +1057,7 @@ func (d *Delegate) newServicesOCR2Keepers( switch cfg.ContractVersion { case "v2.1": - return d.newServicesOCR2Keepers21(lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger, cfg, spec) + return d.newServicesOCR2Keepers21(ctx, lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger, cfg, spec) case "v2.0": return d.newServicesOCR2Keepers20(lggr, jb, bootstrapPeers, kb, ocrDB, lc, ocrLogger, cfg, spec) default: @@ -1055,6 +1066,7 @@ func (d *Delegate) newServicesOCR2Keepers( } func (d *Delegate) newServicesOCR2Keepers21( + ctx context.Context, lggr logger.SugaredLogger, jb job.Job, bootstrapPeers []commontypes.BootstrapperLocator, @@ -1079,14 +1091,37 @@ func (d *Delegate) newServicesOCR2Keepers21( return nil, fmt.Errorf("keeper2 services: expected EVM relayer got %s", rid.Network) } - chain, err2 := d.legacyChains.Get(rid.ChainID) - if err2 != nil { - return nil, fmt.Errorf("keeper2 services: failed to get chain %s: %w", rid.ChainID, err2) + transmitterID := spec.TransmitterID.String + relayer, err := d.RelayGetter.Get(rid) + if err != nil { + return nil, ErrRelayNotEnabled{Err: err, Relay: spec.Relay, PluginName: "ocr2keepers"} } - keeperProvider, services, err2 := ocr2keeper.EVMDependencies21(jb, d.db, lggr, chain, d.pipelineRunner, mc, kb, d.cfg.Database()) - if err2 != nil { - return nil, errors.Wrap(err2, "could not build dependencies for ocr2 keepers") + provider, err := relayer.NewPluginProvider(ctx, + types.RelayArgs{ + ExternalJobID: jb.ExternalJobID, + JobID: jb.ID, + ContractID: spec.ContractID, + New: d.isNewlyCreatedJob, + RelayConfig: spec.RelayConfig.Bytes(), + ProviderType: string(spec.PluginType), + MercuryCredentials: mc, + }, types.PluginArgs{ + TransmitterID: transmitterID, + PluginConfig: spec.PluginConfig.Bytes(), + }) + if err != nil { + return nil, err + } + + keeperProvider, ok := provider.(types.AutomationProvider) + if !ok { + return nil, errors.New("could not coerce PluginProvider to AutomationProvider") + } + + services, err := ocr2keeper.EVMDependencies21(kb) + if err != nil { + return nil, errors.Wrap(err, "could not build dependencies for ocr2 keepers") } // set some defaults conf := ocr2keepers21config.ReportingFactoryConfig{ @@ -1125,15 +1160,15 @@ func (d *Delegate) newServicesOCR2Keepers21( OffchainKeyring: kb, OnchainKeyring: services.Keyring(), LocalConfig: lc, - LogProvider: services.LogEventProvider(), - EventProvider: services.TransmitEventProvider(), - Runnable: services.Registry(), - Encoder: services.Encoder(), - BlockSubscriber: services.BlockSubscriber(), - RecoverableProvider: services.LogRecoverer(), - PayloadBuilder: services.PayloadBuilder(), - UpkeepProvider: services.UpkeepProvider(), - UpkeepStateUpdater: services.UpkeepStateStore(), + LogProvider: keeperProvider.LogEventProvider(), + EventProvider: keeperProvider.TransmitEventProvider(), + Runnable: keeperProvider.Registry(), + Encoder: keeperProvider.Encoder(), + BlockSubscriber: keeperProvider.BlockSubscriber(), + RecoverableProvider: keeperProvider.LogRecoverer(), + PayloadBuilder: keeperProvider.PayloadBuilder(), + UpkeepProvider: keeperProvider.UpkeepProvider(), + UpkeepStateUpdater: keeperProvider.UpkeepStateStore(), UpkeepTypeGetter: ocr2keeper21core.GetUpkeepType, WorkIDGenerator: ocr2keeper21core.UpkeepWorkID, // TODO: Clean up the config @@ -1150,12 +1185,12 @@ func (d *Delegate) newServicesOCR2Keepers21( automationServices := []job.ServiceCtx{ keeperProvider, - services.Registry(), - services.BlockSubscriber(), - services.LogEventProvider(), - services.LogRecoverer(), - services.UpkeepStateStore(), - services.TransmitEventProvider(), + keeperProvider.Registry(), + keeperProvider.BlockSubscriber(), + keeperProvider.LogEventProvider(), + keeperProvider.LogRecoverer(), + keeperProvider.UpkeepStateStore(), + keeperProvider.TransmitEventProvider(), pluginService, } @@ -1165,7 +1200,7 @@ func (d *Delegate) newServicesOCR2Keepers21( customTelemService, custErr := autotelemetry21.NewAutomationCustomTelemetryService( endpoint, lggr, - services.BlockSubscriber(), + keeperProvider.BlockSubscriber(), keeperProvider.ContractConfigTracker(), ) if custErr != nil { @@ -1201,7 +1236,7 @@ func (d *Delegate) newServicesOCR2Keepers20( return nil, fmt.Errorf("keepers2.0 services: failed to get chain (%s): %w", rid.ChainID, err2) } - keeperProvider, rgstry, encoder, logProvider, err2 := ocr2keeper.EVMDependencies20(jb, d.db, lggr, chain, d.pipelineRunner) + keeperProvider, rgstry, encoder, logProvider, err2 := ocr2keeper.EVMDependencies20(jb, d.db, lggr, chain, d.ethKs, d.cfg.Database()) if err2 != nil { return nil, errors.Wrap(err2, "could not build dependencies for ocr2 keepers") } diff --git a/core/services/ocr2/delegate_test.go b/core/services/ocr2/delegate_test.go index b55e128119d..3da0c9cbfd6 100644 --- a/core/services/ocr2/delegate_test.go +++ b/core/services/ocr2/delegate_test.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + "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" @@ -23,11 +24,10 @@ import ( ocr2validate "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestGetEVMEffectiveTransmitterID(t *testing.T) { - customChainID := utils.NewBig(testutils.NewRandomEVMChainID()) + customChainID := big.New(testutils.NewRandomEVMChainID()) config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { enabled := true diff --git a/core/services/ocr2/models/models.go b/core/services/ocr2/models/models.go deleted file mode 100644 index 4d3b8bf532c..00000000000 --- a/core/services/ocr2/models/models.go +++ /dev/null @@ -1,8 +0,0 @@ -package models - -type MercuryCredentials struct { - LegacyURL string - URL string - Username string - Password string -} diff --git a/core/services/ocr2/plugins/dkg/persistence/db.go b/core/services/ocr2/plugins/dkg/persistence/db.go index 304422ace2d..72997e28699 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db.go +++ b/core/services/ocr2/plugins/dkg/persistence/db.go @@ -65,7 +65,7 @@ func NewShareDB(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, chainID *big.In q: pg.NewQ(db, lggr, cfg), lggr: lggr, chainID: chainID, - chainType: string(chainType), + chainType: chainType, } } diff --git a/core/services/ocr2/plugins/dkg/persistence/db_test.go b/core/services/ocr2/plugins/dkg/persistence/db_test.go index b4fa000cb99..53a5ae26758 100644 --- a/core/services/ocr2/plugins/dkg/persistence/db_test.go +++ b/core/services/ocr2/plugins/dkg/persistence/db_test.go @@ -55,6 +55,7 @@ func TestShareDB_WriteShareRecords(t *testing.T) { rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) require.NoError(tt, err) + t.Cleanup(func() { assert.NoError(t, rows.Close()) }) var count int for rows.Next() { @@ -84,6 +85,7 @@ func TestShareDB_WriteShareRecords(t *testing.T) { rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) require.NoError(tt, err) + t.Cleanup(func() { assert.NoError(t, rows.Close()) }) var count int for rows.Next() { @@ -122,6 +124,7 @@ func TestShareDB_WriteShareRecords(t *testing.T) { // no rows should have been inserted rows, err := db.Query(`SELECT COUNT(*) AS count FROM dkg_shares`) require.NoError(tt, err) + t.Cleanup(func() { assert.NoError(t, rows.Close()) }) var count int for rows.Next() { diff --git a/core/services/ocr2/plugins/functions/aggregation.go b/core/services/ocr2/plugins/functions/aggregation.go index 32a2509e70e..7ae00532f3f 100644 --- a/core/services/ocr2/plugins/functions/aggregation.go +++ b/core/services/ocr2/plugins/functions/aggregation.go @@ -104,7 +104,7 @@ func aggregateMode(items [][]byte) []byte { mostFrequent = item } } - return []byte(mostFrequent) + return mostFrequent } func aggregateMedian(items [][]byte) []byte { diff --git a/core/services/ocr2/plugins/functions/config/config.go b/core/services/ocr2/plugins/functions/config/config.go index 13e02042506..e0e1ba3bfa0 100644 --- a/core/services/ocr2/plugins/functions/config/config.go +++ b/core/services/ocr2/plugins/functions/config/config.go @@ -13,40 +13,42 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" - "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" + "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" s4PluginConfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/s4" "github.com/smartcontractkit/chainlink/v2/core/services/s4" ) // This config is part of the job spec and is loaded only once on node boot/job creation. type PluginConfig struct { - EnableRequestSignatureCheck bool `json:"enableRequestSignatureCheck"` - DONID string `json:"donID"` - ContractVersion uint32 `json:"contractVersion"` - MinRequestConfirmations uint32 `json:"minRequestConfirmations"` - MinResponseConfirmations uint32 `json:"minResponseConfirmations"` - MinIncomingConfirmations uint32 `json:"minIncomingConfirmations"` - PastBlocksToPoll uint32 `json:"pastBlocksToPoll"` - LogPollerCacheDurationSec uint32 `json:"logPollerCacheDurationSec"` // Duration to cache previously detected request or response logs such that they can be filtered when calling logpoller_wrapper.LatestEvents() - RequestTimeoutSec uint32 `json:"requestTimeoutSec"` - RequestTimeoutCheckFrequencySec uint32 `json:"requestTimeoutCheckFrequencySec"` - RequestTimeoutBatchLookupSize uint32 `json:"requestTimeoutBatchLookupSize"` - PruneMaxStoredRequests uint32 `json:"pruneMaxStoredRequests"` - PruneCheckFrequencySec uint32 `json:"pruneCheckFrequencySec"` - PruneBatchSize uint32 `json:"pruneBatchSize"` - ListenerEventHandlerTimeoutSec uint32 `json:"listenerEventHandlerTimeoutSec"` - ListenerEventsCheckFrequencyMillis uint32 `json:"listenerEventsCheckFrequencyMillis"` - ContractUpdateCheckFrequencySec uint32 `json:"contractUpdateCheckFrequencySec"` - MaxRequestSizeBytes uint32 `json:"maxRequestSizeBytes"` - MaxRequestSizesList []uint32 `json:"maxRequestSizesList"` - MaxSecretsSizesList []uint32 `json:"maxSecretsSizesList"` - MinimumSubscriptionBalance assets.Link `json:"minimumSubscriptionBalance"` - GatewayConnectorConfig *connector.ConnectorConfig `json:"gatewayConnectorConfig"` - OnchainAllowlist *functions.OnchainAllowlistConfig `json:"onchainAllowlist"` - OnchainSubscriptions *functions.OnchainSubscriptionsConfig `json:"onchainSubscriptions"` - RateLimiter *common.RateLimiterConfig `json:"rateLimiter"` - S4Constraints *s4.Constraints `json:"s4Constraints"` - DecryptionQueueConfig *DecryptionQueueConfig `json:"decryptionQueueConfig"` + EnableRequestSignatureCheck bool `json:"enableRequestSignatureCheck"` + DONID string `json:"donID"` + ContractVersion uint32 `json:"contractVersion"` + MinRequestConfirmations uint32 `json:"minRequestConfirmations"` + MinResponseConfirmations uint32 `json:"minResponseConfirmations"` + MinIncomingConfirmations uint32 `json:"minIncomingConfirmations"` + PastBlocksToPoll uint32 `json:"pastBlocksToPoll"` + LogPollerCacheDurationSec uint32 `json:"logPollerCacheDurationSec"` // Duration to cache previously detected request or response logs such that they can be filtered when calling logpoller_wrapper.LatestEvents() + RequestTimeoutSec uint32 `json:"requestTimeoutSec"` + RequestTimeoutCheckFrequencySec uint32 `json:"requestTimeoutCheckFrequencySec"` + RequestTimeoutBatchLookupSize uint32 `json:"requestTimeoutBatchLookupSize"` + PruneMaxStoredRequests uint32 `json:"pruneMaxStoredRequests"` + PruneCheckFrequencySec uint32 `json:"pruneCheckFrequencySec"` + PruneBatchSize uint32 `json:"pruneBatchSize"` + ListenerEventHandlerTimeoutSec uint32 `json:"listenerEventHandlerTimeoutSec"` + ListenerEventsCheckFrequencyMillis uint32 `json:"listenerEventsCheckFrequencyMillis"` + ContractUpdateCheckFrequencySec uint32 `json:"contractUpdateCheckFrequencySec"` + MaxRequestSizeBytes uint32 `json:"maxRequestSizeBytes"` + MaxRequestSizesList []uint32 `json:"maxRequestSizesList"` + MaxSecretsSizesList []uint32 `json:"maxSecretsSizesList"` + MinimumSubscriptionBalance assets.Link `json:"minimumSubscriptionBalance"` + AllowedHeartbeatInitiators []string `json:"allowedHeartbeatInitiators"` + GatewayConnectorConfig *connector.ConnectorConfig `json:"gatewayConnectorConfig"` + OnchainAllowlist *allowlist.OnchainAllowlistConfig `json:"onchainAllowlist"` + OnchainSubscriptions *subscriptions.OnchainSubscriptionsConfig `json:"onchainSubscriptions"` + RateLimiter *common.RateLimiterConfig `json:"rateLimiter"` + S4Constraints *s4.Constraints `json:"s4Constraints"` + DecryptionQueueConfig *DecryptionQueueConfig `json:"decryptionQueueConfig"` } type DecryptionQueueConfig struct { 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 e576e829677..5ea1d3e4030 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 @@ -18,7 +18,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/hashicorp/consul/sdk/freeport" @@ -29,8 +28,10 @@ import ( confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_allow_list" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_client_example" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" @@ -49,7 +50,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var nilOpts *bind.CallOpts @@ -318,16 +318,15 @@ func StartNewNode( c.OCR2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - c.P2P.V1.Enabled = ptr(false) c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", port)} if len(p2pV2Bootstrappers) > 0 { c.P2P.V2.DefaultBootstrappers = &p2pV2Bootstrappers } - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].Transactions.ForwardersEnabled = ptr(false) c.EVM[0].GasEstimator.LimitDefault = ptr(maxGas) c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") @@ -349,7 +348,7 @@ func StartNewNode( n, err := b.NonceAt(testutils.Context(t), owner.From, nil) require.NoError(t, err) - tx := types.NewTransaction( + tx := cltest.NewLegacyTransaction( n, transmitter, assets.Ether(1).ToInt(), 21000, diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index 2ebd7e30805..15e36f07b09 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -13,14 +13,16 @@ import ( "github.com/smartcontractkit/libocr/commontypes" libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/functions" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" - gwFunctions "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" + gwAllowlist "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" + gwSubscriptions "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -42,7 +44,7 @@ type FunctionsServicesConfig struct { Chain legacyevm.Chain ContractID string Logger logger.Logger - MailMon *utils.MailboxMonitor + MailMon *mailbox.Monitor URLsMonEndpoint commontypes.MonitoringEndpoint EthKeystore keystore.Eth ThresholdKeyShare []byte @@ -133,7 +135,11 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs allServices = append(allServices, job.NewServiceAdapter(functionsReportingPluginOracle)) if pluginConfig.GatewayConnectorConfig != nil && s4Storage != nil && pluginConfig.OnchainAllowlist != nil && pluginConfig.RateLimiter != nil && pluginConfig.OnchainSubscriptions != nil { - allowlist, err2 := gwFunctions.NewOnchainAllowlist(conf.Chain.Client(), *pluginConfig.OnchainAllowlist, conf.Logger) + allowlistORM, err := gwAllowlist.NewORM(conf.DB, conf.Logger, conf.QConfig, pluginConfig.OnchainAllowlist.ContractAddress) + if err != nil { + return nil, errors.Wrap(err, "failed to create allowlist ORM") + } + allowlist, err2 := gwAllowlist.NewOnchainAllowlist(conf.Chain.Client(), *pluginConfig.OnchainAllowlist, allowlistORM, conf.Logger) if err2 != nil { return nil, errors.Wrap(err, "failed to create OnchainAllowlist") } @@ -141,12 +147,16 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs if err2 != nil { return nil, errors.Wrap(err, "failed to create a RateLimiter") } - subscriptions, err2 := gwFunctions.NewOnchainSubscriptions(conf.Chain.Client(), *pluginConfig.OnchainSubscriptions, conf.Logger) + subscriptionsORM, err := gwSubscriptions.NewORM(conf.DB, conf.Logger, conf.QConfig, pluginConfig.OnchainSubscriptions.ContractAddress) + if err != nil { + return nil, errors.Wrap(err, "failed to create subscriptions ORM") + } + subscriptions, err2 := gwSubscriptions.NewOnchainSubscriptions(conf.Chain.Client(), *pluginConfig.OnchainSubscriptions, subscriptionsORM, conf.Logger) if err2 != nil { return nil, errors.Wrap(err, "failed to create a OnchainSubscriptions") } connectorLogger := conf.Logger.Named("GatewayConnector").With("jobName", conf.Job.PipelineSpec.JobName) - connector, err2 := NewConnector(pluginConfig.GatewayConnectorConfig, conf.EthKeystore, conf.Chain.ID(), s4Storage, allowlist, rateLimiter, subscriptions, functionsListener, offchainTransmitter, pluginConfig.MinimumSubscriptionBalance, connectorLogger) + connector, err2 := NewConnector(&pluginConfig, conf.EthKeystore, conf.Chain.ID(), s4Storage, allowlist, rateLimiter, subscriptions, functionsListener, offchainTransmitter, connectorLogger) if err2 != nil { return nil, errors.Wrap(err, "failed to create a GatewayConnector") } @@ -173,24 +183,26 @@ func NewFunctionsServices(functionsOracleArgs, thresholdOracleArgs, s4OracleArgs return allServices, nil } -func NewConnector(gwcCfg *connector.ConnectorConfig, ethKeystore keystore.Eth, chainID *big.Int, s4Storage s4.Storage, allowlist gwFunctions.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions gwFunctions.OnchainSubscriptions, listener functions.FunctionsListener, offchainTransmitter functions.OffchainTransmitter, minimumBalance assets.Link, lggr logger.Logger) (connector.GatewayConnector, error) { +func NewConnector(pluginConfig *config.PluginConfig, ethKeystore keystore.Eth, chainID *big.Int, s4Storage s4.Storage, allowlist gwAllowlist.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions gwSubscriptions.OnchainSubscriptions, listener functions.FunctionsListener, offchainTransmitter functions.OffchainTransmitter, lggr logger.Logger) (connector.GatewayConnector, error) { enabledKeys, err := ethKeystore.EnabledKeysForChain(chainID) if err != nil { return nil, err } - configuredNodeAddress := common.HexToAddress(gwcCfg.NodeAddress) + configuredNodeAddress := common.HexToAddress(pluginConfig.GatewayConnectorConfig.NodeAddress) idx := slices.IndexFunc(enabledKeys, func(key ethkey.KeyV2) bool { return key.Address == configuredNodeAddress }) if idx == -1 { return nil, errors.New("key for configured node address not found") } signerKey := enabledKeys[idx].ToEcdsaPrivKey() - nodeAddress := enabledKeys[idx].ID() + if enabledKeys[idx].ID() != pluginConfig.GatewayConnectorConfig.NodeAddress { + return nil, errors.New("node address mismatch") + } - handler, err := functions.NewFunctionsConnectorHandler(nodeAddress, signerKey, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, minimumBalance, lggr) + handler, err := functions.NewFunctionsConnectorHandler(pluginConfig, signerKey, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, lggr) if err != nil { return nil, err } - connector, err := connector.NewGatewayConnector(gwcCfg, handler, handler, utils.NewRealClock(), lggr) + connector, err := connector.NewGatewayConnector(pluginConfig.GatewayConnectorConfig, handler, handler, utils.NewRealClock(), lggr) if err != nil { return nil, err } diff --git a/core/services/ocr2/plugins/functions/plugin_test.go b/core/services/ocr2/plugins/functions/plugin_test.go index d77fabcc437..cd7956240df 100644 --- a/core/services/ocr2/plugins/functions/plugin_test.go +++ b/core/services/ocr2/plugins/functions/plugin_test.go @@ -8,15 +8,16 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/logger" sfmocks "github.com/smartcontractkit/chainlink/v2/core/services/functions/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" hc "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/common" - gfmocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/mocks" + gfaMocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist/mocks" + gfsMocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" s4mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" ) @@ -32,14 +33,17 @@ func TestNewConnector_Success(t *testing.T) { chainID := big.NewInt(80001) ethKeystore := ksmocks.NewEth(t) s4Storage := s4mocks.NewStorage(t) - allowlist := gfmocks.NewOnchainAllowlist(t) - subscriptions := gfmocks.NewOnchainSubscriptions(t) + allowlist := gfaMocks.NewOnchainAllowlist(t) + subscriptions := gfsMocks.NewOnchainSubscriptions(t) rateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) require.NoError(t, err) listener := sfmocks.NewFunctionsListener(t) offchainTransmitter := sfmocks.NewOffchainTransmitter(t) ethKeystore.On("EnabledKeysForChain", mock.Anything).Return([]ethkey.KeyV2{keyV2}, nil) - _, err = functions.NewConnector(gwcCfg, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, *assets.NewLinkFromJuels(0), logger.TestLogger(t)) + config := &config.PluginConfig{ + GatewayConnectorConfig: gwcCfg, + } + _, err = functions.NewConnector(config, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) require.NoError(t, err) } @@ -57,13 +61,16 @@ func TestNewConnector_NoKeyForConfiguredAddress(t *testing.T) { chainID := big.NewInt(80001) ethKeystore := ksmocks.NewEth(t) s4Storage := s4mocks.NewStorage(t) - allowlist := gfmocks.NewOnchainAllowlist(t) - subscriptions := gfmocks.NewOnchainSubscriptions(t) + allowlist := gfaMocks.NewOnchainAllowlist(t) + subscriptions := gfsMocks.NewOnchainSubscriptions(t) rateLimiter, err := hc.NewRateLimiter(hc.RateLimiterConfig{GlobalRPS: 100.0, GlobalBurst: 100, PerSenderRPS: 100.0, PerSenderBurst: 100}) require.NoError(t, err) listener := sfmocks.NewFunctionsListener(t) offchainTransmitter := sfmocks.NewOffchainTransmitter(t) ethKeystore.On("EnabledKeysForChain", mock.Anything).Return([]ethkey.KeyV2{{Address: common.HexToAddress(addresses[1])}}, nil) - _, err = functions.NewConnector(gwcCfg, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, *assets.NewLinkFromJuels(0), logger.TestLogger(t)) + config := &config.PluginConfig{ + GatewayConnectorConfig: gwcCfg, + } + _, err = functions.NewConnector(config, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) require.Error(t, err) } diff --git a/core/services/ocr2/plugins/median/services.go b/core/services/ocr2/plugins/median/services.go index 2d1ef720545..2a874ff1756 100644 --- a/core/services/ocr2/plugins/median/services.go +++ b/core/services/ocr2/plugins/median/services.go @@ -125,11 +125,20 @@ func NewMedianServices(ctx context.Context, CreatedAt: time.Now(), }, lggr) - if cmdName := env.MedianPluginCmd.Get(); cmdName != "" { - + if cmdName := env.MedianPlugin.Cmd.Get(); cmdName != "" { // use unique logger names so we can use it to register a loop medianLggr := lggr.Named("Median").Named(spec.ContractID).Named(spec.GetID()) - cmdFn, telem, err2 := cfg.RegisterLOOP(medianLggr.Name(), cmdName) + envVars, err2 := plugins.ParseEnvFile(env.MedianPlugin.Env.Get()) + if err2 != nil { + err = fmt.Errorf("failed to parse median env file: %w", err2) + abort() + return + } + cmdFn, telem, err2 := cfg.RegisterLOOP(plugins.CmdConfig{ + ID: medianLggr.Name(), + Cmd: cmdName, + Env: envVars, + }) if err2 != nil { err = fmt.Errorf("failed to register loop: %w", err2) abort() diff --git a/core/services/ocr2/plugins/mercury/helpers_test.go b/core/services/ocr2/plugins/mercury/helpers_test.go index ed59213840c..473db53bc6f 100644 --- a/core/services/ocr2/plugins/mercury/helpers_test.go +++ b/core/services/ocr2/plugins/mercury/helpers_test.go @@ -25,6 +25,8 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -39,8 +41,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ pb.MercuryServer = &mercuryServer{} @@ -199,8 +199,8 @@ func setupNode( c.P2P.V2.Enabled = ptr(true) c.P2P.V2.AnnounceAddresses = &p2paddresses c.P2P.V2.ListenAddresses = &p2paddresses - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) }) lggr, observedLogs := logger.TestLoggerObserved(t, zapcore.DebugLevel) diff --git a/core/services/ocr2/plugins/mercury/integration_test.go b/core/services/ocr2/plugins/mercury/integration_test.go index e8adb55b397..6d847098f94 100644 --- a/core/services/ocr2/plugins/mercury/integration_test.go +++ b/core/services/ocr2/plugins/mercury/integration_test.go @@ -34,10 +34,11 @@ import ( ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/wsrpc/credentials" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaycodecv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - relaycodecv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" - relaycodecv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" + v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" + relaymercury "github.com/smartcontractkit/chainlink-data-streams/mercury" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -62,7 +63,7 @@ var ( f = uint8(1) n = 4 // number of nodes multiplier int64 = 100000000 - rawOnchainConfig = relaymercury.OnchainConfig{ + rawOnchainConfig = mercurytypes.OnchainConfig{ Min: big.NewInt(0), Max: big.NewInt(math.MaxInt64), } @@ -154,7 +155,7 @@ func TestIntegration_MercuryV1(t *testing.T) { serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { - report, err := (&reportcodecv1.ReportCodec{}).BuildReport(relaycodecv1.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), CurrentBlockHash: make([]byte, 32)}) + report, err := (&reportcodecv1.ReportCodec{}).BuildReport(v1.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), CurrentBlockHash: make([]byte, 32)}) if err != nil { panic(err) } @@ -356,7 +357,7 @@ func TestIntegration_MercuryV1(t *testing.T) { err = reportcodecv1.ReportTypes.UnpackIntoMap(reportElems, report.([]byte)) require.NoError(t, err) - feedID := ([32]byte)(reportElems["feedId"].([32]uint8)) + feedID := reportElems["feedId"].([32]uint8) feed, exists := feedM[feedID] require.True(t, exists) @@ -420,7 +421,7 @@ func TestIntegration_MercuryV1(t *testing.T) { err = reportcodecv1.ReportTypes.UnpackIntoMap(reportElems, report.([]byte)) require.NoError(t, err) - feedID := ([32]byte)(reportElems["feedId"].([32]uint8)) + feedID := reportElems["feedId"].([32]uint8) feed, exists := feedM[feedID] require.True(t, exists) @@ -503,7 +504,7 @@ func TestIntegration_MercuryV2(t *testing.T) { serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { - report, err := (&reportcodecv2.ReportCodec{}).BuildReport(relaycodecv2.ReportFields{BenchmarkPrice: big.NewInt(234567), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) + report, err := (&reportcodecv2.ReportCodec{}).BuildReport(v2.ReportFields{BenchmarkPrice: big.NewInt(234567), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) if err != nil { panic(err) } @@ -690,7 +691,7 @@ func TestIntegration_MercuryV2(t *testing.T) { err = reportcodecv2.ReportTypes.UnpackIntoMap(reportElems, report.([]byte)) require.NoError(t, err) - feedID := ([32]byte)(reportElems["feedId"].([32]uint8)) + feedID := reportElems["feedId"].([32]uint8) feed, exists := feedM[feedID] require.True(t, exists) @@ -779,7 +780,7 @@ func TestIntegration_MercuryV3(t *testing.T) { serverKey := csakey.MustNewV2XXXTestingOnly(big.NewInt(-1)) serverPubKey := serverKey.PublicKey srv := NewMercuryServer(t, ed25519.PrivateKey(serverKey.Raw()), reqs, func() []byte { - report, err := (&reportcodecv3.ReportCodec{}).BuildReport(relaycodecv3.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) + report, err := (&reportcodecv3.ReportCodec{}).BuildReport(v3.ReportFields{BenchmarkPrice: big.NewInt(234567), Bid: big.NewInt(1), Ask: big.NewInt(1), LinkFee: big.NewInt(1), NativeFee: big.NewInt(1)}) if err != nil { panic(err) } @@ -970,7 +971,7 @@ func TestIntegration_MercuryV3(t *testing.T) { err = reportcodecv3.ReportTypes.UnpackIntoMap(reportElems, report.([]byte)) require.NoError(t, err) - feedID := ([32]byte)(reportElems["feedId"].([32]uint8)) + feedID := reportElems["feedId"].([32]uint8) feed, exists := feedM[feedID] require.True(t, exists) diff --git a/core/services/ocr2/plugins/mercury/plugin.go b/core/services/ocr2/plugins/mercury/plugin.go index d443008334c..b2767d6bcf5 100644 --- a/core/services/ocr2/plugins/mercury/plugin.go +++ b/core/services/ocr2/plugins/mercury/plugin.go @@ -7,10 +7,10 @@ import ( libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + relaymercuryv1 "github.com/smartcontractkit/chainlink-data-streams/mercury/v1" + relaymercuryv2 "github.com/smartcontractkit/chainlink-data-streams/mercury/v2" + relaymercuryv3 "github.com/smartcontractkit/chainlink-data-streams/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -67,7 +67,7 @@ func NewServices( lggr, saver, chEnhancedTelem, - ocr2Provider.ChainReader(), + ocr2Provider.MercuryChainReader(), ocr2Provider.MercuryServerFetcher(), pluginConfig.InitialBlockNumber.Ptr(), feedID, 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 bc30ac781de..8c8ea721d73 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -25,6 +25,10 @@ type Registry struct { func (_m *Registry) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { ret := _m.Called(opts, startIndex, maxCount) + if len(ret) == 0 { + panic("no return value specified for GetActiveUpkeepIDs") + } + var r0 []*big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, *big.Int) ([]*big.Int, error)); ok { @@ -51,6 +55,10 @@ func (_m *Registry) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, func (_m *Registry) GetState(opts *bind.CallOpts) (keeper_registry_wrapper2_0.GetState, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetState") + } + var r0 keeper_registry_wrapper2_0.GetState var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (keeper_registry_wrapper2_0.GetState, error)); ok { @@ -75,6 +83,10 @@ func (_m *Registry) GetState(opts *bind.CallOpts) (keeper_registry_wrapper2_0.Ge func (_m *Registry) GetUpkeep(opts *bind.CallOpts, id *big.Int) (keeper_registry_wrapper2_0.UpkeepInfo, error) { ret := _m.Called(opts, id) + if len(ret) == 0 { + panic("no return value specified for GetUpkeep") + } + var r0 keeper_registry_wrapper2_0.UpkeepInfo var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (keeper_registry_wrapper2_0.UpkeepInfo, error)); ok { @@ -99,6 +111,10 @@ func (_m *Registry) GetUpkeep(opts *bind.CallOpts, id *big.Int) (keeper_registry func (_m *Registry) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go index 0e0ceba7160..51448db35cf 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20/registry_test.go @@ -16,8 +16,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestGetActiveUpkeepKeys(t *testing.T) { @@ -176,8 +176,8 @@ func TestPollLogs(t *testing.T) { InputStart: 250, InputEnd: 500, OutputLogs: []logpoller.Log{ - {EvmChainId: utils.NewBig(big.NewInt(5)), LogIndex: 1}, - {EvmChainId: utils.NewBig(big.NewInt(6)), LogIndex: 2}, + {EvmChainId: ubig.New(big.NewInt(5)), LogIndex: 1}, + {EvmChainId: ubig.New(big.NewInt(6)), LogIndex: 2}, }, OutputErr: nil, }, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go index 7ea476ee773..55c01939cb8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list.go @@ -4,7 +4,9 @@ import ( "math/big" "sync" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) @@ -18,7 +20,7 @@ type ActiveUpkeepList interface { // Remove removes entries from the list Remove(id ...*big.Int) int // View returns the list of IDs of the given type - View(...ocr2keepers.UpkeepType) []*big.Int + View(...types.UpkeepType) []*big.Int // IsActive returns true if the given ID is of an active upkeep IsActive(id *big.Int) bool Size() int @@ -81,7 +83,7 @@ func (al *activeList) Remove(ids ...*big.Int) int { } // View returns the list of IDs of the given type -func (al *activeList) View(upkeepTypes ...ocr2keepers.UpkeepType) []*big.Int { +func (al *activeList) View(upkeepTypes ...types.UpkeepType) []*big.Int { al.lock.RLock() defer al.lock.RUnlock() diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go index 378589d1779..d9f9c45d749 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/active_list_test.go @@ -5,27 +5,29 @@ import ( "sort" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) func TestActiveUpkeepList(t *testing.T) { logIDs := []ocr2keepers.UpkeepIdentifier{ - core.GenUpkeepID(ocr2keepers.LogTrigger, "0"), - core.GenUpkeepID(ocr2keepers.LogTrigger, "1"), - core.GenUpkeepID(ocr2keepers.LogTrigger, "2"), - core.GenUpkeepID(ocr2keepers.LogTrigger, "3"), - core.GenUpkeepID(ocr2keepers.LogTrigger, "4"), + core.GenUpkeepID(types.LogTrigger, "0"), + core.GenUpkeepID(types.LogTrigger, "1"), + core.GenUpkeepID(types.LogTrigger, "2"), + core.GenUpkeepID(types.LogTrigger, "3"), + core.GenUpkeepID(types.LogTrigger, "4"), } conditionalIDs := []ocr2keepers.UpkeepIdentifier{ - core.GenUpkeepID(ocr2keepers.ConditionTrigger, "0"), - core.GenUpkeepID(ocr2keepers.ConditionTrigger, "1"), - core.GenUpkeepID(ocr2keepers.ConditionTrigger, "2"), - core.GenUpkeepID(ocr2keepers.ConditionTrigger, "3"), - core.GenUpkeepID(ocr2keepers.ConditionTrigger, "4"), + core.GenUpkeepID(types.ConditionTrigger, "0"), + core.GenUpkeepID(types.ConditionTrigger, "1"), + core.GenUpkeepID(types.ConditionTrigger, "2"), + core.GenUpkeepID(types.ConditionTrigger, "3"), + core.GenUpkeepID(types.ConditionTrigger, "4"), } tests := []struct { @@ -70,7 +72,7 @@ func TestActiveUpkeepList(t *testing.T) { for _, id := range tc.remove { require.False(t, al.IsActive(id)) } - logIds := al.View(ocr2keepers.LogTrigger) + logIds := al.View(types.LogTrigger) require.Equal(t, len(tc.expectedLogIds), len(logIds)) sort.Slice(logIds, func(i, j int) bool { return logIds[i].Cmp(logIds[j]) < 0 @@ -78,7 +80,7 @@ func TestActiveUpkeepList(t *testing.T) { for i := range logIds { require.Equal(t, tc.expectedLogIds[i], logIds[i]) } - conditionalIds := al.View(ocr2keepers.ConditionTrigger) + conditionalIds := al.View(types.ConditionTrigger) require.Equal(t, len(tc.expectedConditionalIds), len(conditionalIds)) sort.Slice(conditionalIds, func(i, j int) bool { return conditionalIds[i].Cmp(conditionalIds[j]) < 0 @@ -98,7 +100,7 @@ func TestActiveUpkeepList_error(t *testing.T) { al.items["-1"] = true al.items["100"] = true - keys := al.View(ocr2keepers.ConditionTrigger) + keys := al.View(types.ConditionTrigger) require.Equal(t, []*big.Int{big.NewInt(100)}, keys) }) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go index e7e9728c3a0..53303553db7 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/autotelemetry21/custom_telemetry.go @@ -10,12 +10,11 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" - evm21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -24,7 +23,7 @@ import ( type AutomationCustomTelemetryService struct { services.StateMachine monitoringEndpoint commontypes.MonitoringEndpoint - blockSubscriber *evm21.BlockSubscriber + blockSubscriber ocr2keepers.BlockSubscriber blockSubChanID int threadCtrl utils.ThreadControl lggr logger.Logger @@ -34,7 +33,7 @@ type AutomationCustomTelemetryService struct { // NewAutomationCustomTelemetryService creates a telemetry service for new blocks and node version func NewAutomationCustomTelemetryService(me commontypes.MonitoringEndpoint, - lggr logger.Logger, blocksub *evm21.BlockSubscriber, configTracker types.ContractConfigTracker) (*AutomationCustomTelemetryService, error) { + lggr logger.Logger, blocksub ocr2keepers.BlockSubscriber, configTracker types.ContractConfigTracker) (*AutomationCustomTelemetryService, error) { return &AutomationCustomTelemetryService{ monitoringEndpoint: me, threadCtrl: utils.NewThreadControl(), diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go index 134a75fc2c7..9ae17c08ee3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go index 41a43b951e7..2be6a6a874c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/block_subscriber_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/interfaces.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/interfaces.go index 49975855b54..4dd4d387a80 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/interfaces.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/interfaces.go @@ -3,7 +3,7 @@ package core import ( "context" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) // UpkeepStateReader is the interface for reading the current state of upkeeps. 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 b036fbb26c3..5a815987a83 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,13 +1,13 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks import ( context "context" - mock "github.com/stretchr/testify/mock" + automation "github.com/smartcontractkit/chainlink-common/pkg/types/automation" - types "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + mock "github.com/stretchr/testify/mock" ) // UpkeepStateReader is an autogenerated mock type for the UpkeepStateReader type @@ -16,7 +16,7 @@ type UpkeepStateReader struct { } // SelectByWorkIDs provides a mock function with given fields: ctx, workIDs -func (_m *UpkeepStateReader) SelectByWorkIDs(ctx context.Context, workIDs ...string) ([]types.UpkeepState, error) { +func (_m *UpkeepStateReader) SelectByWorkIDs(ctx context.Context, workIDs ...string) ([]automation.UpkeepState, error) { _va := make([]interface{}, len(workIDs)) for _i := range workIDs { _va[_i] = workIDs[_i] @@ -26,16 +26,20 @@ func (_m *UpkeepStateReader) SelectByWorkIDs(ctx context.Context, workIDs ...str _ca = append(_ca, _va...) ret := _m.Called(_ca...) - var r0 []types.UpkeepState + if len(ret) == 0 { + panic("no return value specified for SelectByWorkIDs") + } + + var r0 []automation.UpkeepState var r1 error - if rf, ok := ret.Get(0).(func(context.Context, ...string) ([]types.UpkeepState, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, ...string) ([]automation.UpkeepState, error)); ok { return rf(ctx, workIDs...) } - if rf, ok := ret.Get(0).(func(context.Context, ...string) []types.UpkeepState); ok { + if rf, ok := ret.Get(0).(func(context.Context, ...string) []automation.UpkeepState); ok { r0 = rf(ctx, workIDs...) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.UpkeepState) + r0 = ret.Get(0).([]automation.UpkeepState) } } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload.go index ed5530ae7b5..5077e7b74d5 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) var ( diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload_test.go index cb3a67dde0c..63de1f25ec4 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/payload_test.go @@ -4,10 +4,12 @@ import ( "math/big" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) func TestWorkID(t *testing.T) { @@ -35,7 +37,7 @@ func TestWorkID(t *testing.T) { }, { name: "happy flow with extension", - upkeepID: GenUpkeepID(ocr2keepers.LogTrigger, "12345").String(), + upkeepID: GenUpkeepID(types.LogTrigger, "12345").String(), trigger: ocr2keepers.Trigger{ BlockNumber: 123, BlockHash: common.HexToHash("0xabcdef"), @@ -96,7 +98,7 @@ func TestNewUpkeepPayload(t *testing.T) { tests := []struct { name string upkeepID *big.Int - upkeepType ocr2keepers.UpkeepType + upkeepType types.UpkeepType trigger ocr2keepers.Trigger check []byte errored bool @@ -105,7 +107,7 @@ func TestNewUpkeepPayload(t *testing.T) { { name: "happy flow no extension", upkeepID: big.NewInt(111), - upkeepType: ocr2keepers.ConditionTrigger, + upkeepType: types.ConditionTrigger, trigger: ocr2keepers.Trigger{ BlockNumber: 11, BlockHash: common.HexToHash("0x11111"), @@ -116,7 +118,7 @@ func TestNewUpkeepPayload(t *testing.T) { { name: "happy flow with extension", upkeepID: big.NewInt(111), - upkeepType: ocr2keepers.LogTrigger, + upkeepType: types.LogTrigger, trigger: ocr2keepers.Trigger{ BlockNumber: 11, BlockHash: common.HexToHash("0x11111"), diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/testutil.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/testutil.go index 3c0eeb1c44e..18f4a73de05 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/testutil.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/testutil.go @@ -3,13 +3,15 @@ package core import ( "math/big" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) // GenUpkeepID generates an ocr2keepers.UpkeepIdentifier with a specific UpkeepType and some random string -func GenUpkeepID(uType ocr2keepers.UpkeepType, rand string) ocr2keepers.UpkeepIdentifier { +func GenUpkeepID(uType types.UpkeepType, rand string) ocr2keepers.UpkeepIdentifier { b := append([]byte{1}, common.LeftPadBytes([]byte{uint8(uType)}, 15)...) b = append(b, []byte(rand)...) b = common.RightPadBytes(b, 32-len(b)) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger.go index 02e6946c8fb..b6ea7399736 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger.go @@ -5,9 +5,9 @@ import ( "math/big" "strings" - "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" ) @@ -33,13 +33,13 @@ func PackTrigger(id *big.Int, trig triggerWrapper) ([]byte, error) { return nil, ErrInvalidUpkeepID } switch upkeepType { - case ocr2keepers.ConditionTrigger: + case types.ConditionTrigger: trig := automation_utils_2_1.KeeperRegistryBase21ConditionalTrigger{ BlockNum: trig.BlockNum, BlockHash: trig.BlockHash, } trigger, err = utilsABI.Pack("_conditionalTrigger", &trig) - case ocr2keepers.LogTrigger: + case types.LogTrigger: logTrig := automation_utils_2_1.KeeperRegistryBase21LogTrigger{ BlockNum: trig.BlockNum, BlockHash: trig.BlockHash, @@ -70,7 +70,7 @@ func UnpackTrigger(id *big.Int, raw []byte) (triggerWrapper, error) { return triggerWrapper{}, ErrInvalidUpkeepID } switch upkeepType { - case ocr2keepers.ConditionTrigger: + case types.ConditionTrigger: unpacked, err := utilsABI.Methods["_conditionalTrigger"].Inputs.Unpack(raw) if err != nil { return triggerWrapper{}, fmt.Errorf("%w: failed to unpack conditional trigger", err) @@ -84,7 +84,7 @@ func UnpackTrigger(id *big.Int, raw []byte) (triggerWrapper, error) { } copy(triggerW.BlockHash[:], converted.BlockHash[:]) return triggerW, nil - case ocr2keepers.LogTrigger: + case types.LogTrigger: unpacked, err := utilsABI.Methods["_logTrigger"].Inputs.Unpack(raw) if err != nil { return triggerWrapper{}, fmt.Errorf("%w: failed to unpack log trigger", err) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger_test.go index 366d59b6397..0a5d3fba4a0 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/trigger_test.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) func TestPackUnpackTrigger(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type.go index 7820b47e6eb..b285db4d8aa 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type.go @@ -3,7 +3,9 @@ package core import ( "math/big" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) const ( @@ -17,17 +19,17 @@ const ( // GetUpkeepType returns the upkeep type from the given ID. // it follows the same logic as the contract, but performs it locally. -func GetUpkeepType(id ocr2keepers.UpkeepIdentifier) ocr2keepers.UpkeepType { +func GetUpkeepType(id ocr2keepers.UpkeepIdentifier) types.UpkeepType { for i := upkeepTypeStartIndex; i < upkeepTypeByteIndex; i++ { if id[i] != 0 { // old id - return ocr2keepers.ConditionTrigger + return types.ConditionTrigger } } typeByte := id[upkeepTypeByteIndex] - return ocr2keepers.UpkeepType(typeByte) + return types.UpkeepType(typeByte) } -func getUpkeepTypeFromBigInt(id *big.Int) (ocr2keepers.UpkeepType, bool) { +func getUpkeepTypeFromBigInt(id *big.Int) (types.UpkeepType, bool) { uid := &ocr2keepers.UpkeepIdentifier{} ok := uid.FromBigInt(id) return GetUpkeepType(*uid), ok diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type_test.go index 6f81ca7690e..1e4ec201b47 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/type_test.go @@ -4,36 +4,38 @@ import ( "math/big" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/stretchr/testify/assert" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) func TestGetUpkeepType(t *testing.T) { tests := []struct { name string upkeepID []byte - upkeepType ocr2keepers.UpkeepType + upkeepType types.UpkeepType }{ { "zeroed id", big.NewInt(0).Bytes(), - ocr2keepers.ConditionTrigger, + types.ConditionTrigger, }, { "old id", []byte("5820911532554020907796191562093071158274499580927271776163559390280294438608"), - ocr2keepers.ConditionTrigger, + types.ConditionTrigger, }, { "condition trigger", - GenUpkeepID(ocr2keepers.ConditionTrigger, "").BigInt().Bytes(), - ocr2keepers.ConditionTrigger, + GenUpkeepID(types.ConditionTrigger, "").BigInt().Bytes(), + types.ConditionTrigger, }, { "log trigger", - GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt().Bytes(), - ocr2keepers.LogTrigger, + GenUpkeepID(types.LogTrigger, "111").BigInt().Bytes(), + types.LogTrigger, }, { "log trigger id", @@ -41,7 +43,7 @@ func TestGetUpkeepType(t *testing.T) { id, _ := big.NewInt(0).SetString("32329108151019397958065800113404894502874153543356521479058624064899121404671", 10) return id.Bytes() }(), - ocr2keepers.LogTrigger, + types.LogTrigger, }, } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go index 89fcbb4a0ef..cdf2b0ea521 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder.go @@ -4,7 +4,9 @@ import ( "fmt" "math/big" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" @@ -65,7 +67,7 @@ func (e reportEncoder) Encode(results ...ocr2keepers.CheckResult) ([]byte, error BlockHash: result.Trigger.BlockHash, } switch core.GetUpkeepType(result.UpkeepID) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: triggerW.TxHash = result.Trigger.LogTriggerExtension.TxHash triggerW.LogIndex = result.Trigger.LogTriggerExtension.Index triggerW.LogBlockHash = result.Trigger.LogTriggerExtension.BlockHash @@ -107,7 +109,7 @@ func (e reportEncoder) Extract(raw []byte) ([]ocr2keepers.ReportedUpkeep, error) triggerW.BlockHash, ) switch core.GetUpkeepType(*id) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: trigger.LogTriggerExtension = &ocr2keepers.LogTriggerExtension{} trigger.LogTriggerExtension.TxHash = triggerW.TxHash trigger.LogTriggerExtension.Index = triggerW.LogIndex diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go index aa549ab3ec8..600dc851728 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/encoder_test.go @@ -7,10 +7,12 @@ import ( "os" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" ) @@ -44,7 +46,7 @@ func TestReportEncoder_EncodeExtract(t *testing.T) { { "happy flow single", []ocr2keepers.CheckResult{ - newResult(1, 1, core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.LogTrigger, "123"), 1, 1), }, 736, 1, @@ -54,9 +56,9 @@ func TestReportEncoder_EncodeExtract(t *testing.T) { { "happy flow multiple", []ocr2keepers.CheckResult{ - newResult(1, 1, core.GenUpkeepID(ocr2keepers.LogTrigger, "10"), 1, 1), - newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "20"), 1, 1), - newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "30"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.LogTrigger, "10"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.ConditionTrigger, "20"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.ConditionTrigger, "30"), 1, 1), }, 1312, 3, @@ -66,9 +68,9 @@ func TestReportEncoder_EncodeExtract(t *testing.T) { { "happy flow highest block number first", []ocr2keepers.CheckResult{ - newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "30"), 1, 1), - newResult(1, 1, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "20"), 1, 1), - newResult(1, 1, core.GenUpkeepID(ocr2keepers.LogTrigger, "10"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.ConditionTrigger, "30"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.ConditionTrigger, "20"), 1, 1), + newResult(1, 1, core.GenUpkeepID(types.LogTrigger, "10"), 1, 1), }, 1312, 1000, @@ -114,8 +116,8 @@ func TestReportEncoder_BackwardsCompatibility(t *testing.T) { packer: NewAbiPacker(), } results := []ocr2keepers.CheckResult{ - newResult(1, 2, core.GenUpkeepID(ocr2keepers.LogTrigger, "10"), 5, 6), - newResult(3, 4, core.GenUpkeepID(ocr2keepers.ConditionTrigger, "20"), 7, 8), + newResult(1, 2, core.GenUpkeepID(types.LogTrigger, "10"), 5, 6), + newResult(3, 4, core.GenUpkeepID(types.ConditionTrigger, "20"), 7, 8), } encoded, err := encoder.Encode(results...) assert.NoError(t, err) @@ -136,7 +138,7 @@ func newResult(block int64, checkBlock ocr2keepers.BlockNumber, id ocr2keepers.U BlockHash: [32]byte{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}, } - if tp == ocr2keepers.LogTrigger { + if tp == types.LogTrigger { trig.LogTriggerExtension = &ocr2keepers.LogTriggerExtension{ Index: 1, TxHash: common.HexToHash("0x1234567890123456789012345678901234567890123456789012345678901234"), diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go index 06a3e7b106b..1f93fd3ee22 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/interface.go @@ -1,62 +1,54 @@ package encoding import ( - "math/big" - - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" ) +type UpkeepFailureReason uint8 +type PipelineExecutionState uint8 + const ( - // NOTE: This enum should be kept in sync with evmregistry/v21/mercury/upkeep_failure_reasons.go - // TODO (AUTO-7928) Remove this duplication // upkeep failure onchain reasons - UpkeepFailureReasonNone uint8 = 0 - UpkeepFailureReasonUpkeepCancelled uint8 = 1 - UpkeepFailureReasonUpkeepPaused uint8 = 2 - UpkeepFailureReasonTargetCheckReverted uint8 = 3 - UpkeepFailureReasonUpkeepNotNeeded uint8 = 4 - UpkeepFailureReasonPerformDataExceedsLimit uint8 = 5 - UpkeepFailureReasonInsufficientBalance uint8 = 6 - UpkeepFailureReasonMercuryCallbackReverted uint8 = 7 - UpkeepFailureReasonRevertDataExceedsLimit uint8 = 8 - UpkeepFailureReasonRegistryPaused uint8 = 9 + UpkeepFailureReasonNone UpkeepFailureReason = 0 + UpkeepFailureReasonUpkeepCancelled UpkeepFailureReason = 1 + UpkeepFailureReasonUpkeepPaused UpkeepFailureReason = 2 + UpkeepFailureReasonTargetCheckReverted UpkeepFailureReason = 3 + UpkeepFailureReasonUpkeepNotNeeded UpkeepFailureReason = 4 + UpkeepFailureReasonPerformDataExceedsLimit UpkeepFailureReason = 5 + UpkeepFailureReasonInsufficientBalance UpkeepFailureReason = 6 + UpkeepFailureReasonMercuryCallbackReverted UpkeepFailureReason = 7 + UpkeepFailureReasonRevertDataExceedsLimit UpkeepFailureReason = 8 + UpkeepFailureReasonRegistryPaused UpkeepFailureReason = 9 // leaving a gap here for more onchain failure reasons in the future // upkeep failure offchain reasons - UpkeepFailureReasonMercuryAccessNotAllowed uint8 = 32 - UpkeepFailureReasonTxHashNoLongerExists uint8 = 33 - UpkeepFailureReasonInvalidRevertDataInput uint8 = 34 - UpkeepFailureReasonSimulationFailed uint8 = 35 - UpkeepFailureReasonTxHashReorged uint8 = 36 + UpkeepFailureReasonMercuryAccessNotAllowed UpkeepFailureReason = 32 + UpkeepFailureReasonTxHashNoLongerExists UpkeepFailureReason = 33 + UpkeepFailureReasonInvalidRevertDataInput UpkeepFailureReason = 34 + UpkeepFailureReasonSimulationFailed UpkeepFailureReason = 35 + UpkeepFailureReasonTxHashReorged UpkeepFailureReason = 36 - // NOTE: This enum should be kept in sync with evmregistry/v21/mercury/upkeep_states.go - // TODO (AUTO-7928) Remove this duplication // pipeline execution error - NoPipelineError uint8 = 0 - CheckBlockTooOld uint8 = 1 - CheckBlockInvalid uint8 = 2 - RpcFlakyFailure uint8 = 3 - MercuryFlakyFailure uint8 = 4 - PackUnpackDecodeFailed uint8 = 5 - MercuryUnmarshalError uint8 = 6 - InvalidMercuryRequest uint8 = 7 - InvalidMercuryResponse uint8 = 8 // this will only happen if Mercury server sends bad responses - UpkeepNotAuthorized uint8 = 9 + NoPipelineError PipelineExecutionState = 0 + CheckBlockTooOld PipelineExecutionState = 1 + CheckBlockInvalid PipelineExecutionState = 2 + RpcFlakyFailure PipelineExecutionState = 3 + MercuryFlakyFailure PipelineExecutionState = 4 + PackUnpackDecodeFailed PipelineExecutionState = 5 + MercuryUnmarshalError PipelineExecutionState = 6 + InvalidMercuryRequest PipelineExecutionState = 7 + InvalidMercuryResponse PipelineExecutionState = 8 // this will only happen if Mercury server sends bad responses + UpkeepNotAuthorized PipelineExecutionState = 9 ) type UpkeepInfo = iregistry21.KeeperRegistryBase21UpkeepInfo type Packer interface { UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw string) (ocr2keepers.CheckResult, error) - UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) - UnpackPerformResult(raw string) (uint8, bool, error) + UnpackPerformResult(raw string) (PipelineExecutionState, bool, error) UnpackLogTriggerConfig(raw []byte) (automation_utils_2_1.LogTriggerConfig, error) PackReport(report automation_utils_2_1.KeeperRegistryBase21Report) ([]byte, error) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistryBase21Report, error) - PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) - UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) - DecodeStreamsLookupRequest(data []byte) (*mercury.StreamsLookupError, error) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go index 57013a6277a..81f4716a51b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer.go @@ -7,11 +7,10 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" ) // triggerWrapper is a wrapper for the different trigger types (log and condition triggers). @@ -67,36 +66,7 @@ func (p *abiPacker) UnpackCheckResult(payload ocr2keepers.UpkeepPayload, raw str return result, nil } -func (p *abiPacker) PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { - return p.registryABI.Pack("getUpkeepPrivilegeConfig", upkeepId) -} - -func (p *abiPacker) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) { - out, err := p.registryABI.Methods["getUpkeepPrivilegeConfig"].Outputs.UnpackValues(resp) - if err != nil { - return nil, fmt.Errorf("%w: unpack getUpkeepPrivilegeConfig return", err) - } - - bts := *abi.ConvertType(out[0], new([]byte)).(*[]byte) - - return bts, nil -} - -func (p *abiPacker) UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) { - out, err := p.registryABI.Methods["checkCallback"].Outputs.UnpackValues(callbackResp) - if err != nil { - return PackUnpackDecodeFailed, false, nil, 0, nil, fmt.Errorf("%w: unpack checkUpkeep return: %s", err, hexutil.Encode(callbackResp)) - } - - upkeepNeeded := *abi.ConvertType(out[0], new(bool)).(*bool) - rawPerformData := *abi.ConvertType(out[1], new([]byte)).(*[]byte) - failureReason := *abi.ConvertType(out[2], new(uint8)).(*uint8) - gasUsed := *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) - - return NoPipelineError, upkeepNeeded, rawPerformData, failureReason, gasUsed, nil -} - -func (p *abiPacker) UnpackPerformResult(raw string) (uint8, bool, error) { +func (p *abiPacker) UnpackPerformResult(raw string) (PipelineExecutionState, bool, error) { b, err := hexutil.Decode(raw) if err != nil { return PackUnpackDecodeFailed, false, err @@ -163,29 +133,11 @@ func (p *abiPacker) UnpackReport(raw []byte) (automation_utils_2_1.KeeperRegistr return report, nil } -// DecodeStreamsLookupRequest decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string feedParamKey, uint256 time, byte[] extraData) -func (p *abiPacker) DecodeStreamsLookupRequest(data []byte) (*mercury.StreamsLookupError, error) { - e := p.streamsABI.Errors["StreamsLookup"] - unpack, err := e.Unpack(data) - if err != nil { - return nil, fmt.Errorf("unpack error: %w", err) - } - errorParameters := unpack.([]interface{}) - - return &mercury.StreamsLookupError{ - FeedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), - Feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), - TimeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), - Time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int), - ExtraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte), - }, nil -} - // GetIneligibleCheckResultWithoutPerformData returns an ineligible check result with ineligibility reason and pipeline execution state but without perform data -func GetIneligibleCheckResultWithoutPerformData(p ocr2keepers.UpkeepPayload, reason uint8, state uint8, retryable bool) ocr2keepers.CheckResult { +func GetIneligibleCheckResultWithoutPerformData(p ocr2keepers.UpkeepPayload, reason UpkeepFailureReason, state PipelineExecutionState, retryable bool) ocr2keepers.CheckResult { return ocr2keepers.CheckResult{ - IneligibilityReason: reason, - PipelineExecutionState: state, + IneligibilityReason: uint8(reason), + PipelineExecutionState: uint8(state), Retryable: retryable, UpkeepID: p.UpkeepID, Trigger: p.Trigger, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go index 42fcd40d618..79221a620e1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding/packer_test.go @@ -1,8 +1,6 @@ package encoding import ( - "encoding/json" - "errors" "fmt" "math/big" "testing" @@ -12,12 +10,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" automation21Utils "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" ) func TestPacker_PackReport(t *testing.T) { @@ -212,7 +209,7 @@ func TestPacker_UnpackPerformResult(t *testing.T) { tests := []struct { Name string RawData string - State uint8 + State PipelineExecutionState }{ { Name: "unpack success", @@ -231,62 +228,6 @@ func TestPacker_UnpackPerformResult(t *testing.T) { } } -func TestPacker_UnpackCheckCallbackResult(t *testing.T) { - tests := []struct { - Name string - CallbackResp []byte - UpkeepNeeded bool - PerformData []byte - FailureReason uint8 - GasUsed *big.Int - ErrorString string - State uint8 - }{ - { - Name: "unpack upkeep needed", - CallbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - UpkeepNeeded: true, - PerformData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - FailureReason: uint8(UpkeepFailureReasonNone), - GasUsed: big.NewInt(11796), - }, - { - Name: "unpack upkeep not needed", - CallbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - UpkeepNeeded: false, - PerformData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - FailureReason: uint8(UpkeepFailureReasonUpkeepNotNeeded), - GasUsed: big.NewInt(13008), - }, - { - Name: "unpack malformed data", - CallbackResp: []byte{0, 0, 0, 23, 4, 163, 66, 91, 228, 102, 200, 84, 144, 233, 218, 44, 168, 192, 191, 253, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - UpkeepNeeded: false, - PerformData: nil, - ErrorString: "abi: improperly encoded boolean value: unpack checkUpkeep return: ", - State: PackUnpackDecodeFailed, - }, - } - for _, test := range tests { - t.Run(test.Name, func(t *testing.T) { - packer := NewAbiPacker() - - state, needed, pd, failureReason, gasUsed, err := packer.UnpackCheckCallbackResult(test.CallbackResp) - - if test.ErrorString != "" { - assert.EqualError(t, err, test.ErrorString+hexutil.Encode(test.CallbackResp)) - } else { - assert.Nil(t, err) - } - assert.Equal(t, test.UpkeepNeeded, needed) - assert.Equal(t, test.PerformData, pd) - assert.Equal(t, test.FailureReason, failureReason) - assert.Equal(t, test.GasUsed, gasUsed) - assert.Equal(t, test.State, state) - }) - } -} - func TestPacker_UnpackLogTriggerConfig(t *testing.T) { tests := []struct { name string @@ -349,130 +290,3 @@ func TestPacker_PackReport_UnpackReport(t *testing.T) { expected := "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000405060708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004050607080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040102030400000000000000000000000000000000000000000000000000000000" assert.Equal(t, hexutil.Encode(res), expected) } - -func TestPacker_PackGetUpkeepPrivilegeConfig(t *testing.T) { - tests := []struct { - name string - upkeepId *big.Int - raw []byte - errored bool - }{ - { - name: "happy path", - upkeepId: func() *big.Int { - id, _ := new(big.Int).SetString("52236098515066839510538748191966098678939830769967377496848891145101407612976", 10) - - return id - }(), - raw: func() []byte { - b, _ := hexutil.Decode("0x19d97a94737c9583000000000000000000000001ea8ed6d0617dd5b3b87374020efaf030") - - return b - }(), - errored: false, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - packer := NewAbiPacker() - - b, err := packer.PackGetUpkeepPrivilegeConfig(test.upkeepId) - - if !test.errored { - require.NoError(t, err, "no error expected from packing") - - assert.Equal(t, test.raw, b, "raw bytes for output should match expected") - } else { - assert.NotNil(t, err, "error expected from packing function") - } - }) - } -} - -func TestPacker_UnpackGetUpkeepPrivilegeConfig(t *testing.T) { - tests := []struct { - name string - raw []byte - errored bool - }{ - { - name: "happy path", - raw: func() []byte { - b, _ := hexutil.Decode("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000177b226d657263757279456e61626c6564223a747275657d000000000000000000") - - return b - }(), - errored: false, - }, - { - name: "error empty config", - raw: func() []byte { - b, _ := hexutil.Decode("0x") - - return b - }(), - errored: true, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - packer := NewAbiPacker() - - b, err := packer.UnpackGetUpkeepPrivilegeConfig(test.raw) - - if !test.errored { - require.NoError(t, err, "should unpack bytes from abi encoded value") - - // the actual struct to unmarshal into is not available to this - // package so basic json encoding is the limit of the following test - var data map[string]interface{} - err = json.Unmarshal(b, &data) - - assert.NoError(t, err, "packed data should unmarshal using json encoding") - assert.Equal(t, []byte(`{"mercuryEnabled":true}`), b) - } else { - assert.NotNil(t, err, "error expected from unpack function") - } - }) - } -} - -func TestPacker_DecodeStreamsLookupRequest(t *testing.T) { - tests := []struct { - name string - data []byte - expected *mercury.StreamsLookupError - state uint8 - err error - }{ - { - name: "success - decode to streams lookup", - data: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000002435eb50000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), - expected: &mercury.StreamsLookupError{ - FeedParamKey: "feedIdHex", - Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, - TimeParamKey: "blockNumber", - Time: big.NewInt(37969589), - ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, - }, - }, - { - name: "failure - unpack error", - data: []byte{1, 2, 3, 4}, - err: errors.New("unpack error: invalid data for unpacking"), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - packer := NewAbiPacker() - fl, err := packer.DecodeStreamsLookupRequest(tt.data) - assert.Equal(t, tt.expected, fl) - if tt.err != nil { - assert.Equal(t, tt.err.Error(), err.Error()) - } - }) - } -} diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go index 81f51311d44..9f11a1fca01 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer.go @@ -8,17 +8,19 @@ import ( "sync/atomic" "github.com/smartcontractkit/chainlink-automation/pkg/v3/random" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" ) var ( - // maxLogsPerUpkeepInBlock is the maximum number of logs allowed per upkeep in a block. - maxLogsPerUpkeepInBlock = 32 - // maxLogsPerBlock is the maximum number of blocks in the buffer. - maxLogsPerBlock = 1024 + // defaultFastExecLogsHigh is the default upper bound / maximum number of logs that Automation is committed to process for each upkeep, + // based on available capacity, i.e. if there are no logs from other upkeeps. + // Used by Log buffer to limit the number of logs we are saving in memory for each upkeep in a block + defaultFastExecLogsHigh = 32 + // defaultNumOfLogUpkeeps is the default number of log upkeeps supported by the registry. + defaultNumOfLogUpkeeps = 50 ) // fetchedLog holds the log and the ID of the upkeep @@ -143,20 +145,20 @@ type logEventBuffer struct { // size is the number of blocks supported by the buffer size int32 - maxBlockLogs, maxUpkeepLogsPerBlock int + numOfLogUpkeeps, fastExecLogsHigh uint32 // blocks is the circular buffer of fetched blocks blocks []fetchedBlock // latestBlock is the latest block number seen latestBlock int64 } -func newLogEventBuffer(lggr logger.Logger, size, maxBlockLogs, maxUpkeepLogsPerBlock int) *logEventBuffer { +func newLogEventBuffer(lggr logger.Logger, size, numOfLogUpkeeps, fastExecLogsHigh int) *logEventBuffer { return &logEventBuffer{ - lggr: lggr.Named("KeepersRegistry.LogEventBuffer"), - size: int32(size), - blocks: make([]fetchedBlock, size), - maxBlockLogs: maxBlockLogs, - maxUpkeepLogsPerBlock: maxUpkeepLogsPerBlock, + lggr: lggr.Named("KeepersRegistry.LogEventBuffer"), + size: int32(size), + blocks: make([]fetchedBlock, size), + numOfLogUpkeeps: uint32(numOfLogUpkeeps), + fastExecLogsHigh: uint32(fastExecLogsHigh), } } @@ -168,6 +170,11 @@ func (b *logEventBuffer) bufferSize() int { return int(atomic.LoadInt32(&b.size)) } +func (b *logEventBuffer) SetLimits(numOfLogUpkeeps, fastExecLogsHigh int) { + atomic.StoreUint32(&b.numOfLogUpkeeps, uint32(numOfLogUpkeeps)) + atomic.StoreUint32(&b.fastExecLogsHigh, uint32(fastExecLogsHigh)) +} + // enqueue adds logs (if not exist) to the buffer, returning the number of logs added // minus the number of logs dropped. func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { @@ -176,8 +183,8 @@ func (b *logEventBuffer) enqueue(id *big.Int, logs ...logpoller.Log) int { lggr := b.lggr.With("id", id.String()) - maxBlockLogs := int(b.maxBlockLogs) - maxUpkeepLogs := int(b.maxUpkeepLogsPerBlock) + maxBlockLogs := int(atomic.LoadUint32(&b.fastExecLogsHigh) * atomic.LoadUint32(&b.numOfLogUpkeeps)) + maxUpkeepLogs := int(atomic.LoadUint32(&b.fastExecLogsHigh)) latestBlock := b.latestBlockSeen() added, dropped := 0, 0 diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go index 046c93a428a..dca43ca14ac 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/buffer_test.go @@ -6,10 +6,12 @@ import ( "math/big" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -185,7 +187,7 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { }) t.Run("enqueue logs overflow", func(t *testing.T) { - buf := newLogEventBuffer(logger.TestLogger(t), 2, 2, 10) + buf := newLogEventBuffer(logger.TestLogger(t), 2, 2, 2) require.Equal(t, 2, buf.enqueue(big.NewInt(1), logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 0}, @@ -197,6 +199,50 @@ func TestLogEventBuffer_EnqueueDequeue(t *testing.T) { buf.lock.Unlock() }) + t.Run("enqueue logs overflow with dynamic limits", func(t *testing.T) { + buf := newLogEventBuffer(logger.TestLogger(t), 2, 10, 2) + + require.Equal(t, 2, buf.enqueue(big.NewInt(1), + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 0}, + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 1}, + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 2}, + )) + buf.SetLimits(10, 3) + require.Equal(t, 3, buf.enqueue(big.NewInt(1), + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 0}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 1}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 2}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 3}, + )) + + buf.lock.Lock() + defer buf.lock.Unlock() + require.Equal(t, 2, len(buf.blocks[0].logs)) + require.Equal(t, 3, len(buf.blocks[1].logs)) + }) + + t.Run("enqueue logs overflow with dynamic limits", func(t *testing.T) { + buf := newLogEventBuffer(logger.TestLogger(t), 2, 10, 2) + + require.Equal(t, 2, buf.enqueue(big.NewInt(1), + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 0}, + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 1}, + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 2}, + logpoller.Log{BlockNumber: 1, TxHash: common.HexToHash("0x1"), LogIndex: 3}, + )) + buf.SetLimits(10, 3) + require.Equal(t, 3, buf.enqueue(big.NewInt(1), + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 0}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 1}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 2}, + logpoller.Log{BlockNumber: 2, TxHash: common.HexToHash("0x21"), LogIndex: 3}, + )) + + buf.lock.Lock() + defer buf.lock.Unlock() + require.Equal(t, 2, len(buf.blocks[0].logs)) + }) + t.Run("enqueue block overflow", func(t *testing.T) { buf := newLogEventBuffer(logger.TestLogger(t), 3, 2, 10) @@ -378,7 +424,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -392,7 +438,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, }, @@ -406,7 +452,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, visited: []fetchedLog{}, @@ -418,7 +464,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -432,7 +478,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, }, @@ -447,7 +493,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, toAdd: []appendArgs{ @@ -458,7 +504,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -480,7 +526,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -493,7 +539,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 1, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -506,7 +552,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 10, maxUpkeepLogs: 2, @@ -521,7 +567,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 1, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -529,7 +575,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, }, @@ -546,7 +592,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 2, maxUpkeepLogs: 4, @@ -559,7 +605,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 1, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 2, maxUpkeepLogs: 4, @@ -572,7 +618,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, maxBlockLogs: 2, maxUpkeepLogs: 4, @@ -587,7 +633,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 1, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -595,7 +641,7 @@ func TestLogEventBuffer_FetchedBlock_Append(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, }, @@ -676,7 +722,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xb711bd1103927611ee41152aa8ae27f3330"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -685,7 +731,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "222").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "222").BigInt(), }, { log: logpoller.Log{ @@ -694,7 +740,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 4, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -703,7 +749,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 3, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "222").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "222").BigInt(), }, { log: logpoller.Log{ @@ -712,7 +758,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -721,7 +767,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 5, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -730,7 +776,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 3, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -739,7 +785,7 @@ func TestLogEventBuffer_FetchedBlock_Sort(t *testing.T) { TxHash: common.HexToHash("0xa651bd1109922111ee411525ebae27f3fb6"), LogIndex: 1, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, beforeSort: []string{ @@ -801,7 +847,7 @@ func TestLogEventBuffer_FetchedBlock_Clone(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 0, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, { log: logpoller.Log{ @@ -809,7 +855,7 @@ func TestLogEventBuffer_FetchedBlock_Clone(t *testing.T) { TxHash: common.HexToHash("0x1"), LogIndex: 2, }, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "111").BigInt(), + upkeepID: core.GenUpkeepID(types.LogTrigger, "111").BigInt(), }, }, } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_test.go index 8b3b836f87f..75684d17bd8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/filter_test.go @@ -74,7 +74,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "no selector configured - all logs are returned", upkeepFilter{ selector: 0, - topics: []common.Hash{contractAddress.Hash(), emptyTopic, emptyTopic, emptyTopic}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), emptyTopic, emptyTopic, emptyTopic}, upkeepID: uid, }, []logpoller.Log{ @@ -90,7 +90,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 1 - topics 1 is used to filter logs", upkeepFilter{ selector: 1, - topics: []common.Hash{contractAddress.Hash(), common.HexToHash(topic10), emptyTopic, emptyTopic}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), common.HexToHash(topic10), emptyTopic, emptyTopic}, upkeepID: uid, }, []logpoller.Log{ @@ -105,7 +105,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 2 - topic 2 is used to filter logs", upkeepFilter{ selector: 2, - topics: []common.Hash{contractAddress.Hash(), emptyTopic, common.HexToHash(topic21), emptyTopic}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), emptyTopic, common.HexToHash(topic21), emptyTopic}, upkeepID: uid, }, []logpoller.Log{ @@ -120,7 +120,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 3 - topics 1 2 are used to filter logs", upkeepFilter{ selector: 3, - topics: []common.Hash{contractAddress.Hash(), common.HexToHash(topic10), common.HexToHash(topic21), emptyTopic}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), common.HexToHash(topic10), common.HexToHash(topic21), emptyTopic}, upkeepID: uid, }, []logpoller.Log{ @@ -137,7 +137,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 4 - topic 3 is used to filter logs", upkeepFilter{ selector: 4, - topics: []common.Hash{contractAddress.Hash(), emptyTopic, emptyTopic, common.HexToHash(topic31)}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), emptyTopic, emptyTopic, common.HexToHash(topic31)}, upkeepID: uid, }, []logpoller.Log{ @@ -152,7 +152,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 5 - topics 1 3 are used to filter logs", upkeepFilter{ selector: 5, - topics: []common.Hash{contractAddress.Hash(), common.HexToHash(topic11), emptyTopic, common.HexToHash(topic31)}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), common.HexToHash(topic11), emptyTopic, common.HexToHash(topic31)}, upkeepID: uid, }, []logpoller.Log{ @@ -170,7 +170,7 @@ func TestUpkeepFilter_Select(t *testing.T) { "selector is 7 - topics 1 2 3 are used to filter logs", upkeepFilter{ selector: 7, - topics: []common.Hash{contractAddress.Hash(), common.HexToHash(topic10), common.HexToHash(topic20), common.HexToHash(topic30)}, + topics: []common.Hash{common.BytesToHash(contractAddress.Bytes()), common.HexToHash(topic10), common.HexToHash(topic20), common.HexToHash(topic30)}, upkeepID: uid, }, []logpoller.Log{ diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go index caad1adc9ad..5ef06f1bd08 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/integration_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" @@ -18,7 +20,7 @@ import ( "go.uber.org/zap/zapcore" "golang.org/x/time/rate" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" @@ -150,7 +152,7 @@ func TestIntegration_LogEventProvider_UpdateConfig(t *testing.T) { require.Equal(t, 1, len(addrs)) t.Run("update filter config", func(t *testing.T) { - upkeepID := evmregistry21.GenUpkeepID(ocr2keepers.LogTrigger, "111") + upkeepID := evmregistry21.GenUpkeepID(types.LogTrigger, "111") id := upkeepID.BigInt() cfg := newPlainLogTriggerConfig(addrs[0]) b, err := ethClient.BlockByHash(ctx, backend.Commit()) @@ -182,7 +184,7 @@ func TestIntegration_LogEventProvider_UpdateConfig(t *testing.T) { }) t.Run("register same log filter", func(t *testing.T) { - upkeepID := evmregistry21.GenUpkeepID(ocr2keepers.LogTrigger, "222") + upkeepID := evmregistry21.GenUpkeepID(types.LogTrigger, "222") id := upkeepID.BigInt() cfg := newPlainLogTriggerConfig(addrs[0]) b, err := ethClient.BlockByHash(ctx, backend.Commit()) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go index 2dabcc82671..d1360faaf6d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider.go @@ -16,7 +16,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -109,7 +109,7 @@ func NewLogProvider(lggr logger.Logger, poller logpoller.LogPoller, packer LogDa threadCtrl: utils.NewThreadControl(), lggr: lggr.Named("KeepersRegistry.LogEventProvider"), packer: packer, - buffer: newLogEventBuffer(lggr, int(opts.LookbackBlocks), maxLogsPerBlock, maxLogsPerUpkeepInBlock), + buffer: newLogEventBuffer(lggr, int(opts.LookbackBlocks), defaultNumOfLogUpkeeps, defaultFastExecLogsHigh), poller: poller, opts: opts, filterStore: filterStore, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go index 278c727a06a..d978940d297 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_life_cycle_test.go @@ -5,13 +5,13 @@ import ( "math/big" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -155,7 +155,7 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { p := NewLogProvider(logger.TestLogger(t), mp, &mockedPacker{}, NewUpkeepFilterStore(), NewOptions(200)) require.NoError(t, p.RegisterFilter(ctx, FilterOptions{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1111").BigInt(), + UpkeepID: core.GenUpkeepID(types.LogTrigger, "1111").BigInt(), TriggerConfig: LogTriggerConfig{ ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{1, 2, 3, 4}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{1, 2, 3, 4}, 32)), @@ -163,7 +163,7 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { UpdateBlock: uint64(0), })) require.NoError(t, p.RegisterFilter(ctx, FilterOptions{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2222").BigInt(), + UpkeepID: core.GenUpkeepID(types.LogTrigger, "2222").BigInt(), TriggerConfig: LogTriggerConfig{ ContractAddress: common.BytesToAddress(common.LeftPadBytes([]byte{1, 2, 3, 4}, 20)), Topic0: common.BytesToHash(common.LeftPadBytes([]byte{1, 2, 3, 4}, 32)), @@ -175,11 +175,11 @@ func TestEventLogProvider_RefreshActiveUpkeeps(t *testing.T) { newIds, err := p.RefreshActiveUpkeeps() require.NoError(t, err) require.Len(t, newIds, 0) - mp.On("HasFilter", p.filterName(core.GenUpkeepID(ocr2keepers.LogTrigger, "2222").BigInt())).Return(true) + mp.On("HasFilter", p.filterName(core.GenUpkeepID(types.LogTrigger, "2222").BigInt())).Return(true) newIds, err = p.RefreshActiveUpkeeps( - core.GenUpkeepID(ocr2keepers.LogTrigger, "2222").BigInt(), - core.GenUpkeepID(ocr2keepers.LogTrigger, "1234").BigInt(), - core.GenUpkeepID(ocr2keepers.LogTrigger, "123").BigInt()) + core.GenUpkeepID(types.LogTrigger, "2222").BigInt(), + core.GenUpkeepID(types.LogTrigger, "1234").BigInt(), + core.GenUpkeepID(types.LogTrigger, "123").BigInt()) require.NoError(t, err) require.Len(t, newIds, 2) require.Equal(t, 1, p.filterStore.Size()) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go index 81774e26387..464b9aa3ba6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/provider_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/time/rate" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go index c7f6884426f..b28ece9843f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer.go @@ -14,10 +14,12 @@ import ( "sync/atomic" "time" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/smartcontractkit/chainlink-automation/pkg/v3/random" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -193,7 +195,7 @@ func (r *logRecoverer) HealthReport() map[string]error { func (r *logRecoverer) GetProposalData(ctx context.Context, proposal ocr2keepers.CoordinatedBlockProposal) ([]byte, error) { switch core.GetUpkeepType(proposal.UpkeepID) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: return r.getLogTriggerCheckData(ctx, proposal) default: return []byte{}, errors.New("not a log trigger upkeep ID") diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go index 89b19b4a819..eadd0446da8 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider/recoverer_test.go @@ -9,24 +9,26 @@ import ( "testing" "time" + types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestLogRecoverer_GetRecoverables(t *testing.T) { @@ -50,33 +52,33 @@ func TestLogRecoverer_GetRecoverables(t *testing.T) { { "happy flow", []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, false, }, { "rate limiting", []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "3", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "4", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "5", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "6", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "3", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "4", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "5", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "6", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "3", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "4", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "5", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "3", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "4", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "5", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, false, }, @@ -121,9 +123,9 @@ func TestLogRecoverer_Clean(t *testing.T) { { "clean expired", []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, - {WorkID: "3", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "3")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, + {WorkID: "3", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "3")}, }, map[string]visitedRecord{ "1": visitedRecord{time.Now(), ocr2keepers.UpkeepPayload{ @@ -164,9 +166,9 @@ func TestLogRecoverer_Clean(t *testing.T) { ocr2keepers.UnknownState, }, []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, - {WorkID: "4", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "4")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, + {WorkID: "4", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "4")}, }, []string{"1", "2", "4"}, }, @@ -583,7 +585,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a filter is not found for the upkeep ID, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), }, skipFilter: true, expectErr: true, @@ -592,7 +594,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if an error is encountered fetching the latest block, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 0, @@ -615,7 +617,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if an error is encountered fetching the tx receipt, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 0, @@ -643,7 +645,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if the tx block is nil, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 0, @@ -671,7 +673,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log trigger extension block number is 0, and the block number on the tx receipt is not recoverable, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 0, @@ -701,7 +703,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is not recoverable, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 200, @@ -731,7 +733,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block has does not match, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 200, @@ -763,7 +765,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is recoverable, when the upkeep state reader errors, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 80, @@ -798,7 +800,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is recoverable, when the upkeep state reader returns a non recoverable state, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 80, @@ -835,7 +837,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is recoverable, when the filter address is empty, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 80, @@ -875,7 +877,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is recoverable, when the log poller returns an error fetching logs, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 80, @@ -910,7 +912,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "if a log block is recoverable, when logs cannot be found for an upkeep ID, an error is returned", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: ocr2keepers.Trigger{ LogTriggerExtension: &ocr2keepers.LogTriggerExtension{ BlockNumber: 80, @@ -949,7 +951,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "happy path with empty check data", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: func() ocr2keepers.Trigger { t := ocr2keepers.NewTrigger( ocr2keepers.BlockNumber(80), @@ -1000,7 +1002,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { { name: "happy path with check data", proposal: ocr2keepers.CoordinatedBlockProposal{ - UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "123"), Trigger: func() ocr2keepers.Trigger { t := ocr2keepers.NewTrigger( ocr2keepers.BlockNumber(80), @@ -1023,7 +1025,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { LogsWithSigsFn: func(start, end int64, eventSigs []common.Hash, address common.Address, qopts ...pg.QOpt) ([]logpoller.Log, error) { return []logpoller.Log{ { - EvmChainId: utils.NewBig(big.NewInt(1)), + EvmChainId: ubig.New(big.NewInt(1)), LogIndex: 3, BlockHash: [32]byte{1}, BlockNumber: 80, @@ -1061,7 +1063,7 @@ func TestLogRecoverer_GetProposalData(t *testing.T) { filterStore.AddActiveUpkeeps(upkeepFilter{ addr: []byte("test"), topics: []common.Hash{common.HexToHash("0x1"), common.HexToHash("0x2"), common.HexToHash("0x3"), common.HexToHash("0x4")}, - upkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "123").BigInt(), + upkeepID: core.GenUpkeepID(types2.LogTrigger, "123").BigInt(), }) } @@ -1111,34 +1113,34 @@ func TestLogRecoverer_pending(t *testing.T) { name: "add new and existing", maxPerUpkeep: 10, exist: []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, }, new: []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, errored: []bool{false, false}, want: []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "2")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "2")}, }, }, { name: "exceed limits for upkeep", maxPerUpkeep: 3, exist: []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "3", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "3", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, }, new: []ocr2keepers.UpkeepPayload{ - {WorkID: "4", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, + {WorkID: "4", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, }, errored: []bool{true}, want: []ocr2keepers.UpkeepPayload{ - {WorkID: "1", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "2", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, - {WorkID: "3", UpkeepID: core.GenUpkeepID(ocr2keepers.LogTrigger, "1")}, + {WorkID: "1", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "2", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, + {WorkID: "3", UpkeepID: core.GenUpkeepID(types2.LogTrigger, "1")}, }, }, } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go index cf6ebeafc6e..d24442b6ee9 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury.go @@ -10,9 +10,14 @@ import ( "net/http" "time" + "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" ) const ( @@ -65,18 +70,11 @@ type MercuryData struct { Error error Retryable bool Bytes [][]byte - State MercuryUpkeepState -} - -type Packer interface { - UnpackCheckCallbackResult(callbackResp []byte) (uint8, bool, []byte, uint8, *big.Int, error) - PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) - UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) - DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) + State encoding.PipelineExecutionState } type MercuryConfigProvider interface { - Credentials() *models.MercuryCredentials + Credentials() *types.MercuryCredentials IsUpkeepAllowed(string) (interface{}, bool) SetUpkeepAllowed(string, interface{}, time.Duration) GetPluginRetry(string) (interface{}, bool) @@ -88,7 +86,7 @@ type HttpClient interface { } type MercuryClient interface { - DoRequest(ctx context.Context, streamsLookup *StreamsLookup, pluginRetryKey string) (MercuryUpkeepState, MercuryUpkeepFailureReason, [][]byte, bool, time.Duration, error) + DoRequest(ctx context.Context, streamsLookup *StreamsLookup, pluginRetryKey string) (encoding.PipelineExecutionState, encoding.UpkeepFailureReason, [][]byte, bool, time.Duration, error) } type StreamsLookupError struct { @@ -105,10 +103,6 @@ type StreamsLookup struct { Block uint64 } -func (l *StreamsLookup) IsMercuryVersionUnkown() bool { - return l.FeedParamKey != FeedIDs -} - func (l *StreamsLookup) IsMercuryV02() bool { return l.FeedParamKey == FeedIdHex && l.TimeParamKey == BlockNumber } @@ -117,6 +111,70 @@ func (l *StreamsLookup) IsMercuryV03() bool { return l.FeedParamKey == FeedIDs } -func (l *StreamsLookup) IsMercuryUsingBatchPathV03() bool { +// IsMercuryV03UsingBlockNumber is used to distinguish the batch path. It is used for Mercury V03 only +func (l *StreamsLookup) IsMercuryV03UsingBlockNumber() bool { return l.TimeParamKey == BlockNumber } + +type Packer interface { + UnpackCheckCallbackResult(callbackResp []byte) (encoding.PipelineExecutionState, bool, []byte, encoding.UpkeepFailureReason, *big.Int, error) + PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) + UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) + DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) +} + +type abiPacker struct { + registryABI abi.ABI + streamsABI abi.ABI +} + +func NewAbiPacker() *abiPacker { + return &abiPacker{registryABI: core.RegistryABI, streamsABI: core.StreamsCompatibleABI} +} + +// DecodeStreamsLookupRequest decodes the revert error StreamsLookup(string feedParamKey, string[] feeds, string feedParamKey, uint256 time, byte[] extraData) +func (p *abiPacker) DecodeStreamsLookupRequest(data []byte) (*StreamsLookupError, error) { + e := p.streamsABI.Errors["StreamsLookup"] + unpack, err := e.Unpack(data) + if err != nil { + return nil, fmt.Errorf("unpack error: %w", err) + } + errorParameters := unpack.([]interface{}) + + return &StreamsLookupError{ + FeedParamKey: *abi.ConvertType(errorParameters[0], new(string)).(*string), + Feeds: *abi.ConvertType(errorParameters[1], new([]string)).(*[]string), + TimeParamKey: *abi.ConvertType(errorParameters[2], new(string)).(*string), + Time: *abi.ConvertType(errorParameters[3], new(*big.Int)).(**big.Int), + ExtraData: *abi.ConvertType(errorParameters[4], new([]byte)).(*[]byte), + }, nil +} + +func (p *abiPacker) UnpackCheckCallbackResult(callbackResp []byte) (encoding.PipelineExecutionState, bool, []byte, encoding.UpkeepFailureReason, *big.Int, error) { + out, err := p.registryABI.Methods["checkCallback"].Outputs.UnpackValues(callbackResp) + if err != nil { + return encoding.PackUnpackDecodeFailed, false, nil, 0, nil, fmt.Errorf("%w: unpack checkUpkeep return: %s", err, hexutil.Encode(callbackResp)) + } + + upkeepNeeded := *abi.ConvertType(out[0], new(bool)).(*bool) + rawPerformData := *abi.ConvertType(out[1], new([]byte)).(*[]byte) + failureReason := encoding.UpkeepFailureReason(*abi.ConvertType(out[2], new(uint8)).(*uint8)) + gasUsed := *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + + return encoding.NoPipelineError, upkeepNeeded, rawPerformData, failureReason, gasUsed, nil +} + +func (p *abiPacker) UnpackGetUpkeepPrivilegeConfig(resp []byte) ([]byte, error) { + out, err := p.registryABI.Methods["getUpkeepPrivilegeConfig"].Outputs.UnpackValues(resp) + if err != nil { + return nil, fmt.Errorf("%w: unpack getUpkeepPrivilegeConfig return", err) + } + + bts := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return bts, nil +} + +func (p *abiPacker) PackGetUpkeepPrivilegeConfig(upkeepId *big.Int) ([]byte, error) { + return p.registryABI.Pack("getUpkeepPrivilegeConfig", upkeepId) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go index baa939dbecc..ce82ec7ae8f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/mercury_test.go @@ -1,7 +1,17 @@ package mercury import ( + "encoding/json" + "errors" + "math/big" "testing" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" ) func TestGenerateHMACFn(t *testing.T) { @@ -47,3 +57,186 @@ func TestGenerateHMACFn(t *testing.T) { }) } } + +func TestPacker_DecodeStreamsLookupRequest(t *testing.T) { + tests := []struct { + name string + data []byte + expected *StreamsLookupError + state uint8 + err error + }{ + { + name: "success - decode to streams lookup", + data: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000002435eb50000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + expected: &StreamsLookupError{ + FeedParamKey: "feedIdHex", + Feeds: []string{"0x4554482d5553442d415242495452554d2d544553544e45540000000000000000", "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000"}, + TimeParamKey: "blockNumber", + Time: big.NewInt(37969589), + ExtraData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100}, + }, + }, + { + name: "failure - unpack error", + data: []byte{1, 2, 3, 4}, + err: errors.New("unpack error: invalid identifier, have 0x01020304 want 0xf055e4a2"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + packer := NewAbiPacker() + fl, err := packer.DecodeStreamsLookupRequest(tt.data) + assert.Equal(t, tt.expected, fl) + if tt.err != nil { + assert.Equal(t, tt.err.Error(), err.Error()) + } + }) + } +} + +func TestPacker_UnpackGetUpkeepPrivilegeConfig(t *testing.T) { + tests := []struct { + name string + raw []byte + errored bool + }{ + { + name: "happy path", + raw: func() []byte { + b, _ := hexutil.Decode("0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000177b226d657263757279456e61626c6564223a747275657d000000000000000000") + + return b + }(), + errored: false, + }, + { + name: "error empty config", + raw: func() []byte { + b, _ := hexutil.Decode("0x") + + return b + }(), + errored: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + packer := NewAbiPacker() + + b, err := packer.UnpackGetUpkeepPrivilegeConfig(test.raw) + + if !test.errored { + require.NoError(t, err, "should unpack bytes from abi encoded value") + + // the actual struct to unmarshal into is not available to this + // package so basic json encoding is the limit of the following test + var data map[string]interface{} + err = json.Unmarshal(b, &data) + + assert.NoError(t, err, "packed data should unmarshal using json encoding") + assert.Equal(t, []byte(`{"mercuryEnabled":true}`), b) + } else { + assert.NotNil(t, err, "error expected from unpack function") + } + }) + } +} + +func TestPacker_PackGetUpkeepPrivilegeConfig(t *testing.T) { + tests := []struct { + name string + upkeepId *big.Int + raw []byte + errored bool + }{ + { + name: "happy path", + upkeepId: func() *big.Int { + id, _ := new(big.Int).SetString("52236098515066839510538748191966098678939830769967377496848891145101407612976", 10) + + return id + }(), + raw: func() []byte { + b, _ := hexutil.Decode("0x19d97a94737c9583000000000000000000000001ea8ed6d0617dd5b3b87374020efaf030") + + return b + }(), + errored: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + packer := NewAbiPacker() + + b, err := packer.PackGetUpkeepPrivilegeConfig(test.upkeepId) + + if !test.errored { + require.NoError(t, err, "no error expected from packing") + + assert.Equal(t, test.raw, b, "raw bytes for output should match expected") + } else { + assert.NotNil(t, err, "error expected from packing function") + } + }) + } +} + +func TestPacker_UnpackCheckCallbackResult(t *testing.T) { + tests := []struct { + Name string + CallbackResp []byte + UpkeepNeeded bool + PerformData []byte + FailureReason encoding.UpkeepFailureReason + GasUsed *big.Int + ErrorString string + State encoding.PipelineExecutionState + }{ + { + Name: "unpack upkeep needed", + CallbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + UpkeepNeeded: true, + PerformData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + FailureReason: encoding.UpkeepFailureReasonNone, + GasUsed: big.NewInt(11796), + }, + { + Name: "unpack upkeep not needed", + CallbackResp: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + UpkeepNeeded: false, + PerformData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 10, 11, 21, 31, 41, 15, 16, 17, 18, 19, 13, 14, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 120, 111, 101, 122, 90, 54, 44, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + FailureReason: encoding.UpkeepFailureReasonUpkeepNotNeeded, + GasUsed: big.NewInt(13008), + }, + { + Name: "unpack malformed data", + CallbackResp: []byte{0, 0, 0, 23, 4, 163, 66, 91, 228, 102, 200, 84, 144, 233, 218, 44, 168, 192, 191, 253, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + UpkeepNeeded: false, + PerformData: nil, + ErrorString: "abi: improperly encoded boolean value: unpack checkUpkeep return: ", + State: encoding.PackUnpackDecodeFailed, + }, + } + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + packer := NewAbiPacker() + + state, needed, pd, failureReason, gasUsed, err := packer.UnpackCheckCallbackResult(test.CallbackResp) + + if test.ErrorString != "" { + assert.EqualError(t, err, test.ErrorString+hexutil.Encode(test.CallbackResp)) + } else { + assert.Nil(t, err) + } + assert.Equal(t, test.UpkeepNeeded, needed) + assert.Equal(t, test.PerformData, pd) + assert.Equal(t, test.FailureReason, failureReason) + assert.Equal(t, test.GasUsed, gasUsed) + assert.Equal(t, test.State, state) + }) + } +} diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go index aec23431921..db04a066433 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go @@ -15,13 +15,13 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - "github.com/smartcontractkit/chainlink-common/pkg/services" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02" v03 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03" @@ -67,7 +67,6 @@ type UpkeepPrivilegeConfig struct { } func NewStreamsLookup( - packer mercury.Packer, mercuryConfig mercury.MercuryConfigProvider, blockSubscriber latestBlockProvider, client contextCaller, @@ -75,6 +74,8 @@ func NewStreamsLookup( lggr logger.Logger) *streams { httpClient := http.DefaultClient threadCtrl := utils.NewThreadControl() + packer := mercury.NewAbiPacker() + return &streams{ packer: packer, mercuryConfig: mercuryConfig, @@ -114,7 +115,7 @@ func (s *streams) Lookup(ctx context.Context, checkResults []ocr2keepers.CheckRe // buildResult checks if the upkeep is allowed by Mercury and builds a streams lookup request from the check result func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keepers.CheckResult, checkResults []ocr2keepers.CheckResult, lookups map[int]*mercury.StreamsLookup) { lookupLggr := s.lggr.With("where", "StreamsLookup") - if checkResult.IneligibilityReason != uint8(mercury.MercuryUpkeepFailureReasonTargetCheckReverted) { + if checkResult.IneligibilityReason != uint8(encoding.UpkeepFailureReasonTargetCheckReverted) { // Streams Lookup only works when upkeep target check reverts return } @@ -122,11 +123,6 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper block := big.NewInt(int64(checkResult.Trigger.BlockNumber)) upkeepId := checkResult.UpkeepID - if s.mercuryConfig.Credentials() == nil { - lookupLggr.Errorf("at block %d upkeep %s tries to access mercury server but mercury credential is not configured", block, upkeepId) - return - } - // Try to decode the revert error into streams lookup format. User upkeeps can revert with any reason, see if they // tried to call mercury lookupLggr.Infof("at block %d upkeep %s trying to DecodeStreamsLookupRequest performData=%s", block, upkeepId, hexutil.Encode(checkResults[i].PerformData)) @@ -137,14 +133,18 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper return } streamsLookupResponse := &mercury.StreamsLookup{StreamsLookupError: streamsLookupErr} + if s.mercuryConfig.Credentials() == nil { + lookupLggr.Errorf("at block %d upkeep %s tries to access mercury server but mercury credential is not configured", block, upkeepId) + return + } if len(streamsLookupResponse.Feeds) == 0 { - checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) + checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput) lookupLggr.Debugf("at block %s upkeep %s has empty feeds array", block, upkeepId) return } - // mercury permission checking for v0.3 is done by mercury server + // mercury permission checking for v0.3 is done by mercury server, so no need to check here if streamsLookupResponse.IsMercuryV02() { // check permission on the registry for mercury v0.2 opts := s.buildCallOpts(ctx, block) @@ -156,13 +156,13 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper return } else if !allowed { lookupLggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) - checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed) + checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonMercuryAccessNotAllowed) return } - } else if streamsLookupResponse.IsMercuryVersionUnkown() { - // if mercury version cannot be determined, set failure reason + } else if !streamsLookupResponse.IsMercuryV03() { + // if mercury version is not v02 or v03, set failure reason lookupLggr.Debugf("at block %d upkeep %s NOT allowed to query Mercury server", block, upkeepId) - checkResults[i].IneligibilityReason = uint8(mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput) + checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput) return } @@ -177,7 +177,67 @@ func (s *streams) buildResult(ctx context.Context, i int, checkResult ocr2keeper func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *mercury.StreamsLookup, i int, checkResults []ocr2keepers.CheckResult) { defer wg.Done() - state, reason, values, retryable, retryInterval, err := mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0*time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", lookup.FeedParamKey, lookup.TimeParamKey, lookup.Feeds) + values, err := s.DoMercuryRequest(ctx, lookup, checkResults, i) + if err != nil { + s.lggr.Errorf("at block %d upkeep %s requested time %s DoMercuryRequest err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) + } + + if err := s.CheckCallback(ctx, values, lookup, checkResults, i); err != nil { + s.lggr.Errorf("at block %d upkeep %s requested time %s CheckCallback err: %s", lookup.Block, lookup.UpkeepId, lookup.Time, err.Error()) + } +} + +func (s *streams) CheckCallback(ctx context.Context, values [][]byte, lookup *mercury.StreamsLookup, checkResults []ocr2keepers.CheckResult, i int) error { + payload, err := s.abi.Pack("checkCallback", lookup.UpkeepId, values, lookup.ExtraData) + if err != nil { + checkResults[i].Retryable = false + checkResults[i].PipelineExecutionState = uint8(encoding.PackUnpackDecodeFailed) + return err + } + + var mercuryBytes hexutil.Bytes + args := map[string]interface{}{ + "to": s.registry.Address().Hex(), + "data": hexutil.Bytes(payload), + } + + // call checkCallback function at the block which OCR3 has agreed upon + if err = s.client.CallContext(ctx, &mercuryBytes, "eth_call", args, hexutil.EncodeUint64(lookup.Block)); err != nil { + checkResults[i].Retryable = true + checkResults[i].PipelineExecutionState = uint8(encoding.RpcFlakyFailure) + return err + } + + s.lggr.Infof("at block %d upkeep %s requested time %s checkCallback mercuryBytes: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(mercuryBytes)) + + unpackCallBackState, needed, performData, failureReason, _, err := s.packer.UnpackCheckCallbackResult(mercuryBytes) + if err != nil { + checkResults[i].PipelineExecutionState = uint8(unpackCallBackState) + return err + } + + if failureReason == encoding.UpkeepFailureReasonMercuryCallbackReverted { + checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonMercuryCallbackReverted) + s.lggr.Debugf("at block %d upkeep %s requested time %s mercury callback reverts", lookup.Block, lookup.UpkeepId, lookup.Time) + return nil + } + + if !needed { + checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonUpkeepNotNeeded) + s.lggr.Debugf("at block %d upkeep %s requested time %s callback reports upkeep not needed", lookup.Block, lookup.UpkeepId, lookup.Time) + return nil + } + + checkResults[i].IneligibilityReason = uint8(encoding.UpkeepFailureReasonNone) + checkResults[i].Eligible = true + checkResults[i].PerformData = performData + s.lggr.Infof("at block %d upkeep %s requested time %s CheckCallback successful with perform data: %s", lookup.Block, lookup.UpkeepId, lookup.Time, hexutil.Encode(performData)) + + return nil +} + +func (s *streams) DoMercuryRequest(ctx context.Context, lookup *mercury.StreamsLookup, checkResults []ocr2keepers.CheckResult, i int) ([][]byte, error) { + state, reason, values, retryable, retryInterval, err := encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0*time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", lookup.FeedParamKey, lookup.TimeParamKey, lookup.Feeds) pluginRetryKey := generatePluginRetryKey(checkResults[i].WorkID, lookup.Block) if lookup.IsMercuryV02() { @@ -187,12 +247,11 @@ func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *merc } if err != nil { - s.lggr.Errorf("at block %d upkeep %s requested time %s retryable %v retryInterval %s doMercuryRequest: %s", lookup.Block, lookup.UpkeepId, lookup.Time, retryable, retryInterval, err.Error()) checkResults[i].Retryable = retryable checkResults[i].RetryInterval = retryInterval checkResults[i].PipelineExecutionState = uint8(state) checkResults[i].IneligibilityReason = uint8(reason) - return + return nil, err } for j, v := range values { @@ -235,10 +294,10 @@ func (s *streams) doLookup(ctx context.Context, wg *sync.WaitGroup, lookup *merc // allowedToUseMercury retrieves upkeep's administrative offchain config and decode a mercuryEnabled bool to indicate if // this upkeep is allowed to use Mercury service. -func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (state mercury.MercuryUpkeepState, reason mercury.MercuryUpkeepFailureReason, retryable bool, allow bool, err error) { +func (s *streams) AllowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (state encoding.PipelineExecutionState, reason encoding.UpkeepFailureReason, retryable bool, allow bool, err error) { allowed, ok := s.mercuryConfig.IsUpkeepAllowed(upkeepId.String()) if ok { - return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonNone, false, allowed.(bool), nil + return encoding.NoPipelineError, encoding.UpkeepFailureReasonNone, false, allowed.(bool), nil } payload, err := s.packer.PackGetUpkeepPrivilegeConfig(upkeepId) @@ -246,7 +305,7 @@ func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (s // pack error, no retryable s.lggr.Warnf("failed to pack getUpkeepPrivilegeConfig data for upkeepId %s: %s", upkeepId, err) - return mercury.PackUnpackDecodeFailed, mercury.MercuryUpkeepFailureReasonNone, false, false, fmt.Errorf("failed to pack upkeepId: %w", err) + return encoding.PackUnpackDecodeFailed, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to pack upkeepId: %w", err) } var resultBytes hexutil.Bytes @@ -257,28 +316,29 @@ func (s *streams) allowedToUseMercury(opts *bind.CallOpts, upkeepId *big.Int) (s // call checkCallback function at the block which OCR3 has agreed upon if err = s.client.CallContext(opts.Context, &resultBytes, "eth_call", args, hexutil.EncodeBig(opts.BlockNumber)); err != nil { - return mercury.RpcFlakyFailure, mercury.MercuryUpkeepFailureReasonNone, true, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) + return encoding.RpcFlakyFailure, encoding.UpkeepFailureReasonNone, true, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) } var upkeepPrivilegeConfigBytes []byte upkeepPrivilegeConfigBytes, err = s.packer.UnpackGetUpkeepPrivilegeConfig(resultBytes) + if err != nil { - return mercury.PackUnpackDecodeFailed, mercury.MercuryUpkeepFailureReasonNone, false, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) + return encoding.PackUnpackDecodeFailed, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to get upkeep privilege config: %v", err) } if len(upkeepPrivilegeConfigBytes) == 0 { s.mercuryConfig.SetUpkeepAllowed(upkeepId.String(), false, cache.DefaultExpiration) - return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed, false, false, fmt.Errorf("upkeep privilege config is empty") + return encoding.NoPipelineError, encoding.UpkeepFailureReasonMercuryAccessNotAllowed, false, false, fmt.Errorf("upkeep privilege config is empty") } var privilegeConfig UpkeepPrivilegeConfig if err = json.Unmarshal(upkeepPrivilegeConfigBytes, &privilegeConfig); err != nil { - return mercury.MercuryUnmarshalError, mercury.MercuryUpkeepFailureReasonNone, false, false, fmt.Errorf("failed to unmarshal privilege config: %v", err) + return encoding.MercuryUnmarshalError, encoding.UpkeepFailureReasonNone, false, false, fmt.Errorf("failed to unmarshal privilege config: %v", err) } s.mercuryConfig.SetUpkeepAllowed(upkeepId.String(), privilegeConfig.MercuryEnabled, cache.DefaultExpiration) - return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonNone, false, privilegeConfig.MercuryEnabled, nil + return encoding.NoPipelineError, encoding.UpkeepFailureReasonNone, false, privilegeConfig.MercuryEnabled, nil } func (s *streams) checkCallback(ctx context.Context, values [][]byte, lookup *mercury.StreamsLookup) (mercury.MercuryUpkeepState, bool, hexutil.Bytes, error) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go index abcc37dca18..51dd70bbe54 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams_test.go @@ -11,21 +11,23 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/pkg/errors" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" v02 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02" @@ -36,8 +38,8 @@ type MockMercuryConfigProvider struct { mock.Mock } -func (m *MockMercuryConfigProvider) Credentials() *models.MercuryCredentials { - mc := &models.MercuryCredentials{ +func (m *MockMercuryConfigProvider) Credentials() *types.MercuryCredentials { + mc := &types.MercuryCredentials{ LegacyURL: "https://google.old.com", URL: "https://google.com", Username: "FakeClientID", @@ -101,14 +103,12 @@ func (r *mockRegistry) CheckCallback(opts *bind.CallOpts, id *big.Int, values [] // setups up a streams object for tests. func setupStreams(t *testing.T) *streams { lggr := logger.TestLogger(t) - packer := encoding.NewAbiPacker() mercuryConfig := new(MockMercuryConfigProvider) blockSubscriber := new(MockBlockSubscriber) registry := &mockRegistry{} client := evmClientMocks.NewClient(t) streams := NewStreamsLookup( - packer, mercuryConfig, blockSubscriber, client, @@ -136,7 +136,7 @@ func TestStreams_CheckCallback(t *testing.T) { performData []byte wantErr assert.ErrorAssertionFunc - state mercury.MercuryUpkeepState + state encoding.PipelineExecutionState retryable bool registry streamsRegistry }{ @@ -221,7 +221,7 @@ func TestStreams_CheckCallback(t *testing.T) { callbackResp: []byte{}, callbackErr: errors.New("bad response"), wantErr: assert.Error, - state: mercury.RpcFlakyFailure, + state: encoding.RpcFlakyFailure, retryable: true, registry: &mockRegistry{ GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { @@ -255,10 +255,10 @@ func TestStreams_CheckCallback(t *testing.T) { }).Once() s.client = client - state, retryable, _, err := s.checkCallback(testutils.Context(t), tt.values, tt.lookup) - tt.wantErr(t, err, fmt.Sprintf("Error asserion failed: %v", tt.name)) - assert.Equal(t, tt.state, state) - assert.Equal(t, tt.retryable, retryable) + err = s.CheckCallback(testutils.Context(t), tt.values, tt.lookup, tt.input, 0) + tt.wantErr(t, err, fmt.Sprintf("Error assertion failed: %v", tt.name)) + assert.Equal(t, uint8(tt.state), tt.input[0].PipelineExecutionState) + assert.Equal(t, tt.retryable, tt.input[0].Retryable) }) } } @@ -272,8 +272,8 @@ func TestStreams_AllowedToUseMercury(t *testing.T) { allowed bool ethCallErr error err error - state mercury.MercuryUpkeepState - reason mercury.MercuryUpkeepFailureReason + state encoding.PipelineExecutionState + reason encoding.UpkeepFailureReason registry streamsRegistry retryable bool config []byte @@ -331,7 +331,7 @@ func TestStreams_AllowedToUseMercury(t *testing.T) { { name: "failure - cannot unmarshal privilege config", err: fmt.Errorf("failed to unmarshal privilege config: invalid character '\\x00' looking for beginning of value"), - state: mercury.MercuryUnmarshalError, + state: encoding.MercuryUnmarshalError, config: []byte{0, 1}, registry: &mockRegistry{ GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { @@ -346,7 +346,7 @@ func TestStreams_AllowedToUseMercury(t *testing.T) { name: "failure - flaky RPC", retryable: true, err: fmt.Errorf("failed to get upkeep privilege config: flaky RPC"), - state: mercury.RpcFlakyFailure, + state: encoding.RpcFlakyFailure, ethCallErr: fmt.Errorf("flaky RPC"), registry: &mockRegistry{ GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { @@ -360,7 +360,7 @@ func TestStreams_AllowedToUseMercury(t *testing.T) { { name: "failure - empty upkeep privilege config", err: fmt.Errorf("upkeep privilege config is empty"), - reason: mercury.MercuryUpkeepFailureReasonMercuryAccessNotAllowed, + reason: encoding.UpkeepFailureReasonMercuryAccessNotAllowed, config: []byte{}, registry: &mockRegistry{ GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { @@ -475,7 +475,7 @@ func TestStreams_StreamsLookup(t *testing.T) { Trigger: ocr2keepers.Trigger{ BlockNumber: blockNum, }, - IneligibilityReason: uint8(mercury.MercuryUpkeepFailureReasonTargetCheckReverted), + IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), }, }, blobs: map[string]string{ @@ -512,6 +512,69 @@ func TestStreams_StreamsLookup(t *testing.T) { }, }, }, + { + name: "two CheckResults: Mercury success E2E and No Mercury because of insufficient balance", + input: []ocr2keepers.CheckResult{ + { + PerformData: []byte{}, + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: 26046145, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonInsufficientBalance), + }, + { + PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000000966656564496448657800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000423078343535343438326435353533343432643431353234323439353435323535346432643534343535333534346534353534303030303030303030303030303030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000042307834323534343332643535353334343264343135323432343935343532353534643264353434353533353434653435353430303030303030303030303030303030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), + }, + }, + blobs: map[string]string{ + "0x4554482d5553442d415242495452554d2d544553544e45540000000000000000": "0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3", + "0x4254432d5553442d415242495452554d2d544553544e45540000000000000000": "0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d", + }, + cachedAdminCfg: false, + extraData: hexutil.MustDecode("0x0000000000000000000000000000000000000064"), + callbackNeeded: true, + checkCallbackResp: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063a400000000000000000000000000000000000000000000000000000000000006e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + values: [][]byte{hexutil.MustDecode("0x00066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa3"), hexutil.MustDecode("0x0006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d")}, + expectedResults: []ocr2keepers.CheckResult{ + { + Eligible: false, + PerformData: []byte{}, + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: 26046145, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonInsufficientBalance), + }, + { + Eligible: true, + PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonNone), + }, + }, + hasPermission: true, + v3: false, + registry: &mockRegistry{ + GetUpkeepPrivilegeConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { + return []byte(`{"mercuryEnabled":true}`), nil + }, + CheckCallbackFn: func(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (iregistry21.CheckCallback, error) { + return iregistry21.CheckCallback{ + UpkeepNeeded: true, + PerformData: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000002e000066dfcd1ed2d95b18c948dbc5bd64c687afe93e4ca7d663ddec14c20090ad80000000000000000000000000000000000000000000000000000000004555638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204554482d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000000269ecbb83b000000000000000000000000000000000000000000000000000000269e4a4e14000000000000000000000000000000000000000000000000000000269f4d0edb000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002381e91cffa9502c20de1ddcee350db3f715a5ab449448e3184a5b03c682356c6e2115f20663b3731e373cf33465a96da26f2876debb548f281e62e48f64c374200000000000000000000000000000000000000000000000000000000000000027db99e34135098d4e0bb9ae143ec9cd72fd63150c6d0cc5b38f4aa1aa42408377e8fe8e5ac489c9b7f62ff5aa7b05d2e892e7dee4cac631097247969b3b03fa300000000000000000000000000000000000000000000000000000000000002e00006da4a86c4933dd4a87b21dd2871aea29f706bcde43c70039355ac5b664fb5000000000000000000000000000000000000000000000000000000000454d118000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000280000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001204254432d5553442d415242495452554d2d544553544e455400000000000000000000000000000000000000000000000000000000000000000000000064f0d4a0000000000000000000000000000000000000000000000000000002645f00877a000000000000000000000000000000000000000000000000000002645e1e1010000000000000000000000000000000000000000000000000000002645fe2fee4000000000000000000000000000000000000000000000000000000000243716664b42d20423a47fb13ad3098b49b37f667548e6745fff958b663afe25a845f6100000000000000000000000000000000000000000000000000000000024371660000000000000000000000000000000000000000000000000000000064f0d4a00000000000000000000000000000000000000000000000000000000000000002a0373c0bce7393673f819eb9681cac2773c2d718ce933eb858252195b17a9c832d7b0bee173c02c3c25fb65912b8b13b9302ede8423bab3544cb7a8928d5eb3600000000000000000000000000000000000000000000000000000000000000027d7b79d7646383a5dbf51edf14d53bd3ad0a9f3ca8affab3165e89d3ddce9cb17b58e892fafe4ecb24d2fde07c6a756029e752a5114c33c173df4e7d309adb4d00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000064000000000000000000000000"), + }, nil + }, + }, + }, { name: "success - happy path no cache - v0.3", input: []ocr2keepers.CheckResult{ @@ -619,6 +682,31 @@ func TestStreams_StreamsLookup(t *testing.T) { }, hasError: true, }, + { + name: "failure - invalid mercury version", + input: []ocr2keepers.CheckResult{ + { + // This Perform data contains invalid FeedParamKey: {feedIdHex:RandomString [ETD-USD BTC-ETH] blockNumber 100 [48 120 48 48]} + PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000166665656449644865783a52616e646f6d537472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000074554442d5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000074254432d45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043078303000000000000000000000000000000000000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonTargetCheckReverted), + }, + }, + expectedResults: []ocr2keepers.CheckResult{ + { + PerformData: hexutil.MustDecode("0xf055e4a200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000166665656449644865783a52616e646f6d537472696e670000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000074554442d5553440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000074254432d45544800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b626c6f636b4e756d62657200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043078303000000000000000000000000000000000000000000000000000000000"), + UpkeepID: upkeepIdentifier, + Trigger: ocr2keepers.Trigger{ + BlockNumber: blockNum, + }, + IneligibilityReason: uint8(encoding.UpkeepFailureReasonInvalidRevertDataInput), + }, + }, + hasError: true, + }, } for _, tt := range tests { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_failure_reasons.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_failure_reasons.go deleted file mode 100644 index 66f8bca402f..00000000000 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_failure_reasons.go +++ /dev/null @@ -1,17 +0,0 @@ -package mercury - -type MercuryUpkeepFailureReason uint8 - -// NOTE: This enum should be kept in sync with evmregistry/v21/encoding/interface.go -// TODO (AUTO-7928) Remove this duplication -const ( - // upkeep failure onchain reasons - MercuryUpkeepFailureReasonNone MercuryUpkeepFailureReason = 0 - MercuryUpkeepFailureReasonTargetCheckReverted MercuryUpkeepFailureReason = 3 - MercuryUpkeepFailureReasonUpkeepNotNeeded MercuryUpkeepFailureReason = 4 - MercuryUpkeepFailureReasonMercuryCallbackReverted MercuryUpkeepFailureReason = 7 - // leaving a gap here for more onchain failure reasons in the future - // upkeep failure offchain reasons - MercuryUpkeepFailureReasonMercuryAccessNotAllowed MercuryUpkeepFailureReason = 32 - MercuryUpkeepFailureReasonInvalidRevertDataInput MercuryUpkeepFailureReason = 34 -) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_states.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_states.go deleted file mode 100644 index 0d8276ff2de..00000000000 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/upkeep_states.go +++ /dev/null @@ -1,16 +0,0 @@ -package mercury - -type MercuryUpkeepState uint8 - -// NOTE: This enum should be kept in sync with evmregistry/v21/encoding/interface.go -// TODO (AUTO-7928) Remove this duplication -const ( - NoPipelineError MercuryUpkeepState = 0 - RpcFlakyFailure MercuryUpkeepState = 3 - MercuryFlakyFailure MercuryUpkeepState = 4 - PackUnpackDecodeFailed MercuryUpkeepState = 5 - MercuryUnmarshalError MercuryUpkeepState = 6 - InvalidMercuryRequest MercuryUpkeepState = 7 - InvalidMercuryResponse MercuryUpkeepState = 8 // this will only happen if Mercury server sends bad responses - UpkeepNotAuthorized MercuryUpkeepState = 9 -) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go index 8135617b6fd..202661145bf 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v02/request.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -52,11 +53,11 @@ func NewClient(mercuryConfig mercury.MercuryConfigProvider, httpClient mercury.H } } -func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLookup, pluginRetryKey string) (mercury.MercuryUpkeepState, mercury.MercuryUpkeepFailureReason, [][]byte, bool, time.Duration, error) { +func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLookup, pluginRetryKey string) (encoding.PipelineExecutionState, encoding.UpkeepFailureReason, [][]byte, bool, time.Duration, error) { resultLen := len(streamsLookup.Feeds) ch := make(chan mercury.MercuryData, resultLen) if len(streamsLookup.Feeds) == 0 { - return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", streamsLookup.FeedParamKey, streamsLookup.TimeParamKey, streamsLookup.Feeds) + return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", streamsLookup.FeedParamKey, streamsLookup.TimeParamKey, streamsLookup.Feeds) } for i := range streamsLookup.Feeds { // TODO (AUTO-7209): limit the number of concurrent requests @@ -72,15 +73,15 @@ func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLo retryable := true allSuccess := true // in v0.2, use the last execution error as the state, if no execution errors, state will be no error - state := mercury.NoPipelineError + state := encoding.NoPipelineError for i := 0; i < resultLen; i++ { m := <-ch if m.Error != nil { reqErr = errors.Join(reqErr, m.Error) retryable = retryable && m.Retryable allSuccess = false - if m.State != mercury.NoPipelineError { - state = mercury.MercuryUpkeepState(m.State) + if m.State != encoding.NoPipelineError { + state = m.State } continue } @@ -90,7 +91,7 @@ func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLo retryInterval = mercury.CalculateRetryConfigFn(pluginRetryKey, c.mercuryConfig) } // only retry when not all successful AND none are not retryable - return state, mercury.MercuryUpkeepFailureReasonNone, results, retryable && !allSuccess, retryInterval, reqErr + return state, encoding.UpkeepFailureReasonNone, results, retryable && !allSuccess, retryInterval, reqErr } func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.MercuryData, index int, sl *mercury.StreamsLookup) { @@ -107,7 +108,7 @@ func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.Mercur httpRequest, err = http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) if err != nil { - ch <- mercury.MercuryData{Index: index, Error: err, Retryable: false, State: mercury.InvalidMercuryRequest} + ch <- mercury.MercuryData{Index: index, Error: err, Retryable: false, State: encoding.InvalidMercuryRequest} return } @@ -119,7 +120,7 @@ func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.Mercur httpRequest.Header.Set(signatureHeader, signature) // in the case of multiple retries here, use the last attempt's data - state := mercury.NoPipelineError + state := encoding.NoPipelineError retryable := false sent := false retryErr := retry.Do( @@ -132,13 +133,13 @@ func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.Mercur if httpResponse, err = c.httpClient.Do(httpRequest); err != nil { c.lggr.Warnf("at block %s upkeep %s GET request fails for feed %s: %v", sl.Time.String(), sl.UpkeepId.String(), sl.Feeds[index], err) retryable = true - state = mercury.MercuryFlakyFailure + state = encoding.MercuryFlakyFailure return err } defer httpResponse.Body.Close() if responseBody, err = io.ReadAll(httpResponse.Body); err != nil { - state = mercury.InvalidMercuryResponse + state = encoding.InvalidMercuryResponse return err } @@ -146,12 +147,12 @@ func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.Mercur case http.StatusNotFound, http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: c.lggr.Warnf("at block %s upkeep %s received status code %d for feed %s", sl.Time.String(), sl.UpkeepId.String(), httpResponse.StatusCode, sl.Feeds[index]) retryable = true - state = mercury.MercuryFlakyFailure + state = encoding.MercuryFlakyFailure return errors.New(strconv.FormatInt(int64(httpResponse.StatusCode), 10)) case http.StatusOK: // continue default: - state = mercury.InvalidMercuryRequest + state = encoding.InvalidMercuryRequest return fmt.Errorf("at block %s upkeep %s received status code %d for feed %s", sl.Time.String(), sl.UpkeepId.String(), httpResponse.StatusCode, sl.Feeds[index]) } @@ -160,19 +161,19 @@ func (c *client) singleFeedRequest(ctx context.Context, ch chan<- mercury.Mercur var m MercuryV02Response if err = json.Unmarshal(responseBody, &m); err != nil { c.lggr.Warnf("at block %s upkeep %s failed to unmarshal body to MercuryV02Response for feed %s: %v", sl.Time.String(), sl.UpkeepId.String(), sl.Feeds[index], err) - state = mercury.MercuryUnmarshalError + state = encoding.MercuryUnmarshalError return err } if blobBytes, err = hexutil.Decode(m.ChainlinkBlob); err != nil { c.lggr.Warnf("at block %s upkeep %s failed to decode chainlinkBlob %s for feed %s: %v", sl.Time.String(), sl.UpkeepId.String(), m.ChainlinkBlob, sl.Feeds[index], err) - state = mercury.InvalidMercuryResponse + state = encoding.InvalidMercuryResponse return err } ch <- mercury.MercuryData{ Index: index, Bytes: [][]byte{blobBytes}, Retryable: false, - State: mercury.NoPipelineError, + State: encoding.NoPipelineError, } sent = true return nil 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 ac945859d89..6c07c383504 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 @@ -11,13 +11,15 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -40,8 +42,8 @@ func NewMockMercuryConfigProvider() *MockMercuryConfigProvider { } } -func (m *MockMercuryConfigProvider) Credentials() *models.MercuryCredentials { - mc := &models.MercuryCredentials{ +func (m *MockMercuryConfigProvider) Credentials() *types.MercuryCredentials { + mc := &types.MercuryCredentials{ LegacyURL: "https://google.old.com", URL: "https://google.com", Username: "FakeClientID", @@ -289,8 +291,8 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { expectedRetryable bool expectedRetryInterval time.Duration expectedError error - state mercury.MercuryUpkeepState - reason mercury.MercuryUpkeepFailureReason + state encoding.PipelineExecutionState + reason encoding.UpkeepFailureReason }{ { name: "success", @@ -329,7 +331,7 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { pluginRetries: 0, expectedRetryInterval: 1 * time.Second, expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), - state: mercury.MercuryFlakyFailure, + state: encoding.MercuryFlakyFailure, }, { name: "failure - retryable and interval is 5s", @@ -350,7 +352,7 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { expectedRetryable: true, expectedRetryInterval: 5 * time.Second, expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), - state: mercury.MercuryFlakyFailure, + state: encoding.MercuryFlakyFailure, }, { name: "failure - not retryable because there are many plugin retries already", @@ -370,7 +372,7 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { expectedValues: [][]byte{nil}, expectedRetryable: true, expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: 500\n#2: 500\n#3: 500"), - state: mercury.MercuryFlakyFailure, + state: encoding.MercuryFlakyFailure, }, { name: "failure - not retryable", @@ -389,7 +391,7 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { expectedValues: [][]byte{nil}, expectedRetryable: false, expectedError: errors.New("failed to request feed for 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000: All attempts fail:\n#1: at block 25880526 upkeep 88786950015966611018675766524283132478093844178961698330929478019253453382042 received status code 429 for feed 0x4554482d5553442d415242495452554d2d544553544e45540000000000000000"), - state: mercury.InvalidMercuryRequest, + state: encoding.InvalidMercuryRequest, }, { name: "failure - no feeds", @@ -404,7 +406,7 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { UpkeepId: upkeepId, }, expectedValues: [][]byte{}, - reason: mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, + reason: encoding.UpkeepFailureReasonInvalidRevertDataInput, }, { name: "failure - invalid revert data", @@ -419,7 +421,7 @@ func TestV02_DoMercuryRequestV02(t *testing.T) { UpkeepId: upkeepId, }, expectedValues: [][]byte{}, - reason: mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, + reason: encoding.UpkeepFailureReasonInvalidRevertDataInput, }, } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go index cb3c9ef3222..584069adde3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/v03/request.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -60,9 +61,9 @@ func NewClient(mercuryConfig mercury.MercuryConfigProvider, httpClient mercury.H } } -func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLookup, pluginRetryKey string) (mercury.MercuryUpkeepState, mercury.MercuryUpkeepFailureReason, [][]byte, bool, time.Duration, error) { +func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLookup, pluginRetryKey string) (encoding.PipelineExecutionState, encoding.UpkeepFailureReason, [][]byte, bool, time.Duration, error) { if len(streamsLookup.Feeds) == 0 { - return mercury.NoPipelineError, mercury.MercuryUpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", streamsLookup.FeedParamKey, streamsLookup.TimeParamKey, streamsLookup.Feeds) + return encoding.NoPipelineError, encoding.UpkeepFailureReasonInvalidRevertDataInput, [][]byte{}, false, 0 * time.Second, fmt.Errorf("invalid revert data input: feed param key %s, time param key %s, feeds %s", streamsLookup.FeedParamKey, streamsLookup.TimeParamKey, streamsLookup.Feeds) } resultLen := 1 // Only 1 multi-feed request is made for all feeds ch := make(chan mercury.MercuryData, resultLen) @@ -74,7 +75,7 @@ func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLo var retryInterval time.Duration results := make([][]byte, len(streamsLookup.Feeds)) retryable := false - state := mercury.NoPipelineError + state := encoding.NoPipelineError m := <-ch if m.Error != nil { @@ -88,7 +89,7 @@ func (c *client) DoRequest(ctx context.Context, streamsLookup *mercury.StreamsLo results = m.Bytes } - return state, mercury.MercuryUpkeepFailureReasonNone, results, retryable, retryInterval, reqErr + return state, encoding.UpkeepFailureReasonNone, results, retryable, retryInterval, reqErr } func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.MercuryData, sl *mercury.StreamsLookup) { @@ -100,7 +101,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur params := fmt.Sprintf("%s=%s&%s=%s", mercury.FeedIDs, strings.Join(sl.Feeds, ","), mercury.Timestamp, sl.Time.String()) batchPathV03 := mercuryBatchPathV03 - if sl.IsMercuryUsingBatchPathV03() { + if sl.IsMercuryV03UsingBlockNumber() { batchPathV03 = mercuryBatchPathV03BlockNumber } reqUrl := fmt.Sprintf("%s%s%s", c.mercuryConfig.Credentials().URL, batchPathV03, params) @@ -109,7 +110,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqUrl, nil) if err != nil { - ch <- mercury.MercuryData{Index: 0, Error: err, Retryable: false, State: mercury.InvalidMercuryRequest} + ch <- mercury.MercuryData{Index: 0, Error: err, Retryable: false, State: encoding.InvalidMercuryRequest} return } @@ -126,7 +127,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur req.Header.Set(upkeepIDHeader, sl.UpkeepId.String()) // in the case of multiple retries here, use the last attempt's data - state := mercury.NoPipelineError + state := encoding.NoPipelineError retryable := false sent := false retryErr := retry.Do( @@ -136,7 +137,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur if err != nil { c.lggr.Warnf("at timestamp %s upkeep %s GET request fails from mercury v0.3: %v", sl.Time.String(), sl.UpkeepId.String(), err) retryable = true - state = mercury.MercuryFlakyFailure + state = encoding.MercuryFlakyFailure return err } defer resp.Body.Close() @@ -144,7 +145,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur body, err := io.ReadAll(resp.Body) if err != nil { retryable = false - state = mercury.InvalidMercuryResponse + state = encoding.InvalidMercuryResponse return err } @@ -152,27 +153,27 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur switch resp.StatusCode { case http.StatusUnauthorized: retryable = false - state = mercury.UpkeepNotAuthorized + state = encoding.UpkeepNotAuthorized return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by unauthorized upkeep", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) case http.StatusBadRequest: retryable = false - state = mercury.InvalidMercuryRequest + state = encoding.InvalidMercuryRequest return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3, most likely this is caused by invalid format of timestamp", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) case http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: retryable = true - state = mercury.MercuryFlakyFailure + state = encoding.MercuryFlakyFailure return fmt.Errorf("%d", resp.StatusCode) case http.StatusPartialContent: // TODO (AUTO-5044): handle response code 206 entirely with errors field parsing c.lggr.Warnf("at timestamp %s upkeep %s requested [%s] feeds but mercury v0.3 server returned 206 status, treating it as 404 and retrying", sl.Time.String(), sl.UpkeepId.String(), sl.Feeds) retryable = true - state = mercury.MercuryFlakyFailure + state = encoding.MercuryFlakyFailure return fmt.Errorf("%d", http.StatusPartialContent) case http.StatusOK: // continue default: retryable = false - state = mercury.InvalidMercuryRequest + state = encoding.InvalidMercuryRequest return fmt.Errorf("at timestamp %s upkeep %s received status code %d from mercury v0.3", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode) } c.lggr.Debugf("at block %s upkeep %s received status code %d from mercury v0.3 with BODY=%s", sl.Time.String(), sl.UpkeepId.String(), resp.StatusCode, hexutil.Encode(body)) @@ -181,7 +182,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur if err := json.Unmarshal(body, &response); err != nil { c.lggr.Warnf("at timestamp %s upkeep %s failed to unmarshal body to MercuryV03Response from mercury v0.3: %v", sl.Time.String(), sl.UpkeepId.String(), err) retryable = false - state = mercury.MercuryUnmarshalError + state = encoding.MercuryUnmarshalError return err } @@ -194,7 +195,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur } c.lggr.Warnf("at timestamp %s upkeep %s mercury v0.3 server returned 206 status with [%s] reports while we requested [%s] feeds, retrying", sl.Time.String(), sl.UpkeepId.String(), receivedFeeds, sl.Feeds) retryable = true - state = mercury.MercuryFlakyFailure + state = encoding.MercuryFlakyFailure return fmt.Errorf("%d", http.StatusNotFound) } var reportBytes [][]byte @@ -203,7 +204,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur if err != nil { c.lggr.Warnf("at timestamp %s upkeep %s failed to decode reportBlob %s: %v", sl.Time.String(), sl.UpkeepId.String(), rsp.FullReport, err) retryable = false - state = mercury.InvalidMercuryResponse + state = encoding.InvalidMercuryResponse return err } reportBytes = append(reportBytes, b) @@ -212,7 +213,7 @@ func (c *client) multiFeedsRequest(ctx context.Context, ch chan<- mercury.Mercur Index: 0, Bytes: reportBytes, Retryable: false, - State: mercury.NoPipelineError, + State: encoding.NoPipelineError, } sent = true return nil 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 16ccdac5d1f..a7742c04872 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 @@ -9,13 +9,15 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/patrickmn/go-cache" "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -39,8 +41,8 @@ func NewMockMercuryConfigProvider() *MockMercuryConfigProvider { } } -func (m *MockMercuryConfigProvider) Credentials() *models.MercuryCredentials { - mc := &models.MercuryCredentials{ +func (m *MockMercuryConfigProvider) Credentials() *types.MercuryCredentials { + mc := &types.MercuryCredentials{ LegacyURL: "https://google.old.com", URL: "https://google.com", Username: "FakeClientID", @@ -108,8 +110,8 @@ func TestV03_DoMercuryRequestV03(t *testing.T) { expectedRetryable bool expectedRetryInterval time.Duration expectedError error - state mercury.MercuryUpkeepState - reason mercury.MercuryUpkeepFailureReason + state encoding.PipelineExecutionState + reason encoding.UpkeepFailureReason }{ { name: "success v0.3", 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 53d347b1c06..d6982e9dbdb 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type HttpClient struct { func (_m *HttpClient) Do(req *http.Request) (*http.Response, error) { ret := _m.Called(req) + if len(ret) == 0 { + panic("no return value specified for Do") + } + var r0 *http.Response var r1 error if rf, ok := ret.Get(0).(func(*http.Request) (*http.Response, error)); ok { 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 a3cbd772b1d..1bb4cb2a325 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -25,6 +25,10 @@ type Registry struct { func (_m *Registry) CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]byte, extraData []byte) (i_keeper_registry_master_wrapper_2_1.CheckCallback, error) { ret := _m.Called(opts, id, values, extraData) + if len(ret) == 0 { + panic("no return value specified for CheckCallback") + } + var r0 i_keeper_registry_master_wrapper_2_1.CheckCallback var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, [][]byte, []byte) (i_keeper_registry_master_wrapper_2_1.CheckCallback, error)); ok { @@ -49,6 +53,10 @@ func (_m *Registry) CheckCallback(opts *bind.CallOpts, id *big.Int, values [][]b func (_m *Registry) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, maxCount *big.Int) ([]*big.Int, error) { ret := _m.Called(opts, startIndex, maxCount) + if len(ret) == 0 { + panic("no return value specified for GetActiveUpkeepIDs") + } + var r0 []*big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, *big.Int) ([]*big.Int, error)); ok { @@ -75,6 +83,10 @@ func (_m *Registry) GetActiveUpkeepIDs(opts *bind.CallOpts, startIndex *big.Int, func (_m *Registry) GetState(opts *bind.CallOpts) (i_keeper_registry_master_wrapper_2_1.GetState, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetState") + } + var r0 i_keeper_registry_master_wrapper_2_1.GetState var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (i_keeper_registry_master_wrapper_2_1.GetState, error)); ok { @@ -99,6 +111,10 @@ func (_m *Registry) GetState(opts *bind.CallOpts) (i_keeper_registry_master_wrap func (_m *Registry) GetUpkeep(opts *bind.CallOpts, id *big.Int) (i_keeper_registry_master_wrapper_2_1.KeeperRegistryBase21UpkeepInfo, error) { ret := _m.Called(opts, id) + if len(ret) == 0 { + panic("no return value specified for GetUpkeep") + } + var r0 i_keeper_registry_master_wrapper_2_1.KeeperRegistryBase21UpkeepInfo var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (i_keeper_registry_master_wrapper_2_1.KeeperRegistryBase21UpkeepInfo, error)); ok { @@ -123,6 +139,10 @@ func (_m *Registry) GetUpkeep(opts *bind.CallOpts, id *big.Int) (i_keeper_regist func (_m *Registry) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { ret := _m.Called(opts, upkeepId) + if len(ret) == 0 { + panic("no return value specified for GetUpkeepPrivilegeConfig") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) ([]byte, error)); ok { @@ -149,6 +169,10 @@ func (_m *Registry) GetUpkeepPrivilegeConfig(opts *bind.CallOpts, upkeepId *big. func (_m *Registry) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { ret := _m.Called(opts, upkeepId) + if len(ret) == 0 { + panic("no return value specified for GetUpkeepTriggerConfig") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) ([]byte, error)); ok { @@ -175,6 +199,10 @@ func (_m *Registry) GetUpkeepTriggerConfig(opts *bind.CallOpts, upkeepId *big.In func (_m *Registry) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go index 37c458ae6eb..4854f517c46 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder.go @@ -3,7 +3,9 @@ package evm import ( "context" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" @@ -36,13 +38,13 @@ func (b *payloadBuilder) BuildPayloads(ctx context.Context, proposals ...ocr2kee var checkData []byte var err error switch core.GetUpkeepType(proposal.UpkeepID) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: checkData, err = b.recoverer.GetProposalData(ctx, proposal) if err != nil { b.lggr.Warnw("failed to get log proposal data", "err", err, "upkeepID", proposal.UpkeepID, "trigger", proposal.Trigger) continue } - case ocr2keepers.ConditionTrigger: + case types.ConditionTrigger: // Empty checkData for conditionals } payload, err = core.NewUpkeepPayload(proposal.UpkeepID.BigInt(), proposal.Trigger, checkData) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go index 7e55267f6d3..7cd63dd308a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/payload_builder_test.go @@ -5,10 +5,12 @@ import ( "math/big" "testing" + types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" - "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + types "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -33,7 +35,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, proposals: []types.CoordinatedBlockProposal{ { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "abc"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "abc"), WorkID: "workID1", Trigger: types.Trigger{ BlockNumber: 1, @@ -41,7 +43,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, }, { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "def"), WorkID: "workID2", Trigger: types.Trigger{ BlockNumber: 2, @@ -56,7 +58,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, wantPayloads: []types.UpkeepPayload{ { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "abc"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "abc"), WorkID: "714f83255c5b562823725748c4a75777c9b78ea8c5ba72ea819926a1fecd389e", Trigger: types.Trigger{ BlockNumber: 1, @@ -65,7 +67,7 @@ func TestNewPayloadBuilder(t *testing.T) { CheckData: []byte{1, 2, 3}, }, { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "def"), WorkID: "3956daa0378d6a761fe972ee00fe98338f17fb6b7865c1d49a8a416cd85977b8", Trigger: types.Trigger{ BlockNumber: 2, @@ -79,12 +81,12 @@ func TestNewPayloadBuilder(t *testing.T) { name: "for an inactive log trigger upkeep, an empty payload is added to the list of payloads", activeList: &mockActiveUpkeepList{ IsActiveFn: func(id *big.Int) bool { - return core.GenUpkeepID(types.LogTrigger, "ghi").BigInt().Cmp(id) != 0 + return core.GenUpkeepID(types2.LogTrigger, "ghi").BigInt().Cmp(id) != 0 }, }, proposals: []types.CoordinatedBlockProposal{ { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "abc"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "abc"), WorkID: "workID1", Trigger: types.Trigger{ BlockNumber: 1, @@ -92,7 +94,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, }, { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "def"), WorkID: "workID2", Trigger: types.Trigger{ BlockNumber: 2, @@ -100,7 +102,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, }, { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "ghi"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "ghi"), WorkID: "workID3", Trigger: types.Trigger{ BlockNumber: 3, @@ -115,7 +117,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, wantPayloads: []types.UpkeepPayload{ { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "abc"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "abc"), WorkID: "714f83255c5b562823725748c4a75777c9b78ea8c5ba72ea819926a1fecd389e", Trigger: types.Trigger{ BlockNumber: 1, @@ -124,7 +126,7 @@ func TestNewPayloadBuilder(t *testing.T) { CheckData: []byte{1, 2, 3}, }, { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "def"), WorkID: "3956daa0378d6a761fe972ee00fe98338f17fb6b7865c1d49a8a416cd85977b8", Trigger: types.Trigger{ BlockNumber: 2, @@ -144,7 +146,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, proposals: []types.CoordinatedBlockProposal{ { - UpkeepID: core.GenUpkeepID(types.LogTrigger, "abc"), + UpkeepID: core.GenUpkeepID(types2.LogTrigger, "abc"), WorkID: "workID1", Trigger: types.Trigger{ BlockNumber: 1, @@ -170,7 +172,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, proposals: []types.CoordinatedBlockProposal{ { - UpkeepID: core.GenUpkeepID(types.ConditionTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.ConditionTrigger, "def"), WorkID: "workID1", Trigger: types.Trigger{ BlockNumber: 1, @@ -180,7 +182,7 @@ func TestNewPayloadBuilder(t *testing.T) { }, wantPayloads: []types.UpkeepPayload{ { - UpkeepID: core.GenUpkeepID(types.ConditionTrigger, "def"), + UpkeepID: core.GenUpkeepID(types2.ConditionTrigger, "def"), WorkID: "58f2f231792448679a75bac6efc2af4ba731901f0cb93a44a366525751cbabfb", Trigger: types.Trigger{ BlockNumber: 1, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go index bb05b8029fe..fd7bfa91d7f 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry.go @@ -9,6 +9,10 @@ import ( "sync" "time" + types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -19,7 +23,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -27,7 +31,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" @@ -81,7 +84,7 @@ func NewEvmRegistry( addr common.Address, client legacyevm.Chain, registry *iregistry21.IKeeperRegistryMaster, - mc *models.MercuryCredentials, + mc *types.MercuryCredentials, al ActiveUpkeepList, logEventProvider logprovider.LogEventProvider, packer encoding.Packer, @@ -94,7 +97,6 @@ func NewEvmRegistry( AllowListCache: cache.New(defaultAllowListExpiration, cleanupInterval), pluginRetryCache: cache.New(defaultPluginRetryExpiration, cleanupInterval), } - hc := http.DefaultClient return &EvmRegistry{ @@ -115,7 +117,7 @@ func NewEvmRegistry( logEventProvider: logEventProvider, bs: blockSub, finalityDepth: finalityDepth, - streams: streams.NewStreamsLookup(packer, mercuryConfig, blockSub, client.Client(), registry, lggr), + streams: streams.NewStreamsLookup(mercuryConfig, blockSub, client.Client(), registry, lggr), } } @@ -130,14 +132,14 @@ var upkeepStateEvents = []common.Hash{ } type MercuryConfig struct { - cred *models.MercuryCredentials + cred *types.MercuryCredentials Abi abi.ABI // AllowListCache stores the upkeeps privileges. In 2.1, this only includes a JSON bytes for allowed to use mercury AllowListCache *cache.Cache pluginRetryCache *cache.Cache } -func NewMercuryConfig(credentials *models.MercuryCredentials, abi abi.ABI) *MercuryConfig { +func NewMercuryConfig(credentials *types.MercuryCredentials, abi abi.ABI) *MercuryConfig { return &MercuryConfig{ cred: credentials, Abi: abi, @@ -146,7 +148,7 @@ func NewMercuryConfig(credentials *models.MercuryCredentials, abi abi.ABI) *Merc } } -func (c *MercuryConfig) Credentials() *models.MercuryCredentials { +func (c *MercuryConfig) Credentials() *types.MercuryCredentials { return c.cred } @@ -296,7 +298,7 @@ func (r *EvmRegistry) refreshActiveUpkeeps() error { continue } switch core.GetUpkeepType(*uid) { - case ocr2keepers.LogTrigger: + case types2.LogTrigger: logTriggerIDs = append(logTriggerIDs, id) default: } @@ -518,7 +520,7 @@ func (r *EvmRegistry) removeFromActive(id *big.Int) { uid.FromBigInt(id) trigger := core.GetUpkeepType(*uid) switch trigger { - case ocr2keepers.LogTrigger: + case types2.LogTrigger: if err := r.logEventProvider.UnregisterFilter(id); err != nil { r.lggr.Warnw("failed to unregister log filter", "upkeepID", id.String()) } @@ -586,7 +588,7 @@ func (r *EvmRegistry) updateTriggerConfig(id *big.Int, cfg []byte, logBlock uint uid := &ocr2keepers.UpkeepIdentifier{} uid.FromBigInt(id) switch core.GetUpkeepType(*uid) { - case ocr2keepers.LogTrigger: + case types2.LogTrigger: if len(cfg) == 0 { fetched, err := r.fetchTriggerConfig(id) if err != nil { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go index f5a931aae45..6475b3ef7df 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline.go @@ -6,11 +6,13 @@ import ( "math/big" "strings" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" @@ -105,7 +107,7 @@ func (r *EvmRegistry) getBlockHash(blockNumber *big.Int) (common.Hash, error) { } // verifyCheckBlock checks that the check block and hash are valid, returns the pipeline execution state and retryable -func (r *EvmRegistry) verifyCheckBlock(_ context.Context, checkBlock, upkeepId *big.Int, checkHash common.Hash) (state uint8, retryable bool) { +func (r *EvmRegistry) verifyCheckBlock(_ context.Context, checkBlock, upkeepId *big.Int, checkHash common.Hash) (state encoding.PipelineExecutionState, retryable bool) { // verify check block number and hash are valid h, ok := r.bs.queryBlocksMap(checkBlock.Int64()) // if this block number/hash combo exists in block subscriber, this check block and hash still exist on chain and are valid @@ -128,7 +130,7 @@ func (r *EvmRegistry) verifyCheckBlock(_ context.Context, checkBlock, upkeepId * } // verifyLogExists checks that the log still exists on chain, returns failure reason, pipeline error, and retryable -func (r *EvmRegistry) verifyLogExists(upkeepId *big.Int, p ocr2keepers.UpkeepPayload) (uint8, uint8, bool) { +func (r *EvmRegistry) verifyLogExists(upkeepId *big.Int, p ocr2keepers.UpkeepPayload) (encoding.UpkeepFailureReason, encoding.PipelineExecutionState, bool) { logBlockNumber := int64(p.Trigger.LogTriggerExtension.BlockNumber) logBlockHash := common.BytesToHash(p.Trigger.LogTriggerExtension.BlockHash[:]) checkBlockHash := common.BytesToHash(p.Trigger.BlockHash[:]) @@ -197,7 +199,7 @@ func (r *EvmRegistry) checkUpkeeps(ctx context.Context, payloads []ocr2keepers.U uid := &ocr2keepers.UpkeepIdentifier{} uid.FromBigInt(upkeepId) switch core.GetUpkeepType(*uid) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: reason, state, retryable := r.verifyLogExists(upkeepId, p) if reason != encoding.UpkeepFailureReasonNone || state != encoding.NoPipelineError { results[i] = encoding.GetIneligibleCheckResultWithoutPerformData(p, reason, state, retryable) diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go index a14aaec0c5e..e6b61be8d0a 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_check_pipeline_test.go @@ -8,6 +8,10 @@ import ( "sync/atomic" "testing" + types3 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + + types2 "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/rpc" @@ -16,7 +20,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -25,7 +29,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_compatible_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mocks" @@ -90,7 +93,7 @@ func TestRegistry_VerifyCheckBlock(t *testing.T) { payload ocr2keepers.UpkeepPayload blocks map[int64]string poller logpoller.LogPoller - state uint8 + state encoding.PipelineExecutionState retryable bool makeEthCall bool }{ @@ -248,8 +251,8 @@ func TestRegistry_VerifyLogExists(t *testing.T) { payload ocr2keepers.UpkeepPayload blocks map[int64]string makeEthCall bool - reason uint8 - state uint8 + reason encoding.UpkeepFailureReason + state encoding.PipelineExecutionState retryable bool ethCallErr error receipt *types.Receipt @@ -376,9 +379,9 @@ func TestRegistry_VerifyLogExists(t *testing.T) { func TestRegistry_CheckUpkeeps(t *testing.T) { lggr := logger.TestLogger(t) - uid0 := core.GenUpkeepID(ocr2keepers.UpkeepType(0), "p0") - uid1 := core.GenUpkeepID(ocr2keepers.UpkeepType(1), "p1") - uid2 := core.GenUpkeepID(ocr2keepers.UpkeepType(1), "p2") + uid0 := core.GenUpkeepID(types3.UpkeepType(0), "p0") + uid1 := core.GenUpkeepID(types3.UpkeepType(1), "p1") + uid2 := core.GenUpkeepID(types3.UpkeepType(1), "p2") extension1 := &ocr2keepers.LogTriggerExtension{ TxHash: common.HexToHash("0xc8def8abdcf3a4eaaf6cc13bff3e4e2a7168d86ea41dbbf97451235aa76c3651"), @@ -536,9 +539,9 @@ func TestRegistry_CheckUpkeeps(t *testing.T) { } func TestRegistry_SimulatePerformUpkeeps(t *testing.T) { - uid0 := core.GenUpkeepID(ocr2keepers.UpkeepType(0), "p0") - uid1 := core.GenUpkeepID(ocr2keepers.UpkeepType(1), "p1") - uid2 := core.GenUpkeepID(ocr2keepers.UpkeepType(1), "p2") + uid0 := core.GenUpkeepID(types3.UpkeepType(0), "p0") + uid1 := core.GenUpkeepID(types3.UpkeepType(1), "p1") + uid2 := core.GenUpkeepID(types3.UpkeepType(1), "p2") extension1 := &ocr2keepers.LogTriggerExtension{ TxHash: common.HexToHash("0xc8def8abdcf3a4eaaf6cc13bff3e4e2a7168d86ea41dbbf97451235aa76c3651"), @@ -682,7 +685,7 @@ func setupEVMRegistry(t *testing.T) *EvmRegistry { headFunc: func(ocr2keepers.BlockKey) {}, chLog: make(chan logpoller.Log, 1000), mercury: &MercuryConfig{ - cred: &models.MercuryCredentials{ + cred: &types2.MercuryCredentials{ LegacyURL: "https://google.old.com", URL: "https://google.com", Username: "FakeClientID", diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go index f3e4402092c..dc48c3d75f6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/registry_test.go @@ -8,17 +8,18 @@ import ( "testing" "time" + types2 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" coreTypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - types3 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" @@ -27,7 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestPollLogs(t *testing.T) { @@ -132,8 +132,8 @@ func TestPollLogs(t *testing.T) { InputStart: 250, InputEnd: 500, OutputLogs: []logpoller.Log{ - {EvmChainId: utils.NewBig(big.NewInt(5)), LogIndex: 1}, - {EvmChainId: utils.NewBig(big.NewInt(6)), LogIndex: 2}, + {EvmChainId: ubig.New(big.NewInt(5)), LogIndex: 1}, + {EvmChainId: ubig.New(big.NewInt(6)), LogIndex: 2}, }, OutputErr: nil, }, @@ -211,7 +211,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { { name: "an error is returned when fetching indexed logs for IKeeperRegistryMasterUpkeepUnpaused errors", ids: []*big.Int{ - core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), }, logEventProvider: &mockLogEventProvider{ RefreshActiveUpkeepsFn: func(ids ...*big.Int) ([]*big.Int, error) { @@ -234,8 +234,8 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { { name: "an error is returned when fetching indexed logs for IKeeperRegistryMasterUpkeepTriggerConfigSet errors", ids: []*big.Int{ - core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), - core.GenUpkeepID(types.ConditionTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.ConditionTrigger, "abc").BigInt(), big.NewInt(-1), }, logEventProvider: &mockLogEventProvider{ @@ -259,8 +259,8 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { { name: "an error is returned when parsing the logs using the registry errors", ids: []*big.Int{ - core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), - core.GenUpkeepID(types.ConditionTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.ConditionTrigger, "abc").BigInt(), big.NewInt(-1), }, logEventProvider: &mockLogEventProvider{ @@ -288,8 +288,8 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { { name: "an error is returned when registering the filter errors", ids: []*big.Int{ - core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), - core.GenUpkeepID(types.ConditionTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.ConditionTrigger, "abc").BigInt(), big.NewInt(-1), }, logEventProvider: &mockLogEventProvider{ @@ -319,11 +319,11 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { if log.BlockNumber == 1 { return &iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{ TriggerConfig: []byte{1, 2, 3}, - Id: core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), }, nil } return &iregistry21.IKeeperRegistryMasterUpkeepUnpaused{ - Id: core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), }, nil }, GetUpkeepTriggerConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { @@ -341,9 +341,9 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { { name: "log trigger upkeeps are refreshed without error", ids: []*big.Int{ - core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), - core.GenUpkeepID(types.LogTrigger, "def").BigInt(), - core.GenUpkeepID(types.ConditionTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), + core.GenUpkeepID(types2.LogTrigger, "def").BigInt(), + core.GenUpkeepID(types2.ConditionTrigger, "abc").BigInt(), big.NewInt(-1), }, logEventProvider: &mockLogEventProvider{ @@ -372,12 +372,12 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { ParseLogFn: func(log coreTypes.Log) (generated.AbigenLog, error) { if log.BlockNumber == 1 { return &iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{ - Id: core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), TriggerConfig: []byte{1, 2, 3}, }, nil } return &iregistry21.IKeeperRegistryMasterUpkeepUnpaused{ - Id: core.GenUpkeepID(types.LogTrigger, "def").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "def").BigInt(), }, nil }, GetUpkeepTriggerConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { @@ -395,7 +395,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { ids: func() []*big.Int { res := []*big.Int{} for i := 0; i < logTriggerRefreshBatchSize*3; i++ { - res = append(res, core.GenUpkeepID(types.LogTrigger, fmt.Sprintf("%d", i)).BigInt()) + res = append(res, core.GenUpkeepID(types2.LogTrigger, fmt.Sprintf("%d", i)).BigInt()) } return res }(), @@ -424,12 +424,12 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { ParseLogFn: func(log coreTypes.Log) (generated.AbigenLog, error) { if log.BlockNumber == 1 { return &iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{ - Id: core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), TriggerConfig: []byte{1, 2, 3}, }, nil } return &iregistry21.IKeeperRegistryMasterUpkeepUnpaused{ - Id: core.GenUpkeepID(types.LogTrigger, "def").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "def").BigInt(), }, nil }, GetUpkeepTriggerConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { @@ -447,7 +447,7 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { ids: func() []*big.Int { res := []*big.Int{} for i := 0; i < logTriggerRefreshBatchSize+3; i++ { - res = append(res, core.GenUpkeepID(types.LogTrigger, fmt.Sprintf("%d", i)).BigInt()) + res = append(res, core.GenUpkeepID(types2.LogTrigger, fmt.Sprintf("%d", i)).BigInt()) } return res }(), @@ -478,12 +478,12 @@ func TestRegistry_refreshLogTriggerUpkeeps(t *testing.T) { ParseLogFn: func(log coreTypes.Log) (generated.AbigenLog, error) { if log.BlockNumber == 1 { return &iregistry21.IKeeperRegistryMasterUpkeepTriggerConfigSet{ - Id: core.GenUpkeepID(types.LogTrigger, "abc").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "abc").BigInt(), TriggerConfig: []byte{1, 2, 3}, }, nil } return &iregistry21.IKeeperRegistryMasterUpkeepUnpaused{ - Id: core.GenUpkeepID(types.LogTrigger, "def").BigInt(), + Id: core.GenUpkeepID(types2.LogTrigger, "def").BigInt(), }, nil }, GetUpkeepTriggerConfigFn: func(opts *bind.CallOpts, upkeepId *big.Int) ([]byte, error) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go index 71ccee872ff..5fe21b08724 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/services.go @@ -1,136 +1,31 @@ package evm import ( - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/jmoiron/sqlx" - "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - - "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" - iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) type AutomationServices interface { - Registry() *EvmRegistry - Encoder() ocr2keepers.Encoder - TransmitEventProvider() *transmit.EventProvider - BlockSubscriber() *BlockSubscriber - PayloadBuilder() ocr2keepers.PayloadBuilder - UpkeepStateStore() upkeepstate.UpkeepStateStore - LogEventProvider() logprovider.LogEventProvider - LogRecoverer() logprovider.LogRecoverer - UpkeepProvider() ocr2keepers.ConditionalUpkeepProvider Keyring() ocr3types.OnchainKeyring[plugin.AutomationReportInfo] } -func New(addr common.Address, client legacyevm.Chain, mc *models.MercuryCredentials, keyring ocrtypes.OnchainKeyring, lggr logger.Logger, db *sqlx.DB, dbCfg pg.QConfig) (AutomationServices, error) { - registryContract, err := iregistry21.NewIKeeperRegistryMaster(addr, client.Client()) - if err != nil { - return nil, fmt.Errorf("%w: failed to create caller for address and backend", ErrInitializationFailure) - } - // lookback blocks for transmit event is hard coded and should provide ample time for logs - // to be detected in most cases - var transmitLookbackBlocks int64 = 250 - transmitEventProvider, err := transmit.NewTransmitEventProvider(lggr, client.LogPoller(), addr, client.Client(), transmitLookbackBlocks) - if err != nil { - return nil, err - } +func New(keyring ocrtypes.OnchainKeyring) (AutomationServices, error) { services := new(automationServices) - services.transmitEventProvider = transmitEventProvider - - packer := encoding.NewAbiPacker() - services.encoder = encoding.NewReportEncoder(packer) - - finalityDepth := client.Config().EVM().FinalityDepth() - - orm := upkeepstate.NewORM(client.ID(), db, lggr, dbCfg) - scanner := upkeepstate.NewPerformedEventsScanner(lggr, client.LogPoller(), addr, finalityDepth) - services.upkeepState = upkeepstate.NewUpkeepStateStore(orm, lggr, scanner) - - logProvider, logRecoverer := logprovider.New(lggr, client.LogPoller(), client.Client(), services.upkeepState, finalityDepth) - services.logProvider = logProvider - services.logRecoverer = logRecoverer - services.blockSub = NewBlockSubscriber(client.HeadBroadcaster(), client.LogPoller(), finalityDepth, lggr) services.keyring = NewOnchainKeyringV3Wrapper(keyring) - al := NewActiveUpkeepList() - services.payloadBuilder = NewPayloadBuilder(al, logRecoverer, lggr) - - services.reg = NewEvmRegistry(lggr, addr, client, - registryContract, mc, al, services.logProvider, - packer, services.blockSub, finalityDepth) - - services.upkeepProvider = NewUpkeepProvider(al, services.blockSub, client.LogPoller()) - return services, nil } type automationServices struct { - reg *EvmRegistry - encoder ocr2keepers.Encoder - transmitEventProvider *transmit.EventProvider - blockSub *BlockSubscriber - payloadBuilder ocr2keepers.PayloadBuilder - upkeepState upkeepstate.UpkeepStateStore - logProvider logprovider.LogEventProvider - logRecoverer logprovider.LogRecoverer - upkeepProvider *upkeepProvider - keyring *onchainKeyringV3Wrapper + keyring *onchainKeyringV3Wrapper } var _ AutomationServices = &automationServices{} -func (f *automationServices) Registry() *EvmRegistry { - return f.reg -} - -func (f *automationServices) Encoder() ocr2keepers.Encoder { - return f.encoder -} - -func (f *automationServices) TransmitEventProvider() *transmit.EventProvider { - return f.transmitEventProvider -} - -func (f *automationServices) BlockSubscriber() *BlockSubscriber { - return f.blockSub -} - -func (f *automationServices) PayloadBuilder() ocr2keepers.PayloadBuilder { - return f.payloadBuilder -} - -func (f *automationServices) UpkeepStateStore() upkeepstate.UpkeepStateStore { - return f.upkeepState -} - -func (f *automationServices) LogEventProvider() logprovider.LogEventProvider { - return f.logProvider -} - -func (f *automationServices) LogRecoverer() logprovider.LogRecoverer { - return f.logRecoverer -} - -func (f *automationServices) UpkeepProvider() ocr2keepers.ConditionalUpkeepProvider { - return f.upkeepProvider -} - func (f *automationServices) Keyring() ocr3types.OnchainKeyring[plugin.AutomationReportInfo] { return f.keyring } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go index 99e1f1dc164..814e86040b3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache.go @@ -3,7 +3,7 @@ package transmit import ( "sync" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) // transmitEventCache holds a ring buffer of the last visited blocks (transmit block), @@ -28,7 +28,7 @@ func (c *transmitEventCache) get(block ocr2keepers.BlockNumber, logID string) (o c.lock.RLock() defer c.lock.RUnlock() - i := int64(block) % int64(c.cap) + i := int64(block) % c.cap b := c.buffer[i] if b.block != block { return ocr2keepers.TransmitEvent{}, false @@ -45,7 +45,7 @@ func (c *transmitEventCache) add(logID string, e ocr2keepers.TransmitEvent) { c.lock.Lock() defer c.lock.Unlock() - i := int64(e.TransmitBlock) % int64(c.cap) + i := int64(e.TransmitBlock) % c.cap b := c.buffer[i] isBlockEmpty := len(b.records) == 0 isNewBlock := b.block < e.TransmitBlock diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache_test.go index 7f4a1296567..e7b7ca800ab 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/cache_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" ) func TestTransmitEventCache_Sanity(t *testing.T) { diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding.go index 17d3cd439f8..89dbb52c0e3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go index da32376aab6..97aed4706ec 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/encoding_test.go @@ -3,10 +3,12 @@ package transmit import ( "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" @@ -14,7 +16,7 @@ import ( ) func TestTransmitEventLog(t *testing.T) { - uid := core.GenUpkeepID(ocr2keepers.ConditionTrigger, "111") + uid := core.GenUpkeepID(types.ConditionTrigger, "111") tests := []struct { name string diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go index f66711c2b71..eb8dc1793c1 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider.go @@ -6,9 +6,11 @@ import ( "fmt" "sync" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" @@ -20,7 +22,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" ) -var _ ocr2keepers.TransmitEventProvider = &EventProvider{} +var _ types.TransmitEventProvider = &EventProvider{} type logParser func(registry *iregistry21.IKeeperRegistryMaster, log logpoller.Log) (transmitEventLog, error) @@ -189,7 +191,7 @@ func (c *EventProvider) processLogs(latestBlock int64, logs ...logpoller.Log) ([ triggerW.BlockHash, ) switch core.GetUpkeepType(*upkeepId) { - case ocr2keepers.LogTrigger: + case types.LogTrigger: trigger.LogTriggerExtension = &ocr2keepers.LogTriggerExtension{} trigger.LogTriggerExtension.TxHash = triggerW.TxHash trigger.LogTriggerExtension.Index = triggerW.LogIndex diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go index 950ec810402..89a49f07807 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit/event_provider_test.go @@ -5,12 +5,14 @@ import ( "runtime" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" @@ -107,7 +109,7 @@ func TestTransmitEventProvider_ProcessLogs(t *testing.T) { provider, err := NewTransmitEventProvider(logger.TestLogger(t), lp, common.HexToAddress("0x"), client, 250) require.NoError(t, err) - id := core.GenUpkeepID(ocr2keepers.LogTrigger, "1111111111111111") + id := core.GenUpkeepID(types.LogTrigger, "1111111111111111") tests := []struct { name string diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go index b30215e4fbf..01f136aaa6b 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider.go @@ -4,7 +4,8 @@ import ( "context" "fmt" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" @@ -32,7 +33,7 @@ func (p *upkeepProvider) GetActiveUpkeeps(_ context.Context) ([]ocr2keepers.Upke return nil, fmt.Errorf("no latest block found when fetching active upkeeps") } var payloads []ocr2keepers.UpkeepPayload - for _, uid := range p.activeUpkeeps.View(ocr2keepers.ConditionTrigger) { + for _, uid := range p.activeUpkeeps.View(types.ConditionTrigger) { payload, err := core.NewUpkeepPayload( uid, ocr2keepers.NewTrigger(latestBlock.Number, latestBlock.Hash), diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go index 81ea3913188..cad2d77411d 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeep_provider_test.go @@ -5,9 +5,11 @@ import ( "sync/atomic" "testing" + "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + "github.com/stretchr/testify/require" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -29,7 +31,7 @@ func TestUpkeepProvider_GetActiveUpkeeps(t *testing.T) { { "empty", &mockActiveUpkeepList{ - ViewFn: func(upkeepType ...ocr2keepers.UpkeepType) []*big.Int { + ViewFn: func(upkeepType ...types.UpkeepType) []*big.Int { return []*big.Int{} }, }, @@ -40,7 +42,7 @@ func TestUpkeepProvider_GetActiveUpkeeps(t *testing.T) { { "happy flow", &mockActiveUpkeepList{ - ViewFn: func(upkeepType ...ocr2keepers.UpkeepType) []*big.Int { + ViewFn: func(upkeepType ...types.UpkeepType) []*big.Int { return []*big.Int{ big.NewInt(1), big.NewInt(2), @@ -65,7 +67,7 @@ func TestUpkeepProvider_GetActiveUpkeeps(t *testing.T) { { "latest block not found", &mockActiveUpkeepList{ - ViewFn: func(upkeepType ...ocr2keepers.UpkeepType) []*big.Int { + ViewFn: func(upkeepType ...types.UpkeepType) []*big.Int { return []*big.Int{ big.NewInt(1), big.NewInt(2), @@ -100,11 +102,11 @@ func TestUpkeepProvider_GetActiveUpkeeps(t *testing.T) { type mockActiveUpkeepList struct { ActiveUpkeepList - ViewFn func(...ocr2keepers.UpkeepType) []*big.Int + ViewFn func(...types.UpkeepType) []*big.Int IsActiveFn func(id *big.Int) bool } -func (l *mockActiveUpkeepList) View(u ...ocr2keepers.UpkeepType) []*big.Int { +func (l *mockActiveUpkeepList) View(u ...types.UpkeepType) []*big.Int { return l.ViewFn(u...) } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm.go index c918ad595fa..a5bd738de4c 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm.go @@ -7,18 +7,18 @@ import ( "github.com/jmoiron/sqlx" "github.com/lib/pq" + ubig "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" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type orm struct { - chainID *utils.Big + chainID *ubig.Big q pg.Q } type persistedStateRecord struct { - UpkeepID *utils.Big + UpkeepID *ubig.Big WorkID string CompletionState uint8 BlockNumber int64 @@ -29,7 +29,7 @@ type persistedStateRecord struct { // NewORM creates an ORM scoped to chainID. func NewORM(chainID *big.Int, db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig) *orm { return &orm{ - chainID: utils.NewBig(chainID), + chainID: ubig.New(chainID), q: pg.NewQ(db, lggr.Named("ORM"), cfg), } } @@ -43,12 +43,12 @@ func (o *orm) BatchInsertRecords(state []persistedStateRecord, qopts ...pg.QOpt) } type row struct { - EvmChainId *utils.Big + EvmChainId *ubig.Big WorkId string CompletionState uint8 BlockNumber int64 InsertedAt time.Time - UpkeepId *utils.Big + UpkeepId *ubig.Big IneligibilityReason uint8 } diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm_test.go index 54ca7285dd0..bfd131b5055 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/orm_test.go @@ -9,10 +9,10 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "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/utils" ) func TestInsertSelectDelete(t *testing.T) { @@ -23,7 +23,7 @@ func TestInsertSelectDelete(t *testing.T) { inserted := []persistedStateRecord{ { - UpkeepID: utils.NewBig(big.NewInt(2)), + UpkeepID: ubig.New(big.NewInt(2)), WorkID: "0x1", CompletionState: 100, BlockNumber: 2, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go index 4a4de5ea1ad..9410374d7ca 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store.go @@ -8,10 +8,11 @@ import ( "sync" "time" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "github.com/smartcontractkit/chainlink-common/pkg/services" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/core" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -225,7 +226,7 @@ func (u *upkeepStateStore) upsertStateRecord(ctx context.Context, workID string, u.cache[workID] = record u.pendingRecords = append(u.pendingRecords, persistedStateRecord{ - UpkeepID: utils.NewBig(upkeepID), + UpkeepID: ubig.New(upkeepID), WorkID: record.workID, CompletionState: uint8(record.state), IneligibilityReason: reason, diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go index 138b9ffd782..3912e2a99c6 100644 --- a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate/store_test.go @@ -12,8 +12,9 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" - ocr2keepers "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" + ocr2keepers "github.com/smartcontractkit/chainlink-common/pkg/types/automation" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -346,7 +347,7 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { scanner := &mockScanner{} store := NewUpkeepStateStore(orm, lggr, scanner) - require.NoError(t, store.Start(ctx)) + servicetest.Run(t, store) t.Cleanup(func() { t.Log("cleaning up database") @@ -379,8 +380,6 @@ func TestUpkeepStateStore_SetSelectIntegration(t *testing.T) { observedLogs.TakeAll() require.Equal(t, 0, observedLogs.Len()) - - require.NoError(t, store.Close()) }) } } @@ -467,7 +466,7 @@ func TestUpkeepStateStore_Service(t *testing.T) { store.retention = 500 * time.Millisecond store.cleanCadence = 100 * time.Millisecond - assert.NoError(t, store.Start(ctx), "no error from starting service") + servicetest.Run(t, store) // add a value to set up the test require.NoError(t, store.SetUpkeepState(ctx, ocr2keepers.CheckResult{ @@ -493,8 +492,6 @@ func TestUpkeepStateStore_Service(t *testing.T) { values, err = store.SelectByWorkIDs(ctx, "0x2") require.NoError(t, err, "no error from selecting states") require.Equal(t, []ocr2keepers.UpkeepState{ocr2keepers.UnknownState}, values, "selected values should match expected") - - assert.NoError(t, store.Close(), "no error from closing service") } func createUpkeepIDForTest(v int64) ocr2keepers.UpkeepIdentifier { diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index 7ccd785a668..81a35a5ced2 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -32,7 +32,6 @@ import ( ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" - "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -55,7 +54,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -118,7 +116,7 @@ func TestIntegration_KeeperPluginConditionalUpkeep(t *testing.T) { require.NoError(t, err) registry := deployKeeper21Registry(t, steve, backend, linkAddr, linkFeedAddr, gasFeedAddr) - nodes, _ := setupNodes(t, nodeKeys, registry, backend, steve) + setupNodes(t, nodeKeys, registry, backend, steve) <-time.After(time.Second * 5) @@ -161,8 +159,6 @@ func TestIntegration_KeeperPluginConditionalUpkeep(t *testing.T) { } g.Eventually(receivedBytes, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal(payload1)) - checkPipelineRuns(t, nodes, 1) - // change payload _, err = upkeepContract.SetBytesToSend(carrol, payload2) require.NoError(t, err) @@ -205,7 +201,7 @@ func TestIntegration_KeeperPluginLogUpkeep(t *testing.T) { require.NoError(t, err) registry := deployKeeper21Registry(t, steve, backend, linkAddr, linkFeedAddr, gasFeedAddr) - nodes, _ := setupNodes(t, nodeKeys, registry, backend, steve) + setupNodes(t, nodeKeys, registry, backend, steve) upkeeps := 1 _, err = linkToken.Transfer(sergey, carrol.From, big.NewInt(0).Mul(oneHunEth, big.NewInt(int64(upkeeps+1)))) @@ -229,35 +225,36 @@ func TestIntegration_KeeperPluginLogUpkeep(t *testing.T) { g.Eventually(listener, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.BeTrue()) done() - runs := checkPipelineRuns(t, nodes, 1) - t.Run("recover logs", func(t *testing.T) { - addr, contract := addrs[0], contracts[0] upkeepID := registerUpkeep(t, registry, addr, carrol, steve, backend) backend.Commit() t.Logf("Registered new upkeep %s for address %s", upkeepID.String(), addr.String()) // Emit 100 logs in a burst - emits := 100 + recoverEmits := 100 i := 0 emitEvents(testutils.Context(t), t, 100, []*log_upkeep_counter_wrapper.LogUpkeepCounter{contract}, carrol, func() { i++ - if i%(emits/4) == 0 { + if i%(recoverEmits/4) == 0 { backend.Commit() time.Sleep(time.Millisecond * 250) // otherwise we get "invalid transaction nonce" errors } }) - // Mine enough blocks to ensre these logs don't fall into log provider range + + beforeDummyBlocks := backend.Blockchain().CurrentBlock().Number.Uint64() + + // Mine enough blocks to ensure these logs don't fall into log provider range dummyBlocks := 500 for i := 0; i < dummyBlocks; i++ { backend.Commit() time.Sleep(time.Millisecond * 10) } - t.Logf("Mined %d blocks, waiting for logs to be recovered", dummyBlocks) - expectedPostRecover := runs + emits - waitPipelineRuns(t, nodes, expectedPostRecover, testutils.WaitTimeout(t), cltest.DBPollingInterval) + t.Logf("Mined %d blocks, waiting for logs to be recovered", dummyBlocks) + listener, done := listenPerformedN(t, backend, registry, ids, int64(beforeDummyBlocks), recoverEmits) + g.Eventually(listener, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.BeTrue()) + done() }) } @@ -297,7 +294,7 @@ func TestIntegration_KeeperPluginLogUpkeep_Retry(t *testing.T) { registry := deployKeeper21Registry(t, registryOwner, backend, linkAddr, linkFeedAddr, gasFeedAddr) - nodes, mercuryServer := setupNodes(t, nodeKeys, registry, backend, registryOwner) + _, mercuryServer := setupNodes(t, nodeKeys, registry, backend, registryOwner) const upkeepCount = 10 const mercuryFailCount = upkeepCount * 3 * 2 @@ -375,39 +372,6 @@ func TestIntegration_KeeperPluginLogUpkeep_Retry(t *testing.T) { g.Eventually(listener, testutils.WaitTimeout(t)-(5*time.Second), cltest.DBPollingInterval).Should(gomega.BeTrue()) done() - - _ = checkPipelineRuns(t, nodes, 1*len(nodes)) // TODO: TBD -} - -func waitPipelineRuns(t *testing.T, nodes []Node, n int, timeout, interval time.Duration) { - ctx, cancel := context.WithTimeout(testutils.Context(t), timeout) - defer cancel() - var allRuns []pipeline.Run - for len(allRuns) < n && ctx.Err() == nil { - allRuns = []pipeline.Run{} - for _, node := range nodes { - runs, err := node.App.PipelineORM().GetAllRuns() - require.NoError(t, err) - allRuns = append(allRuns, runs...) - } - time.Sleep(interval) - } - runs := len(allRuns) - t.Logf("found %d pipeline runs", runs) - require.GreaterOrEqual(t, runs, n) -} - -func checkPipelineRuns(t *testing.T, nodes []Node, n int) int { - var allRuns []pipeline.Run - for _, node := range nodes { - runs, err2 := node.App.PipelineORM().GetAllRuns() - require.NoError(t, err2) - allRuns = append(allRuns, runs...) - } - runs := len(allRuns) - t.Logf("found %d pipeline runs", runs) - require.GreaterOrEqual(t, runs, n) - return runs } func emitEvents(ctx context.Context, t *testing.T, n int, contracts []*log_upkeep_counter_wrapper.LogUpkeepCounter, carrol *bind.TransactOpts, afterEmit func()) { @@ -425,32 +389,32 @@ func mapListener(m *sync.Map, n int) func() bool { return func() bool { count := 0 m.Range(func(key, value interface{}) bool { - count++ + count += value.(int) return true }) return count > n } } -func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry *iregistry21.IKeeperRegistryMaster, ids []*big.Int, startBlock int64) (func() bool, func()) { +func listenPerformedN(t *testing.T, backend *backends.SimulatedBackend, registry *iregistry21.IKeeperRegistryMaster, ids []*big.Int, startBlock int64, count int) (func() bool, func()) { cache := &sync.Map{} ctx, cancel := context.WithCancel(testutils.Context(t)) start := startBlock go func() { for ctx.Err() == nil { - bl := backend.Blockchain().CurrentBlock().Number.Uint64() + currentBlock := backend.Blockchain().CurrentBlock().Number.Uint64() - sc := make([]bool, len(ids)) - for i := range sc { - sc[i] = true + success := make([]bool, len(ids)) + for i := range success { + success[i] = true } iter, err := registry.FilterUpkeepPerformed(&bind.FilterOpts{ Start: uint64(start), - End: &bl, + End: ¤tBlock, Context: ctx, - }, ids, sc) + }, ids, success) if ctx.Err() != nil { return @@ -461,7 +425,15 @@ func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry for iter.Next() { if iter.Event != nil { t.Logf("[automation-ocr3 | EvmRegistry] upkeep performed event emitted for id %s", iter.Event.Id.String()) - cache.Store(iter.Event.Id.String(), true) + + //cache.Store(iter.Event.Id.String(), true) + count, ok := cache.Load(iter.Event.Id.String()) + if !ok { + cache.Store(iter.Event.Id.String(), 1) + continue + } + countI := count.(int) + cache.Store(iter.Event.Id.String(), countI+1) } } @@ -471,7 +443,11 @@ func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry } }() - return mapListener(cache, 0), cancel + return mapListener(cache, count), cancel +} + +func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry *iregistry21.IKeeperRegistryMaster, ids []*big.Int, startBlock int64) (func() bool, func()) { + return listenPerformedN(t, backend, registry, ids, startBlock, 0) } func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IKeeperRegistryMaster, backend *backends.SimulatedBackend, usr *bind.TransactOpts) ([]Node, *SimulatedMercuryServer) { diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 1ab9194c496..56467c60abb 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -32,11 +32,13 @@ import ( ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-automation/pkg/v2/config" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/basic_upkeep_contract" @@ -57,10 +59,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" "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/evm" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( @@ -123,10 +123,9 @@ func setupNode( c.OCR2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - c.P2P.V1.Enabled = ptr(false) c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) c.P2P.V2.AnnounceAddresses = &p2paddresses c.P2P.V2.ListenAddresses = &p2paddresses if len(p2pV2Bootstrappers) > 0 { @@ -412,15 +411,6 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { } g.Eventually(receivedBytes, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal(payload1)) - // check pipeline runs - var allRuns []pipeline.Run - for _, node := range nodes { - runs, err2 := node.App.PipelineORM().GetAllRuns() - require.NoError(t, err2) - allRuns = append(allRuns, runs...) - } - require.GreaterOrEqual(t, len(allRuns), 1) - // change payload _, err = upkeepContract.SetBytesToSend(carrol, payload2) require.NoError(t, err) @@ -449,7 +439,7 @@ func setupForwarderForNode( // add forwarder address to be tracked in db forwarderORM := forwarders.NewORM(app.GetSqlxDB(), logger.TestLogger(t), app.GetConfig().Database()) - chainID := utils.Big(*backend.Blockchain().Config().ChainID) + chainID := ubig.Big(*backend.Blockchain().Config().ChainID) _, err = forwarderORM.CreateForwarder(faddr, chainID) require.NoError(t, err) @@ -684,15 +674,6 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { } g.Eventually(receivedBytes, testutils.WaitTimeout(t), cltest.DBPollingInterval).Should(gomega.Equal(payload1)) - // check pipeline runs - var allRuns []pipeline.Run - for _, node := range nodes { - runs, err2 := node.App.PipelineORM().GetAllRuns() - require.NoError(t, err2) - allRuns = append(allRuns, runs...) - } - require.GreaterOrEqual(t, len(allRuns), 1) - // change payload _, err = upkeepContract.SetBytesToSend(carrol, payload2) require.NoError(t, err) diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index 02a0d033bc1..53fff8751c3 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -3,6 +3,10 @@ package ocr2keeper import ( "fmt" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + "github.com/jmoiron/sqlx" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -11,21 +15,16 @@ import ( ocr2keepers20coordinator "github.com/smartcontractkit/chainlink-automation/pkg/v2/coordinator" ocr2keepers20polling "github.com/smartcontractkit/chainlink-automation/pkg/v2/observer/polling" ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner" - ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types" - - "github.com/smartcontractkit/chainlink-common/pkg/types" + ocr2keepers21 "github.com/smartcontractkit/chainlink-common/pkg/types/automation" "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/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/models" evmregistry20 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20" evmregistry21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" evmregistry21transmit "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" "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" ) type Encoder20 interface { @@ -44,9 +43,9 @@ var ( ErrNoChainFromSpec = fmt.Errorf("could not create chain from spec") ) -func EVMProvider(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, spec job.Job, pr pipeline.Runner) (evmrelay.OCR2KeeperProvider, error) { +func EVMProvider(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, spec job.Job, ethKeystore keystore.Eth, dbCfg pg.QConfig) (evmrelay.OCR2KeeperProvider, error) { oSpec := spec.OCR2OracleSpec - ocr2keeperRelayer := evmrelay.NewOCR2KeeperRelayer(db, chain, pr, spec, lggr.Named("OCR2KeeperRelayer")) + ocr2keeperRelayer := evmrelay.NewOCR2KeeperRelayer(db, chain, lggr.Named("OCR2KeeperRelayer"), ethKeystore, dbCfg) keeperProvider, err := ocr2keeperRelayer.NewOCR2KeeperProvider( types.RelayArgs{ @@ -72,7 +71,8 @@ func EVMDependencies20( db *sqlx.DB, lggr logger.Logger, chain legacyevm.Chain, - pr pipeline.Runner, + ethKeystore keystore.Eth, + dbCfg pg.QConfig, ) (evmrelay.OCR2KeeperProvider, *evmregistry20.EvmRegistry, Encoder20, *evmregistry20.LogProvider, error) { var err error @@ -80,7 +80,7 @@ func EVMDependencies20( var registry *evmregistry20.EvmRegistry // the provider will be returned as a dependency - if keeperProvider, err = EVMProvider(db, chain, lggr, spec, pr); err != nil { + if keeperProvider, err = EVMProvider(db, chain, lggr, spec, ethKeystore, dbCfg); err != nil { return nil, nil, nil, nil, err } @@ -109,31 +109,9 @@ func FilterNamesFromSpec20(spec *job.OCR2OracleSpec) (names []string, err error) } func EVMDependencies21( - spec job.Job, - db *sqlx.DB, - lggr logger.Logger, - chain legacyevm.Chain, - pr pipeline.Runner, - mc *models.MercuryCredentials, keyring ocrtypes.OnchainKeyring, - dbCfg pg.QConfig, -) (evmrelay.OCR2KeeperProvider, evmregistry21.AutomationServices, error) { - var err error - var keeperProvider evmrelay.OCR2KeeperProvider - - oSpec := spec.OCR2OracleSpec - // the provider will be returned as a dependency - if keeperProvider, err = EVMProvider(db, chain, lggr, spec, pr); err != nil { - return nil, nil, err - } - - rAddr := ethkey.MustEIP55Address(oSpec.ContractID).Address() - services, err := evmregistry21.New(rAddr, chain, mc, keyring, lggr, db, dbCfg) - if err != nil { - return nil, nil, err - } - - return keeperProvider, services, err +) (evmregistry21.AutomationServices, error) { + return evmregistry21.New(keyring) } func FilterNamesFromSpec21(spec *job.OCR2OracleSpec) (names []string, err error) { diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go index 63538941532..88d6544d8c4 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator.go @@ -23,6 +23,8 @@ import ( "github.com/smartcontractkit/libocr/commontypes" ocr2Types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" + "github.com/smartcontractkit/chainlink-vrf/dkg" ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" @@ -38,7 +40,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ocr2vrfconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/config" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) var _ ocr2vrftypes.CoordinatorInterface = &coordinator{} @@ -397,7 +398,7 @@ func (c *coordinator) ReportBlocks( // TODO BELOW: Write tests for the new blockhash retrieval. // Obtain recent blockhashes, ordered by ascending block height. - for i := recentBlockHashesStartHeight; i <= uint64(currentHeight); i++ { + for i := recentBlockHashesStartHeight; i <= currentHeight; i++ { recentBlockHashes = append(recentBlockHashes, blockhashesMapping[i]) } @@ -517,7 +518,7 @@ func (c *coordinator) getBlockhashesMappingFromRequests( } // Get a mapping of block numbers to block hashes. - blockhashesMapping, err = c.getBlockhashesMapping(ctx, append(requestedBlockNumbers, uint64(currentHeight), recentBlockHashesStartHeight)) + blockhashesMapping, err = c.getBlockhashesMapping(ctx, append(requestedBlockNumbers, currentHeight, recentBlockHashesStartHeight)) if err != nil { err = errors.Wrap(err, "get blockhashes for ReportBlocks") } diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go index 418e4356c68..096589b2053 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/coordinator_test.go @@ -27,6 +27,7 @@ import ( ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" @@ -38,7 +39,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2vrf/coordinator/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) func TestCoordinator_BeaconPeriod(t *testing.T) { @@ -271,7 +271,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 1) assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -333,7 +333,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.False(t, b.ShouldStore) } assert.Len(t, callbacks, 3) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -400,7 +400,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 0) assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -471,7 +471,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 0) assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -533,7 +533,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 0) assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -635,7 +635,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 0) assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -705,7 +705,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.True(t, b.ShouldStore) } assert.Len(t, callbacks, 0) - assert.Equal(t, uint64(latestHeadNumber-blockhashLookback+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-blockhashLookback+1, recentHeightStart) assert.Len(t, recentBlocks, int(blockhashLookback)) }) @@ -772,7 +772,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.True(t, b.ShouldStore) } assert.Len(t, callbacks, 2) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -835,7 +835,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 1) assert.Len(t, callbacks, 1) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -901,7 +901,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { assert.NoError(t, err) assert.Len(t, blocks, 2) assert.Len(t, callbacks, 2) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Len(t, recentBlocks, int(lookbackBlocks)) }) @@ -956,7 +956,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { ) assert.NoError(t, err) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", 1)), recentBlocks[0]) assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", lookbackBlocks)), recentBlocks[len(recentBlocks)-1]) assert.Len(t, recentBlocks, int(lookbackBlocks)) @@ -1013,7 +1013,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { ) assert.NoError(t, err) - assert.Equal(t, uint64(latestHeadNumber-lookbackBlocks+1), recentHeightStart) + assert.Equal(t, latestHeadNumber-lookbackBlocks+1, recentHeightStart) assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", 1)), recentBlocks[0]) assert.Equal(t, common.HexToHash(fmt.Sprintf("0x00%d", lookbackBlocks)), recentBlocks[len(recentBlocks)-1]) assert.Len(t, recentBlocks, int(lookbackBlocks)) @@ -1035,7 +1035,7 @@ func TestCoordinator_ReportBlocks(t *testing.T) { lp.On("LatestBlock", mock.Anything). Return(logpoller.LogPollerBlock{BlockNumber: int64(latestHeadNumber)}, nil) - lp.On("GetBlocksRange", mock.Anything, append(requestedBlocks, uint64(latestHeadNumber-lookbackBlocks+1), uint64(latestHeadNumber)), mock.Anything). + lp.On("GetBlocksRange", mock.Anything, append(requestedBlocks, latestHeadNumber-lookbackBlocks+1, latestHeadNumber), mock.Anything). Return(nil, errors.New("GetBlocks error")) lp.On( "LogsWithSigs", 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 d3fe5c91195..57521566a71 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ type VRFBeaconInterface struct { func (_m *VRFBeaconInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *VRFBeaconInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.T func (_m *VRFBeaconInterface) AcceptPayeeship(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { ret := _m.Called(opts, transmitter) + if len(ret) == 0 { + panic("no return value specified for AcceptPayeeship") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -80,6 +88,10 @@ func (_m *VRFBeaconInterface) AcceptPayeeship(opts *bind.TransactOpts, transmitt func (_m *VRFBeaconInterface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -96,6 +108,10 @@ func (_m *VRFBeaconInterface) Address() common.Address { func (_m *VRFBeaconInterface) ExposeType(opts *bind.TransactOpts, arg0 vrf_beacon.VRFBeaconReportReport) (*types.Transaction, error) { ret := _m.Called(opts, arg0) + if len(ret) == 0 { + panic("no return value specified for ExposeType") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_beacon.VRFBeaconReportReport) (*types.Transaction, error)); ok { @@ -122,6 +138,10 @@ func (_m *VRFBeaconInterface) ExposeType(opts *bind.TransactOpts, arg0 vrf_beaco func (_m *VRFBeaconInterface) FilterBillingAccessControllerSet(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingAccessControllerSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterBillingAccessControllerSet") + } + var r0 *vrf_beacon.VRFBeaconBillingAccessControllerSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingAccessControllerSetIterator, error)); ok { @@ -148,6 +168,10 @@ func (_m *VRFBeaconInterface) FilterBillingAccessControllerSet(opts *bind.Filter func (_m *VRFBeaconInterface) FilterBillingSet(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterBillingSet") + } + var r0 *vrf_beacon.VRFBeaconBillingSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconBillingSetIterator, error)); ok { @@ -174,6 +198,10 @@ func (_m *VRFBeaconInterface) FilterBillingSet(opts *bind.FilterOpts) (*vrf_beac func (_m *VRFBeaconInterface) FilterConfigSet(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterConfigSet") + } + var r0 *vrf_beacon.VRFBeaconConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconConfigSetIterator, error)); ok { @@ -200,6 +228,10 @@ func (_m *VRFBeaconInterface) FilterConfigSet(opts *bind.FilterOpts) (*vrf_beaco func (_m *VRFBeaconInterface) FilterNewTransmission(opts *bind.FilterOpts, epochAndRound []*big.Int) (*vrf_beacon.VRFBeaconNewTransmissionIterator, error) { ret := _m.Called(opts, epochAndRound) + if len(ret) == 0 { + panic("no return value specified for FilterNewTransmission") + } + var r0 *vrf_beacon.VRFBeaconNewTransmissionIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_beacon.VRFBeaconNewTransmissionIterator, error)); ok { @@ -226,6 +258,10 @@ func (_m *VRFBeaconInterface) FilterNewTransmission(opts *bind.FilterOpts, epoch func (_m *VRFBeaconInterface) FilterOraclePaid(opts *bind.FilterOpts, transmitter []common.Address, payee []common.Address, linkToken []common.Address) (*vrf_beacon.VRFBeaconOraclePaidIterator, error) { ret := _m.Called(opts, transmitter, payee, linkToken) + if len(ret) == 0 { + panic("no return value specified for FilterOraclePaid") + } + var r0 *vrf_beacon.VRFBeaconOraclePaidIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconOraclePaidIterator, error)); ok { @@ -252,6 +288,10 @@ func (_m *VRFBeaconInterface) FilterOraclePaid(opts *bind.FilterOpts, transmitte func (_m *VRFBeaconInterface) FilterOutputsServed(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconOutputsServedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterOutputsServed") + } + var r0 *vrf_beacon.VRFBeaconOutputsServedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconOutputsServedIterator, error)); ok { @@ -278,6 +318,10 @@ func (_m *VRFBeaconInterface) FilterOutputsServed(opts *bind.FilterOpts) (*vrf_b func (_m *VRFBeaconInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferRequestedIterator, error)); ok { @@ -304,6 +348,10 @@ func (_m *VRFBeaconInterface) FilterOwnershipTransferRequested(opts *bind.Filter func (_m *VRFBeaconInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *vrf_beacon.VRFBeaconOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconOwnershipTransferredIterator, error)); ok { @@ -330,6 +378,10 @@ func (_m *VRFBeaconInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, func (_m *VRFBeaconInterface) FilterPayeeshipTransferRequested(opts *bind.FilterOpts, transmitter []common.Address, current []common.Address, proposed []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator, error) { ret := _m.Called(opts, transmitter, current, proposed) + if len(ret) == 0 { + panic("no return value specified for FilterPayeeshipTransferRequested") + } + var r0 *vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferRequestedIterator, error)); ok { @@ -356,6 +408,10 @@ func (_m *VRFBeaconInterface) FilterPayeeshipTransferRequested(opts *bind.Filter func (_m *VRFBeaconInterface) FilterPayeeshipTransferred(opts *bind.FilterOpts, transmitter []common.Address, previous []common.Address, current []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferredIterator, error) { ret := _m.Called(opts, transmitter, previous, current) + if len(ret) == 0 { + panic("no return value specified for FilterPayeeshipTransferred") + } + var r0 *vrf_beacon.VRFBeaconPayeeshipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address, []common.Address) (*vrf_beacon.VRFBeaconPayeeshipTransferredIterator, error)); ok { @@ -382,6 +438,10 @@ func (_m *VRFBeaconInterface) FilterPayeeshipTransferred(opts *bind.FilterOpts, func (_m *VRFBeaconInterface) FilterRandomWordsFulfilled(opts *bind.FilterOpts) (*vrf_beacon.VRFBeaconRandomWordsFulfilledIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterRandomWordsFulfilled") + } + var r0 *vrf_beacon.VRFBeaconRandomWordsFulfilledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_beacon.VRFBeaconRandomWordsFulfilledIterator, error)); ok { @@ -408,6 +468,10 @@ func (_m *VRFBeaconInterface) FilterRandomWordsFulfilled(opts *bind.FilterOpts) func (_m *VRFBeaconInterface) FilterRandomnessFulfillmentRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator, error) { ret := _m.Called(opts, requestID) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessFulfillmentRequested") + } + var r0 *vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequestedIterator, error)); ok { @@ -434,6 +498,10 @@ func (_m *VRFBeaconInterface) FilterRandomnessFulfillmentRequested(opts *bind.Fi func (_m *VRFBeaconInterface) FilterRandomnessRedeemed(opts *bind.FilterOpts, requestID []*big.Int, requester []common.Address) (*vrf_beacon.VRFBeaconRandomnessRedeemedIterator, error) { ret := _m.Called(opts, requestID, requester) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessRedeemed") + } + var r0 *vrf_beacon.VRFBeaconRandomnessRedeemedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*vrf_beacon.VRFBeaconRandomnessRedeemedIterator, error)); ok { @@ -460,6 +528,10 @@ func (_m *VRFBeaconInterface) FilterRandomnessRedeemed(opts *bind.FilterOpts, re func (_m *VRFBeaconInterface) FilterRandomnessRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_beacon.VRFBeaconRandomnessRequestedIterator, error) { ret := _m.Called(opts, requestID) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessRequested") + } + var r0 *vrf_beacon.VRFBeaconRandomnessRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_beacon.VRFBeaconRandomnessRequestedIterator, error)); ok { @@ -486,6 +558,10 @@ func (_m *VRFBeaconInterface) FilterRandomnessRequested(opts *bind.FilterOpts, r func (_m *VRFBeaconInterface) GetBilling(opts *bind.CallOpts) (vrf_beacon.GetBilling, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetBilling") + } + var r0 vrf_beacon.GetBilling var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_beacon.GetBilling, error)); ok { @@ -510,6 +586,10 @@ func (_m *VRFBeaconInterface) GetBilling(opts *bind.CallOpts) (vrf_beacon.GetBil func (_m *VRFBeaconInterface) GetBillingAccessController(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetBillingAccessController") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -536,6 +616,10 @@ func (_m *VRFBeaconInterface) GetBillingAccessController(opts *bind.CallOpts) (c func (_m *VRFBeaconInterface) ICoordinator(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for ICoordinator") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -562,6 +646,10 @@ func (_m *VRFBeaconInterface) ICoordinator(opts *bind.CallOpts) (common.Address, func (_m *VRFBeaconInterface) ILink(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for ILink") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -588,6 +676,10 @@ func (_m *VRFBeaconInterface) ILink(opts *bind.CallOpts) (common.Address, error) func (_m *VRFBeaconInterface) KeyGenerated(opts *bind.TransactOpts, kd vrf_beacon.KeyDataStructKeyData) (*types.Transaction, error) { ret := _m.Called(opts, kd) + if len(ret) == 0 { + panic("no return value specified for KeyGenerated") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_beacon.KeyDataStructKeyData) (*types.Transaction, error)); ok { @@ -614,6 +706,10 @@ func (_m *VRFBeaconInterface) KeyGenerated(opts *bind.TransactOpts, kd vrf_beaco func (_m *VRFBeaconInterface) LatestConfigDetails(opts *bind.CallOpts) (vrf_beacon.LatestConfigDetails, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestConfigDetails") + } + var r0 vrf_beacon.LatestConfigDetails var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_beacon.LatestConfigDetails, error)); ok { @@ -638,6 +734,10 @@ func (_m *VRFBeaconInterface) LatestConfigDetails(opts *bind.CallOpts) (vrf_beac func (_m *VRFBeaconInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (vrf_beacon.LatestConfigDigestAndEpoch, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestConfigDigestAndEpoch") + } + var r0 vrf_beacon.LatestConfigDigestAndEpoch var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_beacon.LatestConfigDigestAndEpoch, error)); ok { @@ -662,6 +762,10 @@ func (_m *VRFBeaconInterface) LatestConfigDigestAndEpoch(opts *bind.CallOpts) (v func (_m *VRFBeaconInterface) LinkAvailableForPayment(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LinkAvailableForPayment") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -688,6 +792,10 @@ func (_m *VRFBeaconInterface) LinkAvailableForPayment(opts *bind.CallOpts) (*big func (_m *VRFBeaconInterface) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for NUMCONFDELAYS") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -712,6 +820,10 @@ func (_m *VRFBeaconInterface) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) func (_m *VRFBeaconInterface) NewKeyRequested(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for NewKeyRequested") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -738,6 +850,10 @@ func (_m *VRFBeaconInterface) NewKeyRequested(opts *bind.TransactOpts) (*types.T func (_m *VRFBeaconInterface) OwedPayment(opts *bind.CallOpts, transmitterAddress common.Address) (*big.Int, error) { ret := _m.Called(opts, transmitterAddress) + if len(ret) == 0 { + panic("no return value specified for OwedPayment") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, common.Address) (*big.Int, error)); ok { @@ -764,6 +880,10 @@ func (_m *VRFBeaconInterface) OwedPayment(opts *bind.CallOpts, transmitterAddres func (_m *VRFBeaconInterface) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -790,6 +910,10 @@ func (_m *VRFBeaconInterface) Owner(opts *bind.CallOpts) (common.Address, error) func (_m *VRFBeaconInterface) ParseBillingAccessControllerSet(log types.Log) (*vrf_beacon.VRFBeaconBillingAccessControllerSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseBillingAccessControllerSet") + } + var r0 *vrf_beacon.VRFBeaconBillingAccessControllerSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconBillingAccessControllerSet, error)); ok { @@ -816,6 +940,10 @@ func (_m *VRFBeaconInterface) ParseBillingAccessControllerSet(log types.Log) (*v func (_m *VRFBeaconInterface) ParseBillingSet(log types.Log) (*vrf_beacon.VRFBeaconBillingSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseBillingSet") + } + var r0 *vrf_beacon.VRFBeaconBillingSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconBillingSet, error)); ok { @@ -842,6 +970,10 @@ func (_m *VRFBeaconInterface) ParseBillingSet(log types.Log) (*vrf_beacon.VRFBea func (_m *VRFBeaconInterface) ParseConfigSet(log types.Log) (*vrf_beacon.VRFBeaconConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseConfigSet") + } + var r0 *vrf_beacon.VRFBeaconConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconConfigSet, error)); ok { @@ -868,6 +1000,10 @@ func (_m *VRFBeaconInterface) ParseConfigSet(log types.Log) (*vrf_beacon.VRFBeac func (_m *VRFBeaconInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -894,6 +1030,10 @@ func (_m *VRFBeaconInterface) ParseLog(log types.Log) (generated.AbigenLog, erro func (_m *VRFBeaconInterface) ParseNewTransmission(log types.Log) (*vrf_beacon.VRFBeaconNewTransmission, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseNewTransmission") + } + var r0 *vrf_beacon.VRFBeaconNewTransmission var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconNewTransmission, error)); ok { @@ -920,6 +1060,10 @@ func (_m *VRFBeaconInterface) ParseNewTransmission(log types.Log) (*vrf_beacon.V func (_m *VRFBeaconInterface) ParseOraclePaid(log types.Log) (*vrf_beacon.VRFBeaconOraclePaid, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOraclePaid") + } + var r0 *vrf_beacon.VRFBeaconOraclePaid var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOraclePaid, error)); ok { @@ -946,6 +1090,10 @@ func (_m *VRFBeaconInterface) ParseOraclePaid(log types.Log) (*vrf_beacon.VRFBea func (_m *VRFBeaconInterface) ParseOutputsServed(log types.Log) (*vrf_beacon.VRFBeaconOutputsServed, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOutputsServed") + } + var r0 *vrf_beacon.VRFBeaconOutputsServed var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOutputsServed, error)); ok { @@ -972,6 +1120,10 @@ func (_m *VRFBeaconInterface) ParseOutputsServed(log types.Log) (*vrf_beacon.VRF func (_m *VRFBeaconInterface) ParseOwnershipTransferRequested(log types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *vrf_beacon.VRFBeaconOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferRequested, error)); ok { @@ -998,6 +1150,10 @@ func (_m *VRFBeaconInterface) ParseOwnershipTransferRequested(log types.Log) (*v func (_m *VRFBeaconInterface) ParseOwnershipTransferred(log types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *vrf_beacon.VRFBeaconOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconOwnershipTransferred, error)); ok { @@ -1024,6 +1180,10 @@ func (_m *VRFBeaconInterface) ParseOwnershipTransferred(log types.Log) (*vrf_bea func (_m *VRFBeaconInterface) ParsePayeeshipTransferRequested(log types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePayeeshipTransferRequested") + } + var r0 *vrf_beacon.VRFBeaconPayeeshipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferRequested, error)); ok { @@ -1050,6 +1210,10 @@ func (_m *VRFBeaconInterface) ParsePayeeshipTransferRequested(log types.Log) (*v func (_m *VRFBeaconInterface) ParsePayeeshipTransferred(log types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePayeeshipTransferred") + } + var r0 *vrf_beacon.VRFBeaconPayeeshipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconPayeeshipTransferred, error)); ok { @@ -1076,6 +1240,10 @@ func (_m *VRFBeaconInterface) ParsePayeeshipTransferred(log types.Log) (*vrf_bea func (_m *VRFBeaconInterface) ParseRandomWordsFulfilled(log types.Log) (*vrf_beacon.VRFBeaconRandomWordsFulfilled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomWordsFulfilled") + } + var r0 *vrf_beacon.VRFBeaconRandomWordsFulfilled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomWordsFulfilled, error)); ok { @@ -1102,6 +1270,10 @@ func (_m *VRFBeaconInterface) ParseRandomWordsFulfilled(log types.Log) (*vrf_bea func (_m *VRFBeaconInterface) ParseRandomnessFulfillmentRequested(log types.Log) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessFulfillmentRequested") + } + var r0 *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, error)); ok { @@ -1128,6 +1300,10 @@ func (_m *VRFBeaconInterface) ParseRandomnessFulfillmentRequested(log types.Log) func (_m *VRFBeaconInterface) ParseRandomnessRedeemed(log types.Log) (*vrf_beacon.VRFBeaconRandomnessRedeemed, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessRedeemed") + } + var r0 *vrf_beacon.VRFBeaconRandomnessRedeemed var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomnessRedeemed, error)); ok { @@ -1154,6 +1330,10 @@ func (_m *VRFBeaconInterface) ParseRandomnessRedeemed(log types.Log) (*vrf_beaco func (_m *VRFBeaconInterface) ParseRandomnessRequested(log types.Log) (*vrf_beacon.VRFBeaconRandomnessRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessRequested") + } + var r0 *vrf_beacon.VRFBeaconRandomnessRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_beacon.VRFBeaconRandomnessRequested, error)); ok { @@ -1180,6 +1360,10 @@ func (_m *VRFBeaconInterface) ParseRandomnessRequested(log types.Log) (*vrf_beac func (_m *VRFBeaconInterface) SKeyID(opts *bind.CallOpts) ([32]byte, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SKeyID") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { @@ -1206,6 +1390,10 @@ func (_m *VRFBeaconInterface) SKeyID(opts *bind.CallOpts) ([32]byte, error) { func (_m *VRFBeaconInterface) SKeyProvider(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SKeyProvider") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -1232,6 +1420,10 @@ func (_m *VRFBeaconInterface) SKeyProvider(opts *bind.CallOpts) (common.Address, func (_m *VRFBeaconInterface) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SProvingKeyHash") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { @@ -1258,6 +1450,10 @@ func (_m *VRFBeaconInterface) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, er func (_m *VRFBeaconInterface) SetBilling(opts *bind.TransactOpts, maximumGasPrice uint64, reasonableGasPrice uint64, observationPayment uint64, transmissionPayment uint64, accountingGas *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, maximumGasPrice, reasonableGasPrice, observationPayment, transmissionPayment, accountingGas) + if len(ret) == 0 { + panic("no return value specified for SetBilling") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, uint64, uint64, uint64, *big.Int) (*types.Transaction, error)); ok { @@ -1284,6 +1480,10 @@ func (_m *VRFBeaconInterface) SetBilling(opts *bind.TransactOpts, maximumGasPric func (_m *VRFBeaconInterface) SetBillingAccessController(opts *bind.TransactOpts, _billingAccessController common.Address) (*types.Transaction, error) { ret := _m.Called(opts, _billingAccessController) + if len(ret) == 0 { + panic("no return value specified for SetBillingAccessController") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1310,6 +1510,10 @@ func (_m *VRFBeaconInterface) SetBillingAccessController(opts *bind.TransactOpts func (_m *VRFBeaconInterface) SetConfig(opts *bind.TransactOpts, signers []common.Address, transmitters []common.Address, f uint8, onchainConfig []byte, offchainConfigVersion uint64, offchainConfig []byte) (*types.Transaction, error) { ret := _m.Called(opts, signers, transmitters, f, onchainConfig, offchainConfigVersion, offchainConfig) + if len(ret) == 0 { + panic("no return value specified for SetConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address, uint8, []byte, uint64, []byte) (*types.Transaction, error)); ok { @@ -1336,6 +1540,10 @@ func (_m *VRFBeaconInterface) SetConfig(opts *bind.TransactOpts, signers []commo func (_m *VRFBeaconInterface) SetPayees(opts *bind.TransactOpts, transmitters []common.Address, payees []common.Address) (*types.Transaction, error) { ret := _m.Called(opts, transmitters, payees) + if len(ret) == 0 { + panic("no return value specified for SetPayees") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []common.Address) (*types.Transaction, error)); ok { @@ -1362,6 +1570,10 @@ func (_m *VRFBeaconInterface) SetPayees(opts *bind.TransactOpts, transmitters [] func (_m *VRFBeaconInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1388,6 +1600,10 @@ func (_m *VRFBeaconInterface) TransferOwnership(opts *bind.TransactOpts, to comm func (_m *VRFBeaconInterface) TransferPayeeship(opts *bind.TransactOpts, transmitter common.Address, proposed common.Address) (*types.Transaction, error) { ret := _m.Called(opts, transmitter, proposed) + if len(ret) == 0 { + panic("no return value specified for TransferPayeeship") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, common.Address) (*types.Transaction, error)); ok { @@ -1414,6 +1630,10 @@ func (_m *VRFBeaconInterface) TransferPayeeship(opts *bind.TransactOpts, transmi func (_m *VRFBeaconInterface) Transmit(opts *bind.TransactOpts, reportContext [3][32]byte, report []byte, rs [][32]byte, ss [][32]byte, rawVs [32]byte) (*types.Transaction, error) { ret := _m.Called(opts, reportContext, report, rs, ss, rawVs) + if len(ret) == 0 { + panic("no return value specified for Transmit") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [3][32]byte, []byte, [][32]byte, [][32]byte, [32]byte) (*types.Transaction, error)); ok { @@ -1440,6 +1660,10 @@ func (_m *VRFBeaconInterface) Transmit(opts *bind.TransactOpts, reportContext [3 func (_m *VRFBeaconInterface) TypeAndVersion(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for TypeAndVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -1464,6 +1688,10 @@ func (_m *VRFBeaconInterface) TypeAndVersion(opts *bind.CallOpts) (string, error func (_m *VRFBeaconInterface) WatchBillingAccessControllerSet(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconBillingAccessControllerSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchBillingAccessControllerSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconBillingAccessControllerSet) (event.Subscription, error)); ok { @@ -1490,6 +1718,10 @@ func (_m *VRFBeaconInterface) WatchBillingAccessControllerSet(opts *bind.WatchOp func (_m *VRFBeaconInterface) WatchBillingSet(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconBillingSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchBillingSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconBillingSet) (event.Subscription, error)); ok { @@ -1516,6 +1748,10 @@ func (_m *VRFBeaconInterface) WatchBillingSet(opts *bind.WatchOpts, sink chan<- func (_m *VRFBeaconInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconConfigSet) (event.Subscription, error)); ok { @@ -1542,6 +1778,10 @@ func (_m *VRFBeaconInterface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- * func (_m *VRFBeaconInterface) WatchNewTransmission(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconNewTransmission, epochAndRound []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, epochAndRound) + if len(ret) == 0 { + panic("no return value specified for WatchNewTransmission") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconNewTransmission, []*big.Int) (event.Subscription, error)); ok { @@ -1568,6 +1808,10 @@ func (_m *VRFBeaconInterface) WatchNewTransmission(opts *bind.WatchOpts, sink ch func (_m *VRFBeaconInterface) WatchOraclePaid(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOraclePaid, transmitter []common.Address, payee []common.Address, linkToken []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, transmitter, payee, linkToken) + if len(ret) == 0 { + panic("no return value specified for WatchOraclePaid") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOraclePaid, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1594,6 +1838,10 @@ func (_m *VRFBeaconInterface) WatchOraclePaid(opts *bind.WatchOpts, sink chan<- func (_m *VRFBeaconInterface) WatchOutputsServed(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOutputsServed) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchOutputsServed") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOutputsServed) (event.Subscription, error)); ok { @@ -1620,6 +1868,10 @@ func (_m *VRFBeaconInterface) WatchOutputsServed(opts *bind.WatchOpts, sink chan func (_m *VRFBeaconInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1646,6 +1898,10 @@ func (_m *VRFBeaconInterface) WatchOwnershipTransferRequested(opts *bind.WatchOp func (_m *VRFBeaconInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1672,6 +1928,10 @@ func (_m *VRFBeaconInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, si func (_m *VRFBeaconInterface) WatchPayeeshipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconPayeeshipTransferRequested, transmitter []common.Address, current []common.Address, proposed []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, transmitter, current, proposed) + if len(ret) == 0 { + panic("no return value specified for WatchPayeeshipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconPayeeshipTransferRequested, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1698,6 +1958,10 @@ func (_m *VRFBeaconInterface) WatchPayeeshipTransferRequested(opts *bind.WatchOp func (_m *VRFBeaconInterface) WatchPayeeshipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconPayeeshipTransferred, transmitter []common.Address, previous []common.Address, current []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, transmitter, previous, current) + if len(ret) == 0 { + panic("no return value specified for WatchPayeeshipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconPayeeshipTransferred, []common.Address, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1724,6 +1988,10 @@ func (_m *VRFBeaconInterface) WatchPayeeshipTransferred(opts *bind.WatchOpts, si func (_m *VRFBeaconInterface) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomWordsFulfilled) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchRandomWordsFulfilled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomWordsFulfilled) (event.Subscription, error)); ok { @@ -1750,6 +2018,10 @@ func (_m *VRFBeaconInterface) WatchRandomWordsFulfilled(opts *bind.WatchOpts, si func (_m *VRFBeaconInterface) WatchRandomnessFulfillmentRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, requestID []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessFulfillmentRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessFulfillmentRequested, []*big.Int) (event.Subscription, error)); ok { @@ -1776,6 +2048,10 @@ func (_m *VRFBeaconInterface) WatchRandomnessFulfillmentRequested(opts *bind.Wat func (_m *VRFBeaconInterface) WatchRandomnessRedeemed(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomnessRedeemed, requestID []*big.Int, requester []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID, requester) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessRedeemed") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessRedeemed, []*big.Int, []common.Address) (event.Subscription, error)); ok { @@ -1802,6 +2078,10 @@ func (_m *VRFBeaconInterface) WatchRandomnessRedeemed(opts *bind.WatchOpts, sink func (_m *VRFBeaconInterface) WatchRandomnessRequested(opts *bind.WatchOpts, sink chan<- *vrf_beacon.VRFBeaconRandomnessRequested, requestID []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_beacon.VRFBeaconRandomnessRequested, []*big.Int) (event.Subscription, error)); ok { @@ -1828,6 +2108,10 @@ func (_m *VRFBeaconInterface) WatchRandomnessRequested(opts *bind.WatchOpts, sin func (_m *VRFBeaconInterface) WithdrawFunds(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, recipient, amount) + if len(ret) == 0 { + panic("no return value specified for WithdrawFunds") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -1854,6 +2138,10 @@ func (_m *VRFBeaconInterface) WithdrawFunds(opts *bind.TransactOpts, recipient c func (_m *VRFBeaconInterface) WithdrawPayment(opts *bind.TransactOpts, transmitter common.Address) (*types.Transaction, error) { ret := _m.Called(opts, transmitter) + if len(ret) == 0 { + panic("no return value specified for WithdrawPayment") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { 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 835702d136a..c0f85d67e06 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -23,6 +23,10 @@ type VRFBeaconCoordinator struct { func (_m *VRFBeaconCoordinator) GetConfirmationDelays(opts *bind.CallOpts) ([8]*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetConfirmationDelays") + } + var r0 [8]*big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([8]*big.Int, error)); ok { @@ -49,6 +53,10 @@ func (_m *VRFBeaconCoordinator) GetConfirmationDelays(opts *bind.CallOpts) ([8]* func (_m *VRFBeaconCoordinator) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for IBeaconPeriodBlocks") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -75,6 +83,10 @@ func (_m *VRFBeaconCoordinator) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.I func (_m *VRFBeaconCoordinator) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -101,6 +113,10 @@ func (_m *VRFBeaconCoordinator) ParseLog(log types.Log) (generated.AbigenLog, er func (_m *VRFBeaconCoordinator) SKeyID(opts *bind.CallOpts) ([32]byte, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SKeyID") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { @@ -127,6 +143,10 @@ func (_m *VRFBeaconCoordinator) SKeyID(opts *bind.CallOpts) ([32]byte, error) { func (_m *VRFBeaconCoordinator) SProvingKeyHash(opts *bind.CallOpts) ([32]byte, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SProvingKeyHash") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([32]byte, error)); ok { 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 d5e373f4bca..4b2155bb4e2 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ type VRFCoordinatorInterface struct { func (_m *VRFCoordinatorInterface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *VRFCoordinatorInterface) AcceptOwnership(opts *bind.TransactOpts) (*ty func (_m *VRFCoordinatorInterface) AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for AcceptSubscriptionOwnerTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int) (*types.Transaction, error)); ok { @@ -80,6 +88,10 @@ func (_m *VRFCoordinatorInterface) AcceptSubscriptionOwnerTransfer(opts *bind.Tr func (_m *VRFCoordinatorInterface) AddConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, consumer) + if len(ret) == 0 { + panic("no return value specified for AddConsumer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { @@ -106,6 +118,10 @@ func (_m *VRFCoordinatorInterface) AddConsumer(opts *bind.TransactOpts, subId *b func (_m *VRFCoordinatorInterface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -122,6 +138,10 @@ func (_m *VRFCoordinatorInterface) Address() common.Address { func (_m *VRFCoordinatorInterface) BatchTransferLink(opts *bind.TransactOpts, recipients []common.Address, paymentsInJuels []*big.Int) (*types.Transaction, error) { ret := _m.Called(opts, recipients, paymentsInJuels) + if len(ret) == 0 { + panic("no return value specified for BatchTransferLink") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []common.Address, []*big.Int) (*types.Transaction, error)); ok { @@ -148,6 +168,10 @@ func (_m *VRFCoordinatorInterface) BatchTransferLink(opts *bind.TransactOpts, re func (_m *VRFCoordinatorInterface) CancelSubscription(opts *bind.TransactOpts, subId *big.Int, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, to) + if len(ret) == 0 { + panic("no return value specified for CancelSubscription") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { @@ -174,6 +198,10 @@ func (_m *VRFCoordinatorInterface) CancelSubscription(opts *bind.TransactOpts, s func (_m *VRFCoordinatorInterface) CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for CreateSubscription") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -200,6 +228,10 @@ func (_m *VRFCoordinatorInterface) CreateSubscription(opts *bind.TransactOpts) ( func (_m *VRFCoordinatorInterface) DeregisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) { ret := _m.Called(opts, target) + if len(ret) == 0 { + panic("no return value specified for DeregisterMigratableCoordinator") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -226,6 +258,10 @@ func (_m *VRFCoordinatorInterface) DeregisterMigratableCoordinator(opts *bind.Tr func (_m *VRFCoordinatorInterface) FilterCallbackConfigSet(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCallbackConfigSet") + } + var r0 *vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCallbackConfigSetIterator, error)); ok { @@ -252,6 +288,10 @@ func (_m *VRFCoordinatorInterface) FilterCallbackConfigSet(opts *bind.FilterOpts func (_m *VRFCoordinatorInterface) FilterCoordinatorConfigSet(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCoordinatorConfigSet") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSetIterator, error)); ok { @@ -278,6 +318,10 @@ func (_m *VRFCoordinatorInterface) FilterCoordinatorConfigSet(opts *bind.FilterO func (_m *VRFCoordinatorInterface) FilterCoordinatorDeregistered(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCoordinatorDeregistered") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregisteredIterator, error)); ok { @@ -304,6 +348,10 @@ func (_m *VRFCoordinatorInterface) FilterCoordinatorDeregistered(opts *bind.Filt func (_m *VRFCoordinatorInterface) FilterCoordinatorRegistered(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterCoordinatorRegistered") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorCoordinatorRegisteredIterator, error)); ok { @@ -330,6 +378,10 @@ func (_m *VRFCoordinatorInterface) FilterCoordinatorRegistered(opts *bind.Filter func (_m *VRFCoordinatorInterface) FilterMigrationCompleted(opts *bind.FilterOpts, newVersion []uint8, subID []*big.Int) (*vrf_coordinator.VRFCoordinatorMigrationCompletedIterator, error) { ret := _m.Called(opts, newVersion, subID) + if len(ret) == 0 { + panic("no return value specified for FilterMigrationCompleted") + } + var r0 *vrf_coordinator.VRFCoordinatorMigrationCompletedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint8, []*big.Int) (*vrf_coordinator.VRFCoordinatorMigrationCompletedIterator, error)); ok { @@ -356,6 +408,10 @@ func (_m *VRFCoordinatorInterface) FilterMigrationCompleted(opts *bind.FilterOpt func (_m *VRFCoordinatorInterface) FilterOutputsServed(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorOutputsServedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterOutputsServed") + } + var r0 *vrf_coordinator.VRFCoordinatorOutputsServedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorOutputsServedIterator, error)); ok { @@ -382,6 +438,10 @@ func (_m *VRFCoordinatorInterface) FilterOutputsServed(opts *bind.FilterOpts) (* func (_m *VRFCoordinatorInterface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequestedIterator, error)); ok { @@ -408,6 +468,10 @@ func (_m *VRFCoordinatorInterface) FilterOwnershipTransferRequested(opts *bind.F func (_m *VRFCoordinatorInterface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_coordinator.VRFCoordinatorOwnershipTransferredIterator, error)); ok { @@ -434,6 +498,10 @@ func (_m *VRFCoordinatorInterface) FilterOwnershipTransferred(opts *bind.FilterO func (_m *VRFCoordinatorInterface) FilterPauseFlagChanged(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterPauseFlagChanged") + } + var r0 *vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorPauseFlagChangedIterator, error)); ok { @@ -460,6 +528,10 @@ func (_m *VRFCoordinatorInterface) FilterPauseFlagChanged(opts *bind.FilterOpts) func (_m *VRFCoordinatorInterface) FilterRandomWordsFulfilled(opts *bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterRandomWordsFulfilled") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilledIterator, error)); ok { @@ -486,6 +558,10 @@ func (_m *VRFCoordinatorInterface) FilterRandomWordsFulfilled(opts *bind.FilterO func (_m *VRFCoordinatorInterface) FilterRandomnessFulfillmentRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator, error) { ret := _m.Called(opts, requestID) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessFulfillmentRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequestedIterator, error)); ok { @@ -512,6 +588,10 @@ func (_m *VRFCoordinatorInterface) FilterRandomnessFulfillmentRequested(opts *bi func (_m *VRFCoordinatorInterface) FilterRandomnessRedeemed(opts *bind.FilterOpts, requestID []*big.Int, requester []common.Address) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator, error) { ret := _m.Called(opts, requestID, requester) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessRedeemed") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemedIterator, error)); ok { @@ -538,6 +618,10 @@ func (_m *VRFCoordinatorInterface) FilterRandomnessRedeemed(opts *bind.FilterOpt func (_m *VRFCoordinatorInterface) FilterRandomnessRequested(opts *bind.FilterOpts, requestID []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator, error) { ret := _m.Called(opts, requestID) + if len(ret) == 0 { + panic("no return value specified for FilterRandomnessRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorRandomnessRequestedIterator, error)); ok { @@ -564,6 +648,10 @@ func (_m *VRFCoordinatorInterface) FilterRandomnessRequested(opts *bind.FilterOp func (_m *VRFCoordinatorInterface) FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionCanceled") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceledIterator, error)); ok { @@ -590,6 +678,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionCanceled(opts *bind.FilterO func (_m *VRFCoordinatorInterface) FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionConsumerAdded") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAddedIterator, error)); ok { @@ -616,6 +708,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionConsumerAdded(opts *bind.Fi func (_m *VRFCoordinatorInterface) FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionConsumerRemoved") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemovedIterator, error)); ok { @@ -642,6 +738,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionConsumerRemoved(opts *bind. func (_m *VRFCoordinatorInterface) FilterSubscriptionCreated(opts *bind.FilterOpts, subId []*big.Int, owner []common.Address) (*vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator, error) { ret := _m.Called(opts, subId, owner) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionCreated") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int, []common.Address) (*vrf_coordinator.VRFCoordinatorSubscriptionCreatedIterator, error)); ok { @@ -668,6 +768,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionCreated(opts *bind.FilterOp func (_m *VRFCoordinatorInterface) FilterSubscriptionFunded(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionFunded") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionFundedIterator, error)); ok { @@ -694,6 +798,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionFunded(opts *bind.FilterOpt func (_m *VRFCoordinatorInterface) FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionOwnerTransferRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequestedIterator, error)); ok { @@ -720,6 +828,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionOwnerTransferRequested(opts func (_m *VRFCoordinatorInterface) FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionOwnerTransferred") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferredIterator, error)); ok { @@ -746,6 +858,10 @@ func (_m *VRFCoordinatorInterface) FilterSubscriptionOwnerTransferred(opts *bind func (_m *VRFCoordinatorInterface) GetCallbackMemo(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) { ret := _m.Called(opts, requestId) + if len(ret) == 0 { + panic("no return value specified for GetCallbackMemo") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) ([32]byte, error)); ok { @@ -772,6 +888,10 @@ func (_m *VRFCoordinatorInterface) GetCallbackMemo(opts *bind.CallOpts, requestI func (_m *VRFCoordinatorInterface) GetConfirmationDelays(opts *bind.CallOpts) ([8]*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetConfirmationDelays") + } + var r0 [8]*big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) ([8]*big.Int, error)); ok { @@ -798,6 +918,10 @@ func (_m *VRFCoordinatorInterface) GetConfirmationDelays(opts *bind.CallOpts) ([ func (_m *VRFCoordinatorInterface) GetFee(opts *bind.CallOpts, arg0 *big.Int, arg1 []byte) (*big.Int, error) { ret := _m.Called(opts, arg0, arg1) + if len(ret) == 0 { + panic("no return value specified for GetFee") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, []byte) (*big.Int, error)); ok { @@ -824,6 +948,10 @@ func (_m *VRFCoordinatorInterface) GetFee(opts *bind.CallOpts, arg0 *big.Int, ar func (_m *VRFCoordinatorInterface) GetFulfillmentFee(opts *bind.CallOpts, arg0 *big.Int, callbackGasLimit uint32, arguments []byte, arg3 []byte) (*big.Int, error) { ret := _m.Called(opts, arg0, callbackGasLimit, arguments, arg3) + if len(ret) == 0 { + panic("no return value specified for GetFulfillmentFee") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int, uint32, []byte, []byte) (*big.Int, error)); ok { @@ -850,6 +978,10 @@ func (_m *VRFCoordinatorInterface) GetFulfillmentFee(opts *bind.CallOpts, arg0 * func (_m *VRFCoordinatorInterface) GetSubscription(opts *bind.CallOpts, subId *big.Int) (vrf_coordinator.GetSubscription, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for GetSubscription") + } + var r0 vrf_coordinator.GetSubscription var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (vrf_coordinator.GetSubscription, error)); ok { @@ -874,6 +1006,10 @@ func (_m *VRFCoordinatorInterface) GetSubscription(opts *bind.CallOpts, subId *b func (_m *VRFCoordinatorInterface) GetSubscriptionLinkBalance(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetSubscriptionLinkBalance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -900,6 +1036,10 @@ func (_m *VRFCoordinatorInterface) GetSubscriptionLinkBalance(opts *bind.CallOpt func (_m *VRFCoordinatorInterface) IBeaconPeriodBlocks(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for IBeaconPeriodBlocks") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -926,6 +1066,10 @@ func (_m *VRFCoordinatorInterface) IBeaconPeriodBlocks(opts *bind.CallOpts) (*bi func (_m *VRFCoordinatorInterface) ILink(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for ILink") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -952,6 +1096,10 @@ func (_m *VRFCoordinatorInterface) ILink(opts *bind.CallOpts) (common.Address, e func (_m *VRFCoordinatorInterface) MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MAXCONSUMERS") + } + var r0 uint16 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint16, error)); ok { @@ -976,6 +1124,10 @@ func (_m *VRFCoordinatorInterface) MAXCONSUMERS(opts *bind.CallOpts) (uint16, er func (_m *VRFCoordinatorInterface) MAXNUMWORDS(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MAXNUMWORDS") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -1002,6 +1154,10 @@ func (_m *VRFCoordinatorInterface) MAXNUMWORDS(opts *bind.CallOpts) (*big.Int, e func (_m *VRFCoordinatorInterface) Migrate(opts *bind.TransactOpts, newCoordinator common.Address, encodedRequest []byte) (*types.Transaction, error) { ret := _m.Called(opts, newCoordinator, encodedRequest) + if len(ret) == 0 { + panic("no return value specified for Migrate") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, []byte) (*types.Transaction, error)); ok { @@ -1028,6 +1184,10 @@ func (_m *VRFCoordinatorInterface) Migrate(opts *bind.TransactOpts, newCoordinat func (_m *VRFCoordinatorInterface) MigrationVersion(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MigrationVersion") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -1052,6 +1212,10 @@ func (_m *VRFCoordinatorInterface) MigrationVersion(opts *bind.CallOpts) (uint8, func (_m *VRFCoordinatorInterface) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for NUMCONFDELAYS") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -1076,6 +1240,10 @@ func (_m *VRFCoordinatorInterface) NUMCONFDELAYS(opts *bind.CallOpts) (uint8, er func (_m *VRFCoordinatorInterface) OnMigration(opts *bind.CallOpts, arg0 []byte) error { ret := _m.Called(opts, arg0) + if len(ret) == 0 { + panic("no return value specified for OnMigration") + } + var r0 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, []byte) error); ok { r0 = rf(opts, arg0) @@ -1090,6 +1258,10 @@ func (_m *VRFCoordinatorInterface) OnMigration(opts *bind.CallOpts, arg0 []byte) func (_m *VRFCoordinatorInterface) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { ret := _m.Called(opts, arg0, amount, data) + if len(ret) == 0 { + panic("no return value specified for OnTokenTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -1116,6 +1288,10 @@ func (_m *VRFCoordinatorInterface) OnTokenTransfer(opts *bind.TransactOpts, arg0 func (_m *VRFCoordinatorInterface) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -1142,6 +1318,10 @@ func (_m *VRFCoordinatorInterface) Owner(opts *bind.CallOpts) (common.Address, e func (_m *VRFCoordinatorInterface) ParseCallbackConfigSet(log types.Log) (*vrf_coordinator.VRFCoordinatorCallbackConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCallbackConfigSet") + } + var r0 *vrf_coordinator.VRFCoordinatorCallbackConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCallbackConfigSet, error)); ok { @@ -1168,6 +1348,10 @@ func (_m *VRFCoordinatorInterface) ParseCallbackConfigSet(log types.Log) (*vrf_c func (_m *VRFCoordinatorInterface) ParseCoordinatorConfigSet(log types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCoordinatorConfigSet") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorConfigSet, error)); ok { @@ -1194,6 +1378,10 @@ func (_m *VRFCoordinatorInterface) ParseCoordinatorConfigSet(log types.Log) (*vr func (_m *VRFCoordinatorInterface) ParseCoordinatorDeregistered(log types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregistered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCoordinatorDeregistered") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorDeregistered, error)); ok { @@ -1220,6 +1408,10 @@ func (_m *VRFCoordinatorInterface) ParseCoordinatorDeregistered(log types.Log) ( func (_m *VRFCoordinatorInterface) ParseCoordinatorRegistered(log types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorRegistered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseCoordinatorRegistered") + } + var r0 *vrf_coordinator.VRFCoordinatorCoordinatorRegistered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorCoordinatorRegistered, error)); ok { @@ -1246,6 +1438,10 @@ func (_m *VRFCoordinatorInterface) ParseCoordinatorRegistered(log types.Log) (*v func (_m *VRFCoordinatorInterface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -1272,6 +1468,10 @@ func (_m *VRFCoordinatorInterface) ParseLog(log types.Log) (generated.AbigenLog, func (_m *VRFCoordinatorInterface) ParseMigrationCompleted(log types.Log) (*vrf_coordinator.VRFCoordinatorMigrationCompleted, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseMigrationCompleted") + } + var r0 *vrf_coordinator.VRFCoordinatorMigrationCompleted var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorMigrationCompleted, error)); ok { @@ -1298,6 +1498,10 @@ func (_m *VRFCoordinatorInterface) ParseMigrationCompleted(log types.Log) (*vrf_ func (_m *VRFCoordinatorInterface) ParseOutputsServed(log types.Log) (*vrf_coordinator.VRFCoordinatorOutputsServed, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOutputsServed") + } + var r0 *vrf_coordinator.VRFCoordinatorOutputsServed var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorOutputsServed, error)); ok { @@ -1324,6 +1528,10 @@ func (_m *VRFCoordinatorInterface) ParseOutputsServed(log types.Log) (*vrf_coord func (_m *VRFCoordinatorInterface) ParseOwnershipTransferRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, error)); ok { @@ -1350,6 +1558,10 @@ func (_m *VRFCoordinatorInterface) ParseOwnershipTransferRequested(log types.Log func (_m *VRFCoordinatorInterface) ParseOwnershipTransferred(log types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *vrf_coordinator.VRFCoordinatorOwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorOwnershipTransferred, error)); ok { @@ -1376,6 +1588,10 @@ func (_m *VRFCoordinatorInterface) ParseOwnershipTransferred(log types.Log) (*vr func (_m *VRFCoordinatorInterface) ParsePauseFlagChanged(log types.Log) (*vrf_coordinator.VRFCoordinatorPauseFlagChanged, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParsePauseFlagChanged") + } + var r0 *vrf_coordinator.VRFCoordinatorPauseFlagChanged var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorPauseFlagChanged, error)); ok { @@ -1402,6 +1618,10 @@ func (_m *VRFCoordinatorInterface) ParsePauseFlagChanged(log types.Log) (*vrf_co func (_m *VRFCoordinatorInterface) ParseRandomWordsFulfilled(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomWordsFulfilled") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomWordsFulfilled, error)); ok { @@ -1428,6 +1648,10 @@ func (_m *VRFCoordinatorInterface) ParseRandomWordsFulfilled(log types.Log) (*vr func (_m *VRFCoordinatorInterface) ParseRandomnessFulfillmentRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessFulfillmentRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, error)); ok { @@ -1454,6 +1678,10 @@ func (_m *VRFCoordinatorInterface) ParseRandomnessFulfillmentRequested(log types func (_m *VRFCoordinatorInterface) ParseRandomnessRedeemed(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemed, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessRedeemed") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessRedeemed var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRedeemed, error)); ok { @@ -1480,6 +1708,10 @@ func (_m *VRFCoordinatorInterface) ParseRandomnessRedeemed(log types.Log) (*vrf_ func (_m *VRFCoordinatorInterface) ParseRandomnessRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomnessRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorRandomnessRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorRandomnessRequested, error)); ok { @@ -1506,6 +1738,10 @@ func (_m *VRFCoordinatorInterface) ParseRandomnessRequested(log types.Log) (*vrf func (_m *VRFCoordinatorInterface) ParseSubscriptionCanceled(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionCanceled") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCanceled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCanceled, error)); ok { @@ -1532,6 +1768,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionCanceled(log types.Log) (*vr func (_m *VRFCoordinatorInterface) ParseSubscriptionConsumerAdded(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionConsumerAdded") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, error)); ok { @@ -1558,6 +1798,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionConsumerAdded(log types.Log) func (_m *VRFCoordinatorInterface) ParseSubscriptionConsumerRemoved(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionConsumerRemoved") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, error)); ok { @@ -1584,6 +1828,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionConsumerRemoved(log types.Lo func (_m *VRFCoordinatorInterface) ParseSubscriptionCreated(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCreated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionCreated") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionCreated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionCreated, error)); ok { @@ -1610,6 +1858,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionCreated(log types.Log) (*vrf func (_m *VRFCoordinatorInterface) ParseSubscriptionFunded(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionFunded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionFunded") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionFunded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionFunded, error)); ok { @@ -1636,6 +1888,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionFunded(log types.Log) (*vrf_ func (_m *VRFCoordinatorInterface) ParseSubscriptionOwnerTransferRequested(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionOwnerTransferRequested") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, error)); ok { @@ -1662,6 +1918,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionOwnerTransferRequested(log t func (_m *VRFCoordinatorInterface) ParseSubscriptionOwnerTransferred(log types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionOwnerTransferred") + } + var r0 *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, error)); ok { @@ -1688,6 +1948,10 @@ func (_m *VRFCoordinatorInterface) ParseSubscriptionOwnerTransferred(log types.L func (_m *VRFCoordinatorInterface) ProcessVRFOutputs(opts *bind.TransactOpts, vrfOutputs []vrf_coordinator.VRFBeaconTypesVRFOutput, juelsPerFeeCoin *big.Int, reasonableGasPrice uint64, blockHeight uint64) (*types.Transaction, error) { ret := _m.Called(opts, vrfOutputs, juelsPerFeeCoin, reasonableGasPrice, blockHeight) + if len(ret) == 0 { + panic("no return value specified for ProcessVRFOutputs") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, []vrf_coordinator.VRFBeaconTypesVRFOutput, *big.Int, uint64, uint64) (*types.Transaction, error)); ok { @@ -1714,6 +1978,10 @@ func (_m *VRFCoordinatorInterface) ProcessVRFOutputs(opts *bind.TransactOpts, vr func (_m *VRFCoordinatorInterface) RedeemRandomness(opts *bind.TransactOpts, subID *big.Int, requestID *big.Int, arg2 []byte) (*types.Transaction, error) { ret := _m.Called(opts, subID, requestID, arg2) + if len(ret) == 0 { + panic("no return value specified for RedeemRandomness") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -1740,6 +2008,10 @@ func (_m *VRFCoordinatorInterface) RedeemRandomness(opts *bind.TransactOpts, sub func (_m *VRFCoordinatorInterface) RegisterMigratableCoordinator(opts *bind.TransactOpts, target common.Address) (*types.Transaction, error) { ret := _m.Called(opts, target) + if len(ret) == 0 { + panic("no return value specified for RegisterMigratableCoordinator") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1766,6 +2038,10 @@ func (_m *VRFCoordinatorInterface) RegisterMigratableCoordinator(opts *bind.Tran func (_m *VRFCoordinatorInterface) RemoveConsumer(opts *bind.TransactOpts, subId *big.Int, consumer common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, consumer) + if len(ret) == 0 { + panic("no return value specified for RemoveConsumer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { @@ -1792,6 +2068,10 @@ func (_m *VRFCoordinatorInterface) RemoveConsumer(opts *bind.TransactOpts, subId func (_m *VRFCoordinatorInterface) RequestRandomness(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, arg3 []byte) (*types.Transaction, error) { ret := _m.Called(opts, subID, numWords, confDelay, arg3) + if len(ret) == 0 { + panic("no return value specified for RequestRandomness") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint16, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -1818,6 +2098,10 @@ func (_m *VRFCoordinatorInterface) RequestRandomness(opts *bind.TransactOpts, su func (_m *VRFCoordinatorInterface) RequestRandomnessFulfillment(opts *bind.TransactOpts, subID *big.Int, numWords uint16, confDelay *big.Int, callbackGasLimit uint32, arguments []byte, arg5 []byte) (*types.Transaction, error) { ret := _m.Called(opts, subID, numWords, confDelay, callbackGasLimit, arguments, arg5) + if len(ret) == 0 { + panic("no return value specified for RequestRandomnessFulfillment") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, uint16, *big.Int, uint32, []byte, []byte) (*types.Transaction, error)); ok { @@ -1844,6 +2128,10 @@ func (_m *VRFCoordinatorInterface) RequestRandomnessFulfillment(opts *bind.Trans func (_m *VRFCoordinatorInterface) RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId *big.Int, newOwner common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, newOwner) + if len(ret) == 0 { + panic("no return value specified for RequestSubscriptionOwnerTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, *big.Int, common.Address) (*types.Transaction, error)); ok { @@ -1870,6 +2158,10 @@ func (_m *VRFCoordinatorInterface) RequestSubscriptionOwnerTransfer(opts *bind.T func (_m *VRFCoordinatorInterface) SCallbackConfig(opts *bind.CallOpts) (vrf_coordinator.SCallbackConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SCallbackConfig") + } + var r0 vrf_coordinator.SCallbackConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_coordinator.SCallbackConfig, error)); ok { @@ -1894,6 +2186,10 @@ func (_m *VRFCoordinatorInterface) SCallbackConfig(opts *bind.CallOpts) (vrf_coo func (_m *VRFCoordinatorInterface) SCoordinatorConfig(opts *bind.CallOpts) (vrf_coordinator.SCoordinatorConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SCoordinatorConfig") + } + var r0 vrf_coordinator.SCoordinatorConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_coordinator.SCoordinatorConfig, error)); ok { @@ -1918,6 +2214,10 @@ func (_m *VRFCoordinatorInterface) SCoordinatorConfig(opts *bind.CallOpts) (vrf_ func (_m *VRFCoordinatorInterface) SPendingRequests(opts *bind.CallOpts, arg0 *big.Int) (vrf_coordinator.SPendingRequests, error) { ret := _m.Called(opts, arg0) + if len(ret) == 0 { + panic("no return value specified for SPendingRequests") + } + var r0 vrf_coordinator.SPendingRequests var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (vrf_coordinator.SPendingRequests, error)); ok { @@ -1942,6 +2242,10 @@ func (_m *VRFCoordinatorInterface) SPendingRequests(opts *bind.CallOpts, arg0 *b func (_m *VRFCoordinatorInterface) SProducer(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for SProducer") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -1968,6 +2272,10 @@ func (_m *VRFCoordinatorInterface) SProducer(opts *bind.CallOpts) (common.Addres func (_m *VRFCoordinatorInterface) SetCallbackConfig(opts *bind.TransactOpts, config vrf_coordinator.VRFCoordinatorCallbackConfig) (*types.Transaction, error) { ret := _m.Called(opts, config) + if len(ret) == 0 { + panic("no return value specified for SetCallbackConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_coordinator.VRFCoordinatorCallbackConfig) (*types.Transaction, error)); ok { @@ -1994,6 +2302,10 @@ func (_m *VRFCoordinatorInterface) SetCallbackConfig(opts *bind.TransactOpts, co func (_m *VRFCoordinatorInterface) SetConfirmationDelays(opts *bind.TransactOpts, confDelays [8]*big.Int) (*types.Transaction, error) { ret := _m.Called(opts, confDelays) + if len(ret) == 0 { + panic("no return value specified for SetConfirmationDelays") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [8]*big.Int) (*types.Transaction, error)); ok { @@ -2020,6 +2332,10 @@ func (_m *VRFCoordinatorInterface) SetConfirmationDelays(opts *bind.TransactOpts func (_m *VRFCoordinatorInterface) SetCoordinatorConfig(opts *bind.TransactOpts, coordinatorConfig vrf_coordinator.VRFBeaconTypesCoordinatorConfig) (*types.Transaction, error) { ret := _m.Called(opts, coordinatorConfig) + if len(ret) == 0 { + panic("no return value specified for SetCoordinatorConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_coordinator.VRFBeaconTypesCoordinatorConfig) (*types.Transaction, error)); ok { @@ -2046,6 +2362,10 @@ func (_m *VRFCoordinatorInterface) SetCoordinatorConfig(opts *bind.TransactOpts, func (_m *VRFCoordinatorInterface) SetPauseFlag(opts *bind.TransactOpts, pause bool) (*types.Transaction, error) { ret := _m.Called(opts, pause) + if len(ret) == 0 { + panic("no return value specified for SetPauseFlag") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, bool) (*types.Transaction, error)); ok { @@ -2072,6 +2392,10 @@ func (_m *VRFCoordinatorInterface) SetPauseFlag(opts *bind.TransactOpts, pause b func (_m *VRFCoordinatorInterface) SetProducer(opts *bind.TransactOpts, producer common.Address) (*types.Transaction, error) { ret := _m.Called(opts, producer) + if len(ret) == 0 { + panic("no return value specified for SetProducer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -2098,6 +2422,10 @@ func (_m *VRFCoordinatorInterface) SetProducer(opts *bind.TransactOpts, producer func (_m *VRFCoordinatorInterface) TransferLink(opts *bind.TransactOpts, recipient common.Address, juelsAmount *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, recipient, juelsAmount) + if len(ret) == 0 { + panic("no return value specified for TransferLink") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -2124,6 +2452,10 @@ func (_m *VRFCoordinatorInterface) TransferLink(opts *bind.TransactOpts, recipie func (_m *VRFCoordinatorInterface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -2150,6 +2482,10 @@ func (_m *VRFCoordinatorInterface) TransferOwnership(opts *bind.TransactOpts, to func (_m *VRFCoordinatorInterface) WatchCallbackConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCallbackConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCallbackConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCallbackConfigSet) (event.Subscription, error)); ok { @@ -2176,6 +2512,10 @@ func (_m *VRFCoordinatorInterface) WatchCallbackConfigSet(opts *bind.WatchOpts, func (_m *VRFCoordinatorInterface) WatchCoordinatorConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCoordinatorConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorConfigSet) (event.Subscription, error)); ok { @@ -2202,6 +2542,10 @@ func (_m *VRFCoordinatorInterface) WatchCoordinatorConfigSet(opts *bind.WatchOpt func (_m *VRFCoordinatorInterface) WatchCoordinatorDeregistered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCoordinatorDeregistered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorDeregistered) (event.Subscription, error)); ok { @@ -2228,6 +2572,10 @@ func (_m *VRFCoordinatorInterface) WatchCoordinatorDeregistered(opts *bind.Watch func (_m *VRFCoordinatorInterface) WatchCoordinatorRegistered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorCoordinatorRegistered) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchCoordinatorRegistered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorCoordinatorRegistered) (event.Subscription, error)); ok { @@ -2254,6 +2602,10 @@ func (_m *VRFCoordinatorInterface) WatchCoordinatorRegistered(opts *bind.WatchOp func (_m *VRFCoordinatorInterface) WatchMigrationCompleted(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorMigrationCompleted, newVersion []uint8, subID []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, newVersion, subID) + if len(ret) == 0 { + panic("no return value specified for WatchMigrationCompleted") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorMigrationCompleted, []uint8, []*big.Int) (event.Subscription, error)); ok { @@ -2280,6 +2632,10 @@ func (_m *VRFCoordinatorInterface) WatchMigrationCompleted(opts *bind.WatchOpts, func (_m *VRFCoordinatorInterface) WatchOutputsServed(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorOutputsServed) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchOutputsServed") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOutputsServed) (event.Subscription, error)); ok { @@ -2306,6 +2662,10 @@ func (_m *VRFCoordinatorInterface) WatchOutputsServed(opts *bind.WatchOpts, sink func (_m *VRFCoordinatorInterface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -2332,6 +2692,10 @@ func (_m *VRFCoordinatorInterface) WatchOwnershipTransferRequested(opts *bind.Wa func (_m *VRFCoordinatorInterface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorOwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -2358,6 +2722,10 @@ func (_m *VRFCoordinatorInterface) WatchOwnershipTransferred(opts *bind.WatchOpt func (_m *VRFCoordinatorInterface) WatchPauseFlagChanged(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorPauseFlagChanged) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchPauseFlagChanged") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorPauseFlagChanged) (event.Subscription, error)); ok { @@ -2384,6 +2752,10 @@ func (_m *VRFCoordinatorInterface) WatchPauseFlagChanged(opts *bind.WatchOpts, s func (_m *VRFCoordinatorInterface) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchRandomWordsFulfilled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomWordsFulfilled) (event.Subscription, error)); ok { @@ -2410,6 +2782,10 @@ func (_m *VRFCoordinatorInterface) WatchRandomWordsFulfilled(opts *bind.WatchOpt func (_m *VRFCoordinatorInterface) WatchRandomnessFulfillmentRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, requestID []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessFulfillmentRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessFulfillmentRequested, []*big.Int) (event.Subscription, error)); ok { @@ -2436,6 +2812,10 @@ func (_m *VRFCoordinatorInterface) WatchRandomnessFulfillmentRequested(opts *bin func (_m *VRFCoordinatorInterface) WatchRandomnessRedeemed(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomnessRedeemed, requestID []*big.Int, requester []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID, requester) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessRedeemed") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessRedeemed, []*big.Int, []common.Address) (event.Subscription, error)); ok { @@ -2462,6 +2842,10 @@ func (_m *VRFCoordinatorInterface) WatchRandomnessRedeemed(opts *bind.WatchOpts, func (_m *VRFCoordinatorInterface) WatchRandomnessRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorRandomnessRequested, requestID []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, requestID) + if len(ret) == 0 { + panic("no return value specified for WatchRandomnessRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorRandomnessRequested, []*big.Int) (event.Subscription, error)); ok { @@ -2488,6 +2872,10 @@ func (_m *VRFCoordinatorInterface) WatchRandomnessRequested(opts *bind.WatchOpts func (_m *VRFCoordinatorInterface) WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCanceled, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionCanceled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCanceled, []*big.Int) (event.Subscription, error)); ok { @@ -2514,6 +2902,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionCanceled(opts *bind.WatchOpt func (_m *VRFCoordinatorInterface) WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionConsumerAdded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerAdded, []*big.Int) (event.Subscription, error)); ok { @@ -2540,6 +2932,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionConsumerAdded(opts *bind.Wat func (_m *VRFCoordinatorInterface) WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionConsumerRemoved") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionConsumerRemoved, []*big.Int) (event.Subscription, error)); ok { @@ -2566,6 +2962,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionConsumerRemoved(opts *bind.W func (_m *VRFCoordinatorInterface) WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCreated, subId []*big.Int, owner []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, subId, owner) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionCreated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionCreated, []*big.Int, []common.Address) (event.Subscription, error)); ok { @@ -2592,6 +2992,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionCreated(opts *bind.WatchOpts func (_m *VRFCoordinatorInterface) WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionFunded, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionFunded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionFunded, []*big.Int) (event.Subscription, error)); ok { @@ -2618,6 +3022,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionFunded(opts *bind.WatchOpts, func (_m *VRFCoordinatorInterface) WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionOwnerTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferRequested, []*big.Int) (event.Subscription, error)); ok { @@ -2644,6 +3052,10 @@ func (_m *VRFCoordinatorInterface) WatchSubscriptionOwnerTransferRequested(opts func (_m *VRFCoordinatorInterface) WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, subId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionOwnerTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator.VRFCoordinatorSubscriptionOwnerTransferred, []*big.Int) (event.Subscription, error)); ok { diff --git a/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go b/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go index 6a4b97b9f0e..57aaf1c5e03 100644 --- a/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/coordinator/ocr_cache_test.go @@ -11,7 +11,7 @@ import ( func TestNewCache(t *testing.T) { b := NewBlockCache[int](time.Second) - assert.Equal(t, time.Second, time.Duration(b.evictionWindow), "must set correct blockEvictionWindow") + assert.Equal(t, time.Second, b.evictionWindow, "must set correct blockEvictionWindow") } func TestCache(t *testing.T) { @@ -30,7 +30,7 @@ func TestCache(t *testing.T) { {Key: common.HexToHash("0x4"), Value: 5}, } - c := NewBlockCache[int](time.Second * 100) + c := NewBlockCache[int](100 * time.Second) // Populate cache with ordered items. for i, test := range tests { @@ -79,7 +79,7 @@ func TestCache(t *testing.T) { {Key: common.HexToHash("0x1"), Value: 5}, } - c := NewBlockCache[int](time.Duration(time.Second * 100)) + c := NewBlockCache[int](100 * time.Second) // Populate cache with items. for i, test := range tests { @@ -119,7 +119,7 @@ func TestCache(t *testing.T) { {Key: common.HexToHash("0x0"), Value: 5}, } - c := NewBlockCache[int](time.Duration(time.Second * 100)) + c := NewBlockCache[int](100 * time.Second) // Populate cache with items. for i, test := range tests { 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 e93824283ba..4a01ee7904f 100644 --- a/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go +++ b/core/services/ocr2/plugins/ocr2vrf/internal/ocr2vrf_integration_test.go @@ -14,7 +14,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/hashicorp/consul/sdk/freeport" @@ -31,8 +30,12 @@ import ( "github.com/smartcontractkit/chainlink-vrf/ocr2vrf" ocr2vrftypes "github.com/smartcontractkit/chainlink-vrf/types" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + "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/gethwrappers/generated/authorized_forwarder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_v3_aggregator_contract" @@ -53,8 +56,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ocr2vrfUniverse struct { @@ -133,13 +134,13 @@ func setupOCR2VRFContracts( require.NoError(t, err) b.Commit() - require.NoError(t, utils.JustError(coordinator.SetCallbackConfig(owner, vrf_wrapper.VRFCoordinatorCallbackConfig{ + require.NoError(t, commonutils.JustError(coordinator.SetCallbackConfig(owner, vrf_wrapper.VRFCoordinatorCallbackConfig{ MaxCallbackGasLimit: 2.5e6, MaxCallbackArgumentsLength: 160, // 5 EVM words }))) b.Commit() - require.NoError(t, utils.JustError(coordinator.SetCoordinatorConfig(owner, vrf_wrapper.VRFBeaconTypesCoordinatorConfig{ + require.NoError(t, commonutils.JustError(coordinator.SetCoordinatorConfig(owner, vrf_wrapper.VRFBeaconTypesCoordinatorConfig{ RedeemableRequestGasOverhead: 50_000, CallbackRequestGasOverhead: 50_000, StalenessSeconds: 60, @@ -163,7 +164,7 @@ func setupOCR2VRFContracts( b.Commit() // Set up coordinator subscription for billing. - require.NoError(t, utils.JustError(coordinator.CreateSubscription(owner))) + require.NoError(t, commonutils.JustError(coordinator.CreateSubscription(owner))) b.Commit() fopts := &bind.FilterOpts{} @@ -174,13 +175,13 @@ func setupOCR2VRFContracts( require.True(t, subscriptionIterator.Next()) subID := subscriptionIterator.Event.SubId - require.NoError(t, utils.JustError(coordinator.AddConsumer(owner, subID, consumerAddress))) + require.NoError(t, commonutils.JustError(coordinator.AddConsumer(owner, subID, consumerAddress))) b.Commit() - require.NoError(t, utils.JustError(coordinator.AddConsumer(owner, subID, loadTestConsumerAddress))) + require.NoError(t, commonutils.JustError(coordinator.AddConsumer(owner, subID, loadTestConsumerAddress))) b.Commit() data, err := utils.ABIEncode(`[{"type":"uint256"}]`, subID) require.NoError(t, err) - require.NoError(t, utils.JustError(link.TransferAndCall(owner, coordinatorAddress, big.NewInt(5e18), data))) + require.NoError(t, commonutils.JustError(link.TransferAndCall(owner, coordinatorAddress, big.NewInt(5e18), data))) b.Commit() _, err = dkg.AddClient(owner, keyID, beaconAddress) @@ -232,10 +233,9 @@ func setupNodeOCR2( c.Feature.LogPoller = ptr(true) c.P2P.PeerID = ptr(p2pKey.PeerID()) - c.P2P.V1.Enabled = ptr(false) c.P2P.V2.Enabled = ptr(true) - c.P2P.V2.DeltaDial = models.MustNewDuration(500 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(5 * time.Second) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(500 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(5 * time.Second) c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", port)} if len(p2pV2Bootstrappers) > 0 { c.P2P.V2.DefaultBootstrappers = &p2pV2Bootstrappers @@ -244,10 +244,10 @@ func setupNodeOCR2( c.OCR.Enabled = ptr(false) c.OCR2.Enabled = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(500 * time.Millisecond) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(500 * time.Millisecond) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](3_500_000) c.EVM[0].Transactions.ForwardersEnabled = &useForwarders - c.OCR2.ContractPollInterval = models.MustNewDuration(10 * time.Second) + c.OCR2.ContractPollInterval = commonconfig.MustNewDuration(10 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, b, p2pKey) @@ -286,7 +286,7 @@ func setupNodeOCR2( // Add the forwarder to the node's forwarder manager. forwarderORM := forwarders.NewORM(app.GetSqlxDB(), logger.TestLogger(t), config.Database()) - chainID := utils.Big(*b.Blockchain().Config().ChainID) + chainID := ubig.Big(*b.Blockchain().Config().ChainID) _, err = forwarderORM.CreateForwarder(faddr, chainID) require.NoError(t, err) effectiveTransmitter = faddr @@ -299,7 +299,7 @@ func setupNodeOCR2( n, err := b.NonceAt(testutils.Context(t), owner.From, nil) require.NoError(t, err) - tx := types.NewTransaction( + tx := cltest.NewLegacyTransaction( n, k.Address, assets.Ether(1).ToInt(), 21000, @@ -663,7 +663,7 @@ linkEthFeedAddress = "%s" // Fund the payee with some ETH. n, err2 := uni.backend.NonceAt(testutils.Context(t), uni.owner.From, nil) require.NoError(t, err2) - tx := types.NewTransaction( + tx := cltest.NewLegacyTransaction( n, payeeTransactor.From, assets.Ether(1).ToInt(), 21000, diff --git a/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go b/core/services/ocr2/plugins/promwrapper/mocks/prometheus_backend.go index ba97eda30b1..418cb276011 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/core/services/ocr2/plugins/promwrapper/plugin.go b/core/services/ocr2/plugins/promwrapper/plugin.go index a409b5ba86c..58d8e171f39 100644 --- a/core/services/ocr2/plugins/promwrapper/plugin.go +++ b/core/services/ocr2/plugins/promwrapper/plugin.go @@ -39,7 +39,7 @@ var ( labels = []string{"chainType", "chainID", "plugin", "oracleID", "configDigest"} getLabelsValues = func(p *promPlugin, t types.ReportTimestamp) []string { return []string{ - string(p.chainType), // chainType + p.chainType, // chainType p.chainID.String(), // chainID p.name, // plugin p.oracleID, // oracleID @@ -333,11 +333,11 @@ func (p *promPlugin) Close() error { defer func() { duration := float64(time.Now().UTC().Sub(start)) labelValues := []string{ - string(p.chainType), // chainType - p.chainID.String(), // chainID - p.name, // plugin - p.oracleID, // oracleID - p.configDigest, // configDigest + p.chainType, // chainType + p.chainID.String(), // chainID + p.name, // plugin + p.oracleID, // oracleID + p.configDigest, // configDigest } p.prometheusBackend.SetCloseDuration(labelValues, duration) }() diff --git a/core/services/ocr2/plugins/s4/integration_test.go b/core/services/ocr2/plugins/s4/integration_test.go index 54f0f02ad98..8efe38f8e2d 100644 --- a/core/services/ocr2/plugins/s4/integration_test.go +++ b/core/services/ocr2/plugins/s4/integration_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "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/pgtest" @@ -16,7 +17,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/s4" "github.com/smartcontractkit/chainlink/v2/core/services/pg" s4_svc "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -357,14 +357,14 @@ func TestS4Integration_RandomState(t *testing.T) { type user struct { privateKey *ecdsa.PrivateKey - address *utils.Big + address *big.Big } nUsers := 100 users := make([]user, nUsers) for i := 0; i < nUsers; i++ { pk, addr := testutils.NewPrivateKeyAndAddress(t) - users[i] = user{pk, utils.NewBig(addr.Big())} + users[i] = user{pk, big.New(addr.Big())} } // generating test records diff --git a/core/services/ocr2/plugins/s4/messages.go b/core/services/ocr2/plugins/s4/messages.go index 8f3a64f4e23..c9695d2db76 100644 --- a/core/services/ocr2/plugins/s4/messages.go +++ b/core/services/ocr2/plugins/s4/messages.go @@ -4,8 +4,8 @@ import ( "bytes" "math/big" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum/common" "google.golang.org/protobuf/proto" @@ -58,8 +58,8 @@ func UnmarshalRows(data []byte) ([]*Row, error) { return rows.Rows, nil } -func UnmarshalAddress(address []byte) *utils.Big { - return utils.NewBig(new(big.Int).SetBytes(address)) +func UnmarshalAddress(address []byte) *ubig.Big { + return ubig.New(new(big.Int).SetBytes(address)) } func (row *Row) VerifySignature() error { diff --git a/core/services/ocr2/plugins/s4/plugin.go b/core/services/ocr2/plugins/s4/plugin.go index 68bd9fd2142..2b55ebf3cc5 100644 --- a/core/services/ocr2/plugins/s4/plugin.go +++ b/core/services/ocr2/plugins/s4/plugin.go @@ -4,13 +4,28 @@ import ( "context" "time" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/s4" +) + +var ( + promStoragePluginUpdatesCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "storage_plugin_updates", + Help: "Number of storage updates fetched from other nodes", + }, []string{}) + + promStorageTotalByteSize = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Name: "storage_total_byte_size", + Help: "Current byte size of data stored in S4", + }, []string{}) ) type plugin struct { @@ -59,6 +74,7 @@ func (c *plugin) Query(ctx context.Context, ts types.ReportTimestamp) (types.Que return nil, errors.Wrap(err, "failed to GetVersions in Query()") } + var storageTotalByteSize uint64 rows := make([]*SnapshotRow, len(snapshot)) for i, v := range snapshot { rows[i] = &SnapshotRow{ @@ -66,6 +82,8 @@ func (c *plugin) Query(ctx context.Context, ts types.ReportTimestamp) (types.Que Slotid: uint32(v.SlotId), Version: v.Version, } + + storageTotalByteSize += v.PayloadSize } queryBytes, err := MarshalQuery(rows, c.addressRange) @@ -76,6 +94,8 @@ func (c *plugin) Query(ctx context.Context, ts types.ReportTimestamp) (types.Que promReportingPluginsQueryRowsCount.WithLabelValues(c.config.ProductName).Set(float64(len(rows))) promReportingPluginsQueryByteSize.WithLabelValues(c.config.ProductName).Set(float64(len(queryBytes))) + promStorageTotalByteSize.WithLabelValues().Set(float64(storageTotalByteSize)) + c.addressRange.Advance() c.logger.Debug("S4StorageReporting Query", commontypes.LogFields{ @@ -123,7 +143,7 @@ func (c *plugin) Observation(ctx context.Context, ts types.ReportTimestamp, quer c.logger.Error("ORM GetSnapshot error", commontypes.LogFields{"err": err}) } else { type rkey struct { - address *utils.Big + address *big.Big slotID uint } @@ -147,9 +167,9 @@ func (c *plugin) Observation(ctx context.Context, ts types.ReportTimestamp, quer if !sr.Confirmed { continue } - k := key{address: sr.Address.String(), slotID: uint(sr.SlotId)} + k := key{address: sr.Address.String(), slotID: sr.SlotId} if _, ok := snapshotVersionsMap[k]; ok { - toBeAdded = append(toBeAdded, rkey{address: sr.Address, slotID: uint(sr.SlotId)}) + toBeAdded = append(toBeAdded, rkey{address: sr.Address, slotID: sr.SlotId}) if len(toBeAdded) == maxRemainingRows { break } @@ -268,6 +288,7 @@ func (c *plugin) ShouldAcceptFinalizedReport(ctx context.Context, ts types.Repor c.logger.Error("Failed to Update a row in ShouldAcceptFinalizedReport()", commontypes.LogFields{"err": err}) continue } + promStoragePluginUpdatesCount.WithLabelValues().Inc() } c.logger.Debug("S4StorageReporting ShouldAcceptFinalizedReport", commontypes.LogFields{ @@ -311,7 +332,7 @@ func snapshotToVersionMap(rows []*s4.SnapshotRow) map[key]uint64 { m := make(map[key]uint64) for _, row := range rows { if row.Confirmed { - m[key{address: row.Address.String(), slotID: uint(row.SlotId)}] = row.Version + m[key{address: row.Address.String(), slotID: row.SlotId}] = row.Version } } return m diff --git a/core/services/ocr2/plugins/s4/plugin_test.go b/core/services/ocr2/plugins/s4/plugin_test.go index e2b5d21b847..b53ab40bfcb 100644 --- a/core/services/ocr2/plugins/s4/plugin_test.go +++ b/core/services/ocr2/plugins/s4/plugin_test.go @@ -5,13 +5,13 @@ import ( "testing" "time" + "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/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/s4" s4_svc "github.com/smartcontractkit/chainlink/v2/core/services/s4" s4_mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" - "github.com/smartcontractkit/chainlink/v2/core/utils" commonlogger "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -51,7 +51,7 @@ func generateTestRows(t *testing.T, n int, ttl time.Duration) []*s4.Row { func generateTestOrmRow(t *testing.T, ttl time.Duration, version uint64, confimed bool) *s4_svc.Row { priv, addr := testutils.NewPrivateKeyAndAddress(t) row := &s4_svc.Row{ - Address: utils.NewBig(addr.Big()), + Address: big.New(addr.Big()), SlotId: 0, Version: version, Confirmed: confimed, @@ -296,7 +296,7 @@ func TestPlugin_Query(t *testing.T) { for i := 0; i < 256; i++ { var thisAddress common.Address thisAddress[0] = byte(i) - ormRows[i].Address = utils.NewBig(thisAddress.Big()) + ormRows[i].Address = big.New(thisAddress.Big()) } versions := rowsToShapshotRows(ormRows) @@ -322,7 +322,7 @@ func TestPlugin_Query(t *testing.T) { assert.Len(t, qq.Rows, 16) for _, r := range qq.Rows { thisAddress := s4.UnmarshalAddress(r.Address) - assert.True(t, ar.Contains((*utils.Big)(thisAddress))) + assert.True(t, ar.Contains(thisAddress)) } ar.Advance() diff --git a/core/services/ocr2/plugins/threshold/mocks/decryptor.go b/core/services/ocr2/plugins/threshold/mocks/decryptor.go index 4b91cbbd26f..5496483c9dd 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type Decryptor struct { func (_m *Decryptor) Decrypt(ctx context.Context, ciphertextId decryptionplugin.CiphertextId, ciphertext []byte) ([]byte, error) { ret := _m.Called(ctx, ciphertextId, ciphertext) + if len(ret) == 0 { + panic("no return value specified for Decrypt") + } + var r0 []byte var r1 error if rf, ok := ret.Get(0).(func(context.Context, decryptionplugin.CiphertextId, []byte) ([]byte, error)); ok { diff --git a/core/services/ocr2/validate/config.go b/core/services/ocr2/validate/config.go index 549b929b23c..0084a18308b 100644 --- a/core/services/ocr2/validate/config.go +++ b/core/services/ocr2/validate/config.go @@ -49,7 +49,7 @@ func ToLocalConfig(ocr2Config OCR2Config, insConf InsecureConfig, spec job.OCR2O ContractTransmitterTransmitTimeout: ocr2Config.ContractTransmitterTransmitTimeout(), DatabaseTimeout: ocr2Config.DatabaseTimeout(), } - if spec.Relay == relay.Solana && env.MedianPluginCmd.Get() != "" { + if spec.Relay == relay.Solana && 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 bb9bb03a8ac..ad54ba4fea2 100644 --- a/core/services/ocr2/validate/validate.go +++ b/core/services/ocr2/validate/validate.go @@ -136,10 +136,11 @@ type Config struct { } type innerConfig struct { - Command string `json:"command"` - ProviderType string `json:"providerType"` - PluginName string `json:"pluginName"` - TelemetryType string `json:"telemetryType"` + Command string `json:"command"` + EnvVars map[string]string `json:"envVars"` + ProviderType string `json:"providerType"` + PluginName string `json:"pluginName"` + TelemetryType string `json:"telemetryType"` Config } diff --git a/core/services/ocr2/validate/validate_test.go b/core/services/ocr2/validate/validate_test.go index b03f08f6b08..52dbe5f0042 100644 --- a/core/services/ocr2/validate/validate_test.go +++ b/core/services/ocr2/validate/validate_test.go @@ -11,13 +11,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "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/job" medianconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/median/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func TestValidateOracleSpec(t *testing.T) { @@ -308,7 +308,7 @@ chainID = 1337 require.Contains(t, err.Error(), "database timeout must be between 100ms and 10s, but is currently 20m0s") }, overrides: func(c *chainlink.Config, s *chainlink.Secrets) { - c.OCR2.DatabaseTimeout = models.MustNewDuration(20 * time.Minute) + c.OCR2.DatabaseTimeout = commonconfig.MustNewDuration(20 * time.Minute) }, }, { diff --git a/core/services/ocrcommon/arbitrum_block_translator_test.go b/core/services/ocrcommon/arbitrum_block_translator_test.go index b7d1b4e60c2..1ad3a6c5950 100644 --- a/core/services/ocrcommon/arbitrum_block_translator_test.go +++ b/core/services/ocrcommon/arbitrum_block_translator_test.go @@ -6,12 +6,12 @@ import ( "testing" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" diff --git a/core/services/ocrcommon/discoverer_database.go b/core/services/ocrcommon/discoverer_database.go index 0a855665575..9413b11ad07 100644 --- a/core/services/ocrcommon/discoverer_database.go +++ b/core/services/ocrcommon/discoverer_database.go @@ -5,10 +5,10 @@ import ( "database/sql" "github.com/lib/pq" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" "github.com/pkg/errors" - ocrnetworking "github.com/smartcontractkit/libocr/networking/types" "go.uber.org/multierr" + + ocrnetworking "github.com/smartcontractkit/libocr/networking/types" ) var _ ocrnetworking.DiscovererDatabase = &DiscovererDatabase{} @@ -18,10 +18,10 @@ type DiscovererDatabase struct { peerID string } -func NewDiscovererDatabase(db *sql.DB, peerID p2ppeer.ID) *DiscovererDatabase { +func NewDiscovererDatabase(db *sql.DB, peerID string) *DiscovererDatabase { return &DiscovererDatabase{ db, - peerID.Pretty(), + peerID, } } @@ -39,27 +39,25 @@ updated_at = EXCLUDED.updated_at // ReadAnnouncements returns one serialized announcement (if available) for each of the peerIDs in the form of a map // keyed by each announcement's corresponding peer ID. -func (d *DiscovererDatabase) ReadAnnouncements(ctx context.Context, peerIDs []string) (map[string][]byte, error) { +func (d *DiscovererDatabase) ReadAnnouncements(ctx context.Context, peerIDs []string) (results map[string][]byte, err error) { rows, err := d.db.QueryContext(ctx, ` SELECT remote_peer_id, ann FROM ocr_discoverer_announcements WHERE remote_peer_id = ANY($1) AND local_peer_id = $2`, pq.Array(peerIDs), d.peerID) if err != nil { return nil, errors.Wrap(err, "DiscovererDatabase failed to ReadAnnouncements") } - results := make(map[string][]byte) + defer func() { err = multierr.Combine(err, rows.Close()) }() + results = make(map[string][]byte) for rows.Next() { var peerID string var ann []byte - err := rows.Scan(&peerID, &ann) + err = rows.Scan(&peerID, &ann) if err != nil { - return nil, multierr.Combine(err, rows.Close()) + return } results[peerID] = ann } - if err := rows.Err(); err != nil { - return nil, err - } - if err := rows.Close(); err != nil { - return nil, errors.WithStack(err) + if err = rows.Err(); err != nil { + return } return results, nil } diff --git a/core/services/ocrcommon/discoverer_database_test.go b/core/services/ocrcommon/discoverer_database_test.go index ff1a931b017..b7a79e92bce 100644 --- a/core/services/ocrcommon/discoverer_database_test.go +++ b/core/services/ocrcommon/discoverer_database_test.go @@ -1,16 +1,17 @@ package ocrcommon_test import ( + "crypto/ed25519" "crypto/rand" "testing" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "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/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" ) @@ -20,8 +21,8 @@ func Test_DiscovererDatabase(t *testing.T) { localPeerID1 := mustRandomP2PPeerID(t) localPeerID2 := mustRandomP2PPeerID(t) - dd1 := ocrcommon.NewDiscovererDatabase(db, localPeerID1) - dd2 := ocrcommon.NewDiscovererDatabase(db, localPeerID2) + dd1 := ocrcommon.NewDiscovererDatabase(db, localPeerID1.Raw()) + dd2 := ocrcommon.NewDiscovererDatabase(db, localPeerID2.Raw()) ctx := testutils.Context(t) @@ -73,7 +74,7 @@ func Test_DiscovererDatabase(t *testing.T) { }) t.Run("persists data across restarts", func(t *testing.T) { - dd3 := ocrcommon.NewDiscovererDatabase(db, localPeerID1) + dd3 := ocrcommon.NewDiscovererDatabase(db, localPeerID1.Raw()) announcements, err := dd3.ReadAnnouncements(ctx, []string{"remote1"}) require.NoError(t, err) @@ -83,10 +84,10 @@ func Test_DiscovererDatabase(t *testing.T) { }) } -func mustRandomP2PPeerID(t *testing.T) p2ppeer.ID { - p2pPrivkey, _, err := cryptop2p.GenerateEd25519Key(rand.Reader) +func mustRandomP2PPeerID(t *testing.T) p2pkey.PeerID { + _, p2pPrivkey, err := ed25519.GenerateKey(rand.Reader) require.NoError(t, err) - id, err := p2ppeer.IDFromPrivateKey(p2pPrivkey) + id, err := ragep2ptypes.PeerIDFromPrivateKey(p2pPrivkey) require.NoError(t, err) - return id + return p2pkey.PeerID(id) } diff --git a/core/services/ocrcommon/peer_wrapper.go b/core/services/ocrcommon/peer_wrapper.go index a7d510ef901..1b8ebfcdb22 100644 --- a/core/services/ocrcommon/peer_wrapper.go +++ b/core/services/ocrcommon/peer_wrapper.go @@ -2,19 +2,12 @@ package ocrcommon import ( "context" - "fmt" "io" - "net" - - p2ppeer "github.com/libp2p/go-libp2p-core/peer" - p2ppeerstore "github.com/libp2p/go-libp2p-core/peerstore" - "github.com/pkg/errors" - "go.uber.org/multierr" "github.com/jmoiron/sqlx" + "github.com/pkg/errors" ocrnetworking "github.com/smartcontractkit/libocr/networking" - ocrnetworkingtypes "github.com/smartcontractkit/libocr/networking/types" ocr1types "github.com/smartcontractkit/libocr/offchainreporting/types" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -46,14 +39,13 @@ type ( // SingletonPeerWrapper manages all libocr peers for the application SingletonPeerWrapper struct { services.StateMachine - keyStore keystore.Master - p2pCfg config.P2P - ocrCfg PeerWrapperOCRConfig - dbConfig pg.QConfig - db *sqlx.DB - lggr logger.Logger - PeerID p2pkey.PeerID - pstoreWrapper *Pstorewrapper + keyStore keystore.Master + p2pCfg config.P2P + ocrCfg PeerWrapperOCRConfig + dbConfig pg.QConfig + db *sqlx.DB + lggr logger.Logger + PeerID p2pkey.PeerID // Used at shutdown to stop all of this peer's goroutines peerCloser io.Closer @@ -67,20 +59,8 @@ type ( ) func ValidatePeerWrapperConfig(config config.P2P) error { - switch config.NetworkStack() { - case ocrnetworking.NetworkingStackV1: - // Note: If P2PListenPort isn't set, the peer wrapper will generate a random one itself. - return nil - case ocrnetworking.NetworkingStackV2: - if len(config.V2().ListenAddresses()) == 0 { - return errors.New("networking stack v2 selected but no P2P.V2.ListenAddresses specified") - } - case ocrnetworking.NetworkingStackV1V2: - if len(config.V2().ListenAddresses()) == 0 { - return errors.New("networking stack v1v2 selected but no P2P.V2.ListenAddresses specified") - } - default: - return errors.New("unknown networking stack") + if len(config.V2().ListenAddresses()) == 0 { + return errors.New("no P2P.V2.ListenAddresses specified") } return nil } @@ -139,70 +119,12 @@ func (p *SingletonPeerWrapper) peerConfig() (ocrnetworking.PeerConfig, error) { } p.PeerID = key.PeerID() - v1 := p.p2pCfg.V1() - p2pPort := v1.ListenPort() - // We need to start the peer store wrapper if v1 is required. - // Also fallback to listen params if announce params not specified. - ns := p.p2pCfg.NetworkStack() - // NewPeer requires that these are both set or unset, otherwise it will error out. - v1AnnounceIP, v1AnnouncePort := v1.AnnounceIP(), v1.AnnouncePort() - var peerStore p2ppeerstore.Peerstore - if ns == ocrnetworking.NetworkingStackV1 || ns == ocrnetworking.NetworkingStackV1V2 { - p.pstoreWrapper, err = NewPeerstoreWrapper(p.db, v1.PeerstoreWriteInterval(), p.PeerID, p.lggr, p.dbConfig) - if err != nil { - return ocrnetworking.PeerConfig{}, errors.Wrap(err, "could not make new pstorewrapper") - } - if err = p.pstoreWrapper.Start(); err != nil { - return ocrnetworking.PeerConfig{}, errors.Wrap(err, "failed to start peer store wrapper") - } - - peerStore = p.pstoreWrapper.Peerstore - - // Use a random port if the port hasn't been set explicitly. - if p2pPort == 0 { - port, perr := p.randomPort() - if perr != nil { - return ocrnetworking.PeerConfig{}, perr - } - p2pPort = port - - p.lggr.Warnw( - fmt.Sprintf("P2PListenPort was not set, listening on random port %d. A new random port will be generated on every boot, for stability it is recommended to set P2PListenPort to a fixed value in your environment", p2pPort), - "p2pPort", - p2pPort, - ) - } - - // Support someone specifying only the announce IP but leaving out - // the port. - // We _should not_ handle the case of someone specifying only the - // port but leaving out the IP, because the listen IP is typically - // an unspecified IP (https://pkg.go.dev/net#IP.IsUnspecified) and - // using that for the announce IP will cause other peers to not be - // able to connect. - if v1AnnounceIP != nil && v1AnnouncePort == 0 { - v1AnnouncePort = p2pPort - } - } - - // Discover DB is only required for v2 - var discovererDB ocrnetworkingtypes.DiscovererDatabase - if ns == ocrnetworking.NetworkingStackV2 || ns == ocrnetworking.NetworkingStackV1V2 { - discovererDB = NewDiscovererDatabase(p.db.DB, p2ppeer.ID(p.PeerID)) - } + discovererDB := NewDiscovererDatabase(p.db.DB, p.PeerID.Raw()) config := p.p2pCfg peerConfig := ocrnetworking.PeerConfig{ - NetworkingStack: config.NetworkStack(), - PrivKey: key.PrivKey, - Logger: commonlogger.NewOCRWrapper(p.lggr, p.ocrCfg.TraceLogging(), func(string) {}), - // V1 config - V1ListenIP: config.V1().ListenIP(), - V1ListenPort: p2pPort, - V1AnnounceIP: v1AnnounceIP, - V1AnnouncePort: v1AnnouncePort, - V1Peerstore: peerStore, - V1DHTAnnouncementCounterUserPrefix: config.V1().DHTAnnouncementCounterUserPrefix(), + PrivKey: key.PrivKey, + Logger: commonlogger.NewOCRWrapper(p.lggr, p.ocrCfg.TraceLogging(), func(string) {}), // V2 config V2ListenAddresses: config.V2().ListenAddresses(), @@ -211,14 +133,6 @@ func (p *SingletonPeerWrapper) peerConfig() (ocrnetworking.PeerConfig, error) { V2DeltaDial: config.V2().DeltaDial().Duration(), V2DiscovererDatabase: discovererDB, - V1EndpointConfig: ocrnetworking.EndpointConfigV1{ - IncomingMessageBufferSize: config.IncomingMessageBufferSize(), - OutgoingMessageBufferSize: config.OutgoingMessageBufferSize(), - NewStreamTimeout: config.V1().NewStreamTimeout(), - DHTLookupInterval: config.V1().DHTLookupInterval(), - BootstrapCheckInterval: config.V1().BootstrapCheckInterval(), - }, - V2EndpointConfig: ocrnetworking.EndpointConfigV2{ IncomingMessageBufferSize: config.IncomingMessageBufferSize(), OutgoingMessageBufferSize: config.OutgoingMessageBufferSize(), @@ -228,29 +142,12 @@ func (p *SingletonPeerWrapper) peerConfig() (ocrnetworking.PeerConfig, error) { return peerConfig, nil } -func (p *SingletonPeerWrapper) randomPort() (uint16, error) { - addr, err := net.ResolveTCPAddr("tcp", "localhost:0") - if err != nil { - return 0, fmt.Errorf("unexpected ResolveTCPAddr error generating random P2PListenPort: %w", err) - } - l, err := net.ListenTCP("tcp", addr) - if err != nil { - return 0, fmt.Errorf("unexpected ListenTCP error generating random P2PListenPort: %w", err) - } - defer l.Close() - - return uint16(l.Addr().(*net.TCPAddr).Port), nil -} - // Close closes the peer and peerstore func (p *SingletonPeerWrapper) Close() error { return p.StopOnce("SingletonPeerWrapper", func() (err error) { if p.peerCloser != nil { err = p.peerCloser.Close() } - if p.pstoreWrapper != nil { - err = multierr.Combine(err, p.pstoreWrapper.Close()) - } return err }) } diff --git a/core/services/ocrcommon/peer_wrapper_test.go b/core/services/ocrcommon/peer_wrapper_test.go index 209bc6b969b..f46b2af27c5 100644 --- a/core/services/ocrcommon/peer_wrapper_test.go +++ b/core/services/ocrcommon/peer_wrapper_test.go @@ -1,13 +1,16 @@ package ocrcommon_test import ( + "fmt" "testing" "time" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" - "github.com/stretchr/testify/assert" + "github.com/hashicorp/consul/sdk/freeport" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "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" @@ -16,8 +19,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func Test_SingletonPeerWrapper_Start(t *testing.T) { @@ -25,12 +26,12 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { db := pgtest.NewSqlxDB(t) - peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) - require.NoError(t, err) + var peerID ragep2ptypes.PeerID + require.NoError(t, peerID.UnmarshalText([]byte(configtest.DefaultPeerID))) t.Run("with no p2p keys returns error", func(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) @@ -39,26 +40,26 @@ func Test_SingletonPeerWrapper_Start(t *testing.T) { 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.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) k, err := keyStore.P2P().Create() require.NoError(t, err) cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + 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()) }) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - require.NoError(t, pw.Start(testutils.Context(t)), "foo") + servicetest.Run(t, pw) require.Equal(t, k.PeerID(), pw.PeerID) - require.NoError(t, pw.Close()) }) t.Run("with one p2p key and mismatching P2P.PeerID returns error", func(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) c.P2P.PeerID = ptr(p2pkey.PeerID(peerID)) }) keyStore := cltest.NewKeyStore(t, db, cfg.Database()) @@ -73,27 +74,29 @@ 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.V1.Enabled = ptr(true) + 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() require.NoError(t, err) cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + 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()) }) pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - require.NoError(t, pw.Start(testutils.Context(t)), "foo") + servicetest.Run(t, pw) require.Equal(t, k2.PeerID(), pw.PeerID) - require.NoError(t, pw.Close()) }) t.Run("with multiple p2p keys and mismatching P2P.PeerID returns error", func(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) + 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()) @@ -120,9 +123,8 @@ func Test_SingletonPeerWrapper_Close(t *testing.T) { 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 = models.MustNewDuration(100 * time.Millisecond) - c.P2P.V2.DeltaReconcile = models.MustNewDuration(1 * time.Second) - c.P2P.V1.ListenPort = ptr[uint16](0) + c.P2P.V2.DeltaDial = commonconfig.MustNewDuration(100 * time.Millisecond) + c.P2P.V2.DeltaReconcile = commonconfig.MustNewDuration(1 * time.Second) p2paddresses := []string{ "127.0.0.1:17193", @@ -146,75 +148,4 @@ func Test_SingletonPeerWrapper_Close(t *testing.T) { require.NoError(t, pw.Close()) } -func TestSingletonPeerWrapper_PeerConfig(t *testing.T) { - t.Parallel() - - db := pgtest.NewSqlxDB(t) - - require.NoError(t, utils.JustError(db.Exec(`DELETE FROM encrypted_key_rings`))) - - cfg := configtest.NewGeneralConfig(t, nil) - keyStore := cltest.NewKeyStore(t, db, cfg.Database()) - k, err := keyStore.P2P().Create() - require.NoError(t, err) - - t.Run("generates a random port if v1 enabled and listen port isn't set", func(t *testing.T) { - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) - c.P2P.V1.ListenPort = ptr(uint16(0)) - c.P2P.PeerID = ptr(k.PeerID()) - }) - - pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - peerConfig, err := pw.PeerConfig() - require.NoError(t, err) - - assert.NotEqual(t, peerConfig.V1ListenPort, 0) - }) - - t.Run("generates a random port if v1v2 enabled and listen port isn't set", func(t *testing.T) { - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) - c.P2P.V2.Enabled = ptr(true) - c.P2P.V1.ListenPort = ptr(uint16(0)) - c.P2P.PeerID = ptr(k.PeerID()) - }) - - pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - peerConfig, err := pw.PeerConfig() - require.NoError(t, err) - - assert.NotEqual(t, peerConfig.V1ListenPort, 0) - }) - - t.Run("doesnt generate a port if v2 is enabled", func(t *testing.T) { - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V2.Enabled = ptr(true) - c.P2P.V1.ListenPort = ptr(uint16(0)) - c.P2P.PeerID = ptr(k.PeerID()) - }) - - pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - peerConfig, err := pw.PeerConfig() - require.NoError(t, err) - - assert.NotEqual(t, peerConfig.V1ListenPort, 0) - }) - - t.Run("doesnt override a port if listenport is set", func(t *testing.T) { - portNo := uint16(33247) - cfg = configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.P2P.V1.Enabled = ptr(true) - c.P2P.V1.ListenPort = ptr(uint16(33247)) - c.P2P.PeerID = ptr(k.PeerID()) - }) - - pw := ocrcommon.NewSingletonPeerWrapper(keyStore, cfg.P2P(), cfg.OCR(), cfg.Database(), db, logger.TestLogger(t)) - peerConfig, err := pw.PeerConfig() - require.NoError(t, err) - - assert.Equal(t, peerConfig.V1ListenPort, portNo) - }) -} - func ptr[T any](t T) *T { return &t } diff --git a/core/services/ocrcommon/peerstore.go b/core/services/ocrcommon/peerstore.go deleted file mode 100644 index 1d859184ab5..00000000000 --- a/core/services/ocrcommon/peerstore.go +++ /dev/null @@ -1,182 +0,0 @@ -package ocrcommon - -import ( - "context" - "fmt" - "strings" - "time" - - p2ppeer "github.com/libp2p/go-libp2p-core/peer" - p2ppeerstore "github.com/libp2p/go-libp2p-core/peerstore" - "github.com/libp2p/go-libp2p-peerstore/pstoremem" - ma "github.com/multiformats/go-multiaddr" - "github.com/pkg/errors" - - "github.com/jmoiron/sqlx" - - "github.com/smartcontractkit/chainlink-common/pkg/services" - - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/recovery" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -type ( - P2PPeer struct { - ID string - Addr string - PeerID string - CreatedAt time.Time - UpdatedAt time.Time - } - - Pstorewrapper struct { - services.StateMachine - Peerstore p2ppeerstore.Peerstore - peerID string - q pg.Q - writeInterval time.Duration - ctx context.Context - ctxCancel context.CancelFunc - chDone chan struct{} - lggr logger.SugaredLogger - } -) - -// NewPeerstoreWrapper creates a new database-backed peerstore wrapper scoped to the given jobID -// Multiple peerstore wrappers should not be instantiated with the same jobID -func NewPeerstoreWrapper(db *sqlx.DB, writeInterval time.Duration, peerID p2pkey.PeerID, lggr logger.Logger, cfg pg.QConfig) (*Pstorewrapper, error) { - ctx, cancel := context.WithCancel(context.Background()) - namedLogger := lggr.Named("PeerStore") - q := pg.NewQ(db, namedLogger, cfg) - - return &Pstorewrapper{ - services.StateMachine{}, - pstoremem.NewPeerstore(), - peerID.Raw(), - q, - writeInterval, - ctx, - cancel, - make(chan struct{}), - logger.Sugared(namedLogger), - }, nil -} - -func (p *Pstorewrapper) Start() error { - return p.StartOnce("PeerStore", func() error { - err := p.readFromDB() - if err != nil { - return errors.Wrap(err, "could not start peerstore wrapper") - } - go p.dbLoop() - return nil - }) -} - -func (p *Pstorewrapper) dbLoop() { - defer close(p.chDone) - ticker := time.NewTicker(utils.WithJitter(p.writeInterval)) - defer ticker.Stop() - for { - select { - case <-p.ctx.Done(): - return - case <-ticker.C: - recovery.WrapRecover(p.lggr, func() { - if err := p.WriteToDB(); err != nil { - p.lggr.Errorw("Error writing peerstore to DB", "err", err) - } - }) - } - } -} - -func (p *Pstorewrapper) Close() error { - return p.StopOnce("PeerStore", func() error { - p.ctxCancel() - <-p.chDone - return p.Peerstore.Close() - }) -} - -func (p *Pstorewrapper) readFromDB() error { - peers, err := p.getPeers() - if err != nil { - return err - } - for _, peer := range peers { - peerID, err := p2ppeer.Decode(peer.ID) - if err != nil { - return errors.Wrapf(err, "unexpectedly failed to decode peer ID '%s'", peer.ID) - } - peerAddr, err := ma.NewMultiaddr(peer.Addr) - if err != nil { - return errors.Wrapf(err, "unexpectedly failed to decode peer multiaddr '%s'", peer.Addr) - } - p.Peerstore.AddAddr(peerID, peerAddr, p2ppeerstore.PermanentAddrTTL) - } - return nil -} - -func (p *Pstorewrapper) getPeers() (peers []P2PPeer, err error) { - rows, err := p.q.WithOpts(pg.WithParentCtx(p.ctx)).Query(`SELECT id, addr FROM p2p_peers WHERE peer_id = $1`, p.peerID) - if err != nil { - return nil, errors.Wrap(err, "error querying peers") - } - defer p.lggr.ErrorIfFn(rows.Close, "Error closing p2p_peers rows") - - peers = make([]P2PPeer, 0) - - for rows.Next() { - peer := P2PPeer{} - if err = rows.Scan(&peer.ID, &peer.Addr); err != nil { - return nil, errors.Wrap(err, "unexpected error scanning row") - } - peers = append(peers, peer) - } - if err = rows.Err(); err != nil { - return nil, err - } - - return peers, nil -} - -func (p *Pstorewrapper) WriteToDB() error { - q := p.q.WithOpts(pg.WithParentCtx(p.ctx)) - err := q.Transaction(func(tx pg.Queryer) error { - _, err := tx.Exec(`DELETE FROM p2p_peers WHERE peer_id = $1`, p.peerID) - if err != nil { - return errors.Wrap(err, "delete from p2p_peers failed") - } - peers := make([]P2PPeer, 0) - for _, pid := range p.Peerstore.PeersWithAddrs() { - addrs := p.Peerstore.Addrs(pid) - for _, addr := range addrs { - p := P2PPeer{ - ID: pid.String(), - Addr: addr.String(), - PeerID: p.peerID, - } - peers = append(peers, p) - } - } - valueStrings := []string{} - valueArgs := []interface{}{} - for _, p := range peers { - valueStrings = append(valueStrings, "(?, ?, ?, NOW(), NOW())") - valueArgs = append(valueArgs, p.ID) - valueArgs = append(valueArgs, p.Addr) - valueArgs = append(valueArgs, p.PeerID) - } - - /* #nosec G201 */ - stmt := fmt.Sprintf("INSERT INTO p2p_peers (id, addr, peer_id, created_at, updated_at) VALUES %s", strings.Join(valueStrings, ",")) - stmt = sqlx.Rebind(sqlx.DOLLAR, stmt) - _, err = tx.Exec(stmt, valueArgs...) - return errors.Wrap(err, "insert into p2p_peers failed") - }) - return errors.Wrap(err, "could not write peers to DB") -} diff --git a/core/services/ocrcommon/peerstore_test.go b/core/services/ocrcommon/peerstore_test.go deleted file mode 100644 index 6e692153564..00000000000 --- a/core/services/ocrcommon/peerstore_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package ocrcommon_test - -import ( - "testing" - "time" - - p2ppeer "github.com/libp2p/go-libp2p-core/peer" - p2ppeerstore "github.com/libp2p/go-libp2p-core/peerstore" - ma "github.com/multiformats/go-multiaddr" - - "github.com/stretchr/testify/require" - - "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/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -func Test_Peerstore_Start(t *testing.T) { - db := pgtest.NewSqlxDB(t) - - peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) - require.NoError(t, err) - - nonExistentP2PPeerID, err := p2ppeer.Decode("12D3KooWAdCzaesXyezatDzgGvCngqsBqoUqnV9PnVc46jsVt2i9") - require.NoError(t, err) - - err = utils.JustError(db.Exec(`INSERT INTO p2p_peers (id, addr, created_at, updated_at, peer_id) VALUES - ( - '12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - '/ip4/127.0.0.1/tcp/12000/p2p/12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - NOW(), - NOW(), - $1 - ), - ( - '12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - '/ip4/127.0.0.2/tcp/12000/p2p/12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - NOW(), - NOW(), - $2 - ), - ( - '12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - '/ip4/127.0.0.2/tcp/12000/p2p/12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph', - NOW(), - NOW(), - $3 - ) - `, p2pkey.PeerID(peerID), p2pkey.PeerID(peerID), p2pkey.PeerID(nonExistentP2PPeerID))) - require.NoError(t, err) - - cfg := configtest.NewTestGeneralConfig(t) - wrapper, err := ocrcommon.NewPeerstoreWrapper(db, 1*time.Second, p2pkey.PeerID(peerID), logger.TestLogger(t), cfg.Database()) - require.NoError(t, err) - - err = wrapper.Start() - require.NoError(t, err) - - require.Equal(t, 1, wrapper.Peerstore.PeersWithAddrs().Len()) - - peerID, err = p2ppeer.Decode("12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph") - require.NoError(t, err) - - maddrs := wrapper.Peerstore.Addrs(peerID) - - require.Len(t, maddrs, 2) -} - -func Test_Peerstore_WriteToDB(t *testing.T) { - db := pgtest.NewSqlxDB(t) - - peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) - require.NoError(t, err) - - cfg := configtest.NewTestGeneralConfig(t) - wrapper, err := ocrcommon.NewPeerstoreWrapper(db, 1*time.Second, p2pkey.PeerID(peerID), logger.TestLogger(t), cfg.Database()) - require.NoError(t, err) - - maddr, err := ma.NewMultiaddr("/ip4/127.0.0.2/tcp/12000/p2p/12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph") - require.NoError(t, err) - newPeerID, err := p2ppeer.Decode("12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph") - require.NoError(t, err) - - wrapper.Peerstore.AddAddr(newPeerID, maddr, p2ppeerstore.PermanentAddrTTL) - - err = wrapper.WriteToDB() - require.NoError(t, err) - - var peers []ocrcommon.P2PPeer - err = db.Select(&peers, `SELECT * FROM p2p_peers`) - require.NoError(t, err) - require.Equal(t, 1, len(peers)) - - peer := peers[0] - require.Equal(t, "12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph", peer.ID) - require.Equal(t, "/ip4/127.0.0.2/tcp/12000/p2p/12D3KooWL1yndUw9T2oWXjhfjdwSscWA78YCpUdduA3Cnn4dCtph", peer.Addr) - require.Equal(t, p2pkey.PeerID(peerID).Raw(), peer.PeerID) -} diff --git a/core/services/ocrcommon/run_saver.go b/core/services/ocrcommon/run_saver.go index b1a0fc7b141..6d85aa857a4 100644 --- a/core/services/ocrcommon/run_saver.go +++ b/core/services/ocrcommon/run_saver.go @@ -5,15 +5,20 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "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 +} + type RunResultSaver struct { services.StateMachine maxSuccessfulRuns uint64 runResults chan *pipeline.Run - pipelineRunner pipeline.Runner + pipelineRunner Runner done chan struct{} logger logger.Logger } @@ -24,7 +29,7 @@ func (r *RunResultSaver) HealthReport() map[string]error { func (r *RunResultSaver) Name() string { return r.logger.Name() } -func NewResultRunSaver(pipelineRunner pipeline.Runner, +func NewResultRunSaver(pipelineRunner Runner, logger logger.Logger, maxSuccessfulRuns uint64, resultsWriteDepth uint64, ) *RunResultSaver { return &RunResultSaver{ diff --git a/core/services/ocrcommon/run_saver_test.go b/core/services/ocrcommon/run_saver_test.go index 73697d181bc..7bfe60f2a06 100644 --- a/core/services/ocrcommon/run_saver_test.go +++ b/core/services/ocrcommon/run_saver_test.go @@ -4,9 +4,8 @@ import ( "testing" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" @@ -20,7 +19,7 @@ func TestRunSaver(t *testing.T) { 1000, 100, ) - require.NoError(t, rs.Start(testutils.Context(t))) + servicetest.Run(t, rs) for i := 0; i < 100; i++ { d := i pipelineRunner.On("InsertFinishedRun", mock.Anything, mock.Anything, mock.Anything, mock.Anything). @@ -31,5 +30,4 @@ func TestRunSaver(t *testing.T) { Once() rs.Save(&pipeline.Run{ID: int64(i)}) } - require.NoError(t, rs.Close()) } diff --git a/core/services/ocrcommon/telemetry.go b/core/services/ocrcommon/telemetry.go index c9d3e85cd2c..b641bd2b3cf 100644 --- a/core/services/ocrcommon/telemetry.go +++ b/core/services/ocrcommon/telemetry.go @@ -21,9 +21,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/utils" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + v1types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + v2types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" + v3types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" ) type eaTelemetry struct { @@ -41,9 +41,9 @@ type EnhancedTelemetryData struct { } type EnhancedTelemetryMercuryData struct { - V1Observation *relaymercuryv1.Observation - V2Observation *relaymercuryv2.Observation - V3Observation *relaymercuryv3.Observation + V1Observation *v1types.Observation + V2Observation *v2types.Observation + V3Observation *v3types.Observation TaskRunResults pipeline.TaskRunResults RepTimestamp ocrtypes.ReportTimestamp FeedVersion mercuryutils.FeedVersion @@ -99,7 +99,7 @@ func (e *EnhancedTelemetryService[T]) Start(context.Context) error { func (e *EnhancedTelemetryService[T]) Close() error { return e.StopOnce("EnhancedTelemetryService", func() error { - e.chDone <- struct{}{} + close(e.chDone) e.lggr.Infof("Stopping enhanced telemetry service for job %d", e.job.ID) return nil }) @@ -234,19 +234,23 @@ func (e *EnhancedTelemetryService[T]) collectAndSend(trrs *pipeline.TaskRunResul if trr.Task.Type() != pipeline.TaskTypeBridge { continue } + var bridgeName string + if b, is := trr.Task.(*pipeline.BridgeTask); is { + bridgeName = b.Name + } if trr.Result.Error != nil { - e.lggr.Warnw(fmt.Sprintf("cannot get bridge response from bridge task, job %d, id %s", e.job.ID, trr.Task.DotID()), "err", trr.Result.Error) + e.lggr.Warnw(fmt.Sprintf("cannot get bridge response from bridge task, job=%d, id=%s, name=%q", e.job.ID, trr.Task.DotID(), bridgeName), "err", trr.Result.Error, "jobID", e.job.ID, "dotID", trr.Task.DotID(), "bridgeName", bridgeName) continue } bridgeRawResponse, ok := trr.Result.Value.(string) if !ok { - e.lggr.Warnf("cannot parse bridge response from bridge task, job %d, id %s: expected string, got: %v (type %T)", e.job.ID, trr.Task.DotID(), trr.Result.Value, trr.Result.Value) + e.lggr.Warnw(fmt.Sprintf("cannot parse bridge response from bridge task, job=%d, id=%s, name=%q: expected string, got: %v (type %T)", e.job.ID, trr.Task.DotID(), bridgeName, trr.Result.Value, trr.Result.Value), "jobID", e.job.ID, "dotID", trr.Task.DotID(), "bridgeName", bridgeName) continue } eaTelem, err := parseEATelemetry([]byte(bridgeRawResponse)) if err != nil { - e.lggr.Warnw(fmt.Sprintf("cannot parse EA telemetry, job %d, id %s", e.job.ID, trr.Task.DotID()), "err", err) + e.lggr.Warnw(fmt.Sprintf("cannot parse EA telemetry, job=%d, id=%s, name=%q", e.job.ID, trr.Task.DotID(), bridgeName), "err", err, "jobID", e.job.ID, "dotID", trr.Task.DotID(), "bridgeName", bridgeName) continue } value := e.getParsedValue(trrs, trr) @@ -359,15 +363,16 @@ func (e *EnhancedTelemetryService[T]) collectMercuryEnhancedTelemetry(d Enhanced continue } bridgeTask := trr.Task.(*pipeline.BridgeTask) + bridgeName := bridgeTask.Name bridgeRawResponse, ok := trr.Result.Value.(string) if !ok { - e.lggr.Warnf("cannot get bridge response from bridge task, job %d, id %s, expected string got %T", e.job.ID, trr.Task.DotID(), trr.Result.Value) + e.lggr.Warnw(fmt.Sprintf("cannot get bridge response from bridge task, job=%d, id=%s, name=%q, expected string got %T", e.job.ID, trr.Task.DotID(), bridgeName, trr.Result.Value), "jobID", e.job.ID, "dotID", trr.Task.DotID(), "bridgeName", bridgeName) continue } eaTelem, err := parseEATelemetry([]byte(bridgeRawResponse)) if err != nil { - e.lggr.Warnw(fmt.Sprintf("cannot parse EA telemetry, job %d, id %s", e.job.ID, trr.Task.DotID()), "err", err) + e.lggr.Warnw(fmt.Sprintf("cannot parse EA telemetry, job=%d, id=%s, name=%q", e.job.ID, trr.Task.DotID(), bridgeName), "err", err, "jobID", e.job.ID, "dotID", trr.Task.DotID(), "bridgeName", bridgeName) } assetSymbol := e.getAssetSymbolFromRequestData(bridgeTask.RequestData) diff --git a/core/services/ocrcommon/telemetry_test.go b/core/services/ocrcommon/telemetry_test.go index 24c798259d9..caa8ccfcc01 100644 --- a/core/services/ocrcommon/telemetry_test.go +++ b/core/services/ocrcommon/telemetry_test.go @@ -14,11 +14,13 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - mercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - mercury_v2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + mercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + mercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "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/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -27,7 +29,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) const bridgeResponse = `{ @@ -45,6 +46,7 @@ const bridgeResponse = `{ var trrs = pipeline.TaskRunResults{ pipeline.TaskRunResult{ Task: &pipeline.BridgeTask{ + Name: "test-bridge-1", BaseTask: pipeline.NewBaseTask(0, "ds1", nil, nil, 0), }, Result: pipeline.Result{ @@ -61,6 +63,7 @@ var trrs = pipeline.TaskRunResults{ }, pipeline.TaskRunResult{ Task: &pipeline.BridgeTask{ + Name: "test-bridge-2", BaseTask: pipeline.NewBaseTask(0, "ds2", nil, nil, 0), }, Result: pipeline.Result{ @@ -77,6 +80,7 @@ var trrs = pipeline.TaskRunResults{ }, pipeline.TaskRunResult{ Task: &pipeline.BridgeTask{ + Name: "test-bridge-3", BaseTask: pipeline.NewBaseTask(0, "ds3", nil, nil, 0), }, Result: pipeline.Result{ @@ -147,7 +151,7 @@ func TestGetChainID(t *testing.T) { } j.Type = job.Type(pipeline.OffchainReportingJobType) - j.OCROracleSpec.EVMChainID = (*utils.Big)(big.NewInt(1234567890)) + j.OCROracleSpec.EVMChainID = (*ubig.Big)(big.NewInt(1234567890)) assert.Equal(t, "1234567890", e.getChainID()) j.Type = job.Type(pipeline.OffchainReporting2JobType) @@ -206,14 +210,14 @@ func TestSendEATelemetry(t *testing.T) { OCROracleSpec: &job.OCROracleSpec{ ContractAddress: ethkey.EIP55AddressFromAddress(feedAddress), CaptureEATelemetry: true, - EVMChainID: (*utils.Big)(big.NewInt(9)), + EVMChainID: (*ubig.Big)(big.NewInt(9)), }, } lggr, _ := logger.TestLoggerObserved(t, zap.WarnLevel) doneCh := make(chan struct{}) enhancedTelemService := NewEnhancedTelemetryService(&jb, enhancedTelemChan, doneCh, monitoringEndpoint, lggr.Named("Enhanced Telemetry Mercury")) - require.NoError(t, enhancedTelemService.Start(testutils.Context(t))) + servicetest.Run(t, enhancedTelemService) trrs := pipeline.TaskRunResults{ pipeline.TaskRunResult{ Task: &pipeline.BridgeTask{ @@ -324,7 +328,7 @@ func TestCollectAndSend(t *testing.T) { doneCh := make(chan struct{}) enhancedTelemService := NewEnhancedTelemetryService(&jb, enhancedTelemChan, doneCh, monitoringEndpoint, lggr.Named("Enhanced Telemetry")) - require.NoError(t, enhancedTelemService.Start(testutils.Context(t))) + servicetest.Run(t, enhancedTelemService) finalResult := &pipeline.FinalResult{ Values: []interface{}{"123456"}, AllErrors: nil, @@ -389,6 +393,7 @@ func TestCollectAndSend(t *testing.T) { var trrsMercuryV1 = pipeline.TaskRunResults{ pipeline.TaskRunResult{ Task: &pipeline.BridgeTask{ + Name: "link-usd-test-bridge-v1", BaseTask: pipeline.NewBaseTask(0, "ds1", nil, nil, 0), RequestData: `{"data":{"to":"LINK","from":"USD"}}`, }, @@ -425,6 +430,7 @@ var trrsMercuryV1 = pipeline.TaskRunResults{ var trrsMercuryV2 = pipeline.TaskRunResults{ pipeline.TaskRunResult{ Task: &pipeline.BridgeTask{ + Name: "link-usd-test-bridge-v2", BaseTask: pipeline.NewBaseTask(0, "ds1", nil, nil, 0), RequestData: `{"data":{"to":"LINK","from":"USD"}}`, }, @@ -476,6 +482,7 @@ func TestGetPricesFromResults(t *testing.T) { trrs2 := pipeline.TaskRunResults{ pipeline.TaskRunResult{ Task: &pipeline.BridgeTask{ + Name: "test-bridge-1", BaseTask: pipeline.NewBaseTask(0, "ds1", nil, nil, 0), }, Result: pipeline.Result{ @@ -574,7 +581,7 @@ func TestCollectMercuryEnhancedTelemetryV1(t *testing.T) { lggr: lggr, monitoringEndpoint: monitoringEndpoint, } - require.NoError(t, e.Start(testutils.Context(t))) + servicetest.Run(t, &e) wg.Add(1) @@ -629,6 +636,7 @@ func TestCollectMercuryEnhancedTelemetryV1(t *testing.T) { chTelem <- EnhancedTelemetryMercuryData{ TaskRunResults: pipeline.TaskRunResults{ pipeline.TaskRunResult{Task: &pipeline.BridgeTask{ + Name: "test-mercury-bridge-1", BaseTask: pipeline.NewBaseTask(0, "ds1", nil, nil, 0), }, Result: pipeline.Result{ @@ -656,7 +664,7 @@ func TestCollectMercuryEnhancedTelemetryV1(t *testing.T) { wg.Wait() require.Equal(t, 2, logs.Len()) - require.Contains(t, logs.All()[0].Message, "cannot get bridge response from bridge task") + require.Contains(t, logs.All()[0].Message, `cannot get bridge response from bridge task, job=0, id=ds1, name="test-mercury-bridge-1"`) require.Contains(t, logs.All()[1].Message, "cannot parse EA telemetry") chDone <- struct{}{} } @@ -690,13 +698,13 @@ func TestCollectMercuryEnhancedTelemetryV2(t *testing.T) { lggr: lggr, monitoringEndpoint: monitoringEndpoint, } - require.NoError(t, e.Start(testutils.Context(t))) + servicetest.Run(t, &e) wg.Add(1) chTelem <- EnhancedTelemetryMercuryData{ TaskRunResults: trrsMercuryV2, - V2Observation: &mercury_v2.Observation{ + V2Observation: &mercuryv2.Observation{ BenchmarkPrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(111111)}, MaxFinalizedTimestamp: mercury.ObsResult[int64]{Val: 321}, LinkPrice: mercury.ObsResult[*big.Int]{Val: big.NewInt(4321)}, @@ -743,13 +751,14 @@ func TestCollectMercuryEnhancedTelemetryV2(t *testing.T) { chTelem <- EnhancedTelemetryMercuryData{ TaskRunResults: pipeline.TaskRunResults{ pipeline.TaskRunResult{Task: &pipeline.BridgeTask{ + Name: "test-mercury-bridge-2", BaseTask: pipeline.NewBaseTask(0, "ds1", nil, nil, 0), }, Result: pipeline.Result{ Value: nil, }}, }, - V2Observation: &mercury_v2.Observation{}, + V2Observation: &mercuryv2.Observation{}, RepTimestamp: types.ReportTimestamp{ ConfigDigest: types.ConfigDigest{2}, Epoch: 11, @@ -760,7 +769,7 @@ func TestCollectMercuryEnhancedTelemetryV2(t *testing.T) { trrsMercuryV2[0].Result.Value = "" chTelem <- EnhancedTelemetryMercuryData{ TaskRunResults: trrsMercuryV2, - V2Observation: &mercury_v2.Observation{}, + V2Observation: &mercuryv2.Observation{}, RepTimestamp: types.ReportTimestamp{ ConfigDigest: types.ConfigDigest{2}, Epoch: 11, diff --git a/core/services/ocrcommon/transmitter_pipeline.go b/core/services/ocrcommon/transmitter_pipeline.go deleted file mode 100644 index e62f745a941..00000000000 --- a/core/services/ocrcommon/transmitter_pipeline.go +++ /dev/null @@ -1,97 +0,0 @@ -package ocrcommon - -import ( - "context" - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" - - "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/job" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" -) - -const txObservationSource = ` - transmit_tx [type=ethtx - minConfirmations=0 - to="$(jobSpec.contractAddress)" - from="[$(jobSpec.fromAddress)]" - evmChainID="$(jobSpec.evmChainID)" - data="$(jobSpec.data)" - gasLimit="$(jobSpec.gasLimit)" - forwardingAllowed="$(jobSpec.forwardingAllowed)" - transmitChecker="$(jobSpec.transmitChecker)"] - transmit_tx -` - -type pipelineTransmitter struct { - lgr logger.Logger - fromAddress common.Address - gasLimit uint32 - effectiveTransmitterAddress common.Address - strategy types.TxStrategy - checker txmgr.TransmitCheckerSpec - pr pipeline.Runner - spec job.Job - chainID string -} - -// NewPipelineTransmitter creates a new eth transmitter using the job pipeline mechanism -func NewPipelineTransmitter( - lgr logger.Logger, - fromAddress common.Address, - gasLimit uint32, - effectiveTransmitterAddress common.Address, - strategy types.TxStrategy, - checker txmgr.TransmitCheckerSpec, - pr pipeline.Runner, - spec job.Job, - chainID string, -) Transmitter { - return &pipelineTransmitter{ - lgr: lgr, - fromAddress: fromAddress, - gasLimit: gasLimit, - effectiveTransmitterAddress: effectiveTransmitterAddress, - strategy: strategy, - checker: checker, - pr: pr, - spec: spec, - chainID: chainID, - } -} - -func (t *pipelineTransmitter) CreateEthTransaction(ctx context.Context, toAddress common.Address, payload []byte, _ *txmgr.TxMeta) error { - // t.strategy is ignored currently as pipeline does not support passing this (sc-55115) - vars := pipeline.NewVarsFrom(map[string]interface{}{ - "jobSpec": map[string]interface{}{ - "contractAddress": toAddress.String(), - "fromAddress": t.fromAddress.String(), - "gasLimit": t.gasLimit, - "evmChainID": t.chainID, - "forwardingAllowed": t.spec.ForwardingAllowed, - "data": payload, - "transmitChecker": t.checker, - }, - }) - - t.spec.PipelineSpec.DotDagSource = txObservationSource - run := pipeline.NewRun(*t.spec.PipelineSpec, vars) - - if _, err := t.pr.Run(ctx, run, t.lgr, true, nil); err != nil { - return errors.Wrap(err, "Skipped OCR transmission") - } - - if run.State != pipeline.RunStatusCompleted { - return fmt.Errorf("unexpected pipeline run state: %s with fatal errors %w", run.State, run.FatalErrors.ToError()) - } - - return nil -} - -func (t *pipelineTransmitter) FromAddress() common.Address { - return t.effectiveTransmitterAddress -} diff --git a/core/services/ocrcommon/transmitter_pipeline_test.go b/core/services/ocrcommon/transmitter_pipeline_test.go deleted file mode 100644 index e0114d0aa0d..00000000000 --- a/core/services/ocrcommon/transmitter_pipeline_test.go +++ /dev/null @@ -1,77 +0,0 @@ -package ocrcommon_test - -import ( - "testing" - - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "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" - "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/job" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" - "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - pipelinemocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks" -) - -func Test_PipelineTransmitter_CreateEthTransaction(t *testing.T) { - t.Parallel() - - lggr := logger.TestLogger(t) - db := pgtest.NewSqlxDB(t) - cfg := configtest.NewTestGeneralConfig(t) - ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() - - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - - chainID := "12345" - gasLimit := uint32(1000) - effectiveTransmitterAddress := fromAddress - toAddress := testutils.NewAddress() - payload := []byte{1, 2, 3} - strategy := newMockTxStrategy(t) - checker := txmgr.TransmitCheckerSpec{CheckerType: txmgr.TransmitCheckerTypeSimulate} - runner := pipelinemocks.NewRunner(t) - - transmitter := ocrcommon.NewPipelineTransmitter( - lggr, - fromAddress, - gasLimit, - effectiveTransmitterAddress, - strategy, - checker, - runner, - job.Job{ - PipelineSpec: &pipeline.Spec{}, - }, - chainID, - ) - - runner.On("Run", mock.Anything, mock.AnythingOfType("*pipeline.Run"), mock.Anything, mock.Anything, mock.Anything). - Return(false, nil). - Run(func(args mock.Arguments) { - run := args.Get(1).(*pipeline.Run) - require.Equal(t, map[string]interface{}{ - "jobSpec": map[string]interface{}{ - "contractAddress": toAddress.String(), - "fromAddress": fromAddress.String(), - "gasLimit": gasLimit, - "evmChainID": chainID, - "forwardingAllowed": false, - "data": payload, - "transmitChecker": checker, - }, - }, run.Inputs.Val) - - save := args.Get(3).(bool) - require.True(t, save) - - run.State = pipeline.RunStatusCompleted - }).Once() - - require.NoError(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil)) -} diff --git a/core/services/pg/channels.go b/core/services/pg/channels.go deleted file mode 100644 index aed132a7f2c..00000000000 --- a/core/services/pg/channels.go +++ /dev/null @@ -1,4 +0,0 @@ -package pg - -// Postgres channel to listen for new evm.txes -const ChannelInsertOnEVMLogs = "evm.insert_on_logs" diff --git a/core/services/pg/event_broadcaster.go b/core/services/pg/event_broadcaster.go deleted file mode 100644 index 70008f4c0de..00000000000 --- a/core/services/pg/event_broadcaster.go +++ /dev/null @@ -1,345 +0,0 @@ -package pg - -import ( - "context" - "database/sql" - "net/url" - "sync" - "time" - - "github.com/google/uuid" - "github.com/lib/pq" - "github.com/pkg/errors" - - "github.com/smartcontractkit/chainlink-common/pkg/services" - - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/static" - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -//go:generate mockery --quiet --name EventBroadcaster --output ./mocks/ --case=underscore -//go:generate mockery --quiet --name Subscription --output ./mocks/ --case=underscore - -// EventBroadcaster opaquely manages a collection of Postgres event listeners -// and broadcasts events to subscribers (with an optional payload filter). -type EventBroadcaster interface { - services.Service - Subscribe(channel, payloadFilter string) (Subscription, error) - Notify(channel string, payload string) error -} - -type eventBroadcaster struct { - services.StateMachine - uri string - minReconnectInterval time.Duration - maxReconnectDuration time.Duration - db *sql.DB - listener *pq.Listener - subscriptions map[string]map[Subscription]struct{} - subscriptionsMu sync.RWMutex - chStop chan struct{} - chDone chan struct{} - lggr logger.Logger -} - -var _ EventBroadcaster = (*eventBroadcaster)(nil) - -type Event struct { - Channel string - Payload string -} - -func NewEventBroadcaster(uri url.URL, minReconnectInterval time.Duration, maxReconnectDuration time.Duration, lggr logger.Logger, appID uuid.UUID) *eventBroadcaster { - if minReconnectInterval == time.Duration(0) { - minReconnectInterval = 1 * time.Second - } - if maxReconnectDuration == time.Duration(0) { - maxReconnectDuration = 1 * time.Minute - } - static.SetConsumerName(&uri, "EventBroadcaster", &appID) - return &eventBroadcaster{ - uri: uri.String(), - minReconnectInterval: minReconnectInterval, - maxReconnectDuration: maxReconnectDuration, - subscriptions: make(map[string]map[Subscription]struct{}), - chStop: make(chan struct{}), - chDone: make(chan struct{}), - lggr: lggr.Named("EventBroadcaster"), - } -} - -// Start starts EventBroadcaster. -func (b *eventBroadcaster) Start(context.Context) error { - return b.StartOnce("Postgres event broadcaster", func() (err error) { - // Explicitly using the lib/pq for notifications so we use the postgres driverName - // and NOT pgx. - db, err := sql.Open("postgres", b.uri) - if err != nil { - return err - } - b.db = db - b.listener = pq.NewListener(b.uri, b.minReconnectInterval, b.maxReconnectDuration, func(ev pq.ListenerEventType, err error) { - // sanity check since these can still be called after closing the listener - select { - case <-b.chStop: - return - default: - } - // These are always connection-related events, and the pq library - // automatically handles reconnecting to the DB. Therefore, we do not - // need to terminate, but rather simply log these events for node - // operators' sanity. - switch ev { - case pq.ListenerEventConnected: - b.lggr.Debug("Postgres event broadcaster: connected") - case pq.ListenerEventDisconnected: - b.lggr.Warnw("Postgres event broadcaster: disconnected, trying to reconnect...", "err", err) - case pq.ListenerEventReconnected: - b.lggr.Debug("Postgres event broadcaster: reconnected") - case pq.ListenerEventConnectionAttemptFailed: - b.lggr.Warnw("Postgres event broadcaster: reconnect attempt failed, trying again...", "err", err) - } - }) - - go b.runLoop() - return nil - }) -} - -// Stop permanently destroys the EventBroadcaster. Calling this does not clean -// up any outstanding subscriptions. Subscribers must explicitly call `.Close()` -// or they will leak goroutines. -func (b *eventBroadcaster) Close() error { - return b.StopOnce("Postgres event broadcaster", func() (err error) { - b.subscriptionsMu.RLock() - defer b.subscriptionsMu.RUnlock() - b.subscriptions = nil - - err = services.CloseAll(b.db, b.listener) - close(b.chStop) - <-b.chDone - return err - }) -} - -func (b *eventBroadcaster) Name() string { - return b.lggr.Name() -} - -func (b *eventBroadcaster) HealthReport() map[string]error { - return map[string]error{b.Name(): b.Healthy()} -} - -func (b *eventBroadcaster) runLoop() { - defer close(b.chDone) - for { - select { - case <-b.chStop: - return - - case notification, open := <-b.listener.NotificationChannel(): - if !open { - return - } else if notification == nil { - continue - } - b.lggr.Debugw("Postgres event broadcaster: received notification", - "channel", notification.Channel, - "payload", notification.Extra, - ) - b.broadcast(notification) - } - } -} - -func (b *eventBroadcaster) Notify(channel string, payload string) error { - _, err := b.db.Exec(`SELECT pg_notify($1, $2)`, channel, payload) - return errors.Wrap(err, "Postgres event broadcaster could not notify") -} - -func (b *eventBroadcaster) Subscribe(channel, payloadFilter string) (Subscription, error) { - b.subscriptionsMu.Lock() - defer b.subscriptionsMu.Unlock() - - if _, exists := b.subscriptions[channel]; !exists { - err := b.listener.Listen(channel) - if err != nil { - return nil, errors.Wrap(err, "Postgres event broadcaster could not subscribe") - } - b.subscriptions[channel] = make(map[Subscription]struct{}) - } - - sub := &subscription{ - channel: channel, - payloadFilter: payloadFilter, - eventBroadcaster: b, - queue: utils.NewBoundedQueue[Event](1000), - chEvents: make(chan Event), - chDone: make(chan struct{}), - lggr: logger.Sugared(b.lggr), - } - sub.processQueueWorker = utils.NewSleeperTask( - utils.SleeperFuncTask(sub.processQueue, "SubscriptionQueueProcessor"), - ) - b.subscriptions[channel][sub] = struct{}{} - return sub, nil -} - -func (b *eventBroadcaster) removeSubscription(sub Subscription) { - b.subscriptionsMu.Lock() - defer b.subscriptionsMu.Unlock() - - // The following conditions can occur on shutdown when .Stop() is called - // before one or more subscriptions' .Close() methods are called - if b.subscriptions == nil { - return - } - subs, exists := b.subscriptions[sub.ChannelName()] - if !exists || subs == nil { - return - } - - delete(b.subscriptions[sub.ChannelName()], sub) - if len(b.subscriptions[sub.ChannelName()]) == 0 { - err := b.listener.Unlisten(sub.ChannelName()) - if err != nil { - b.lggr.Errorw("Postgres event broadcaster: failed to unsubscribe", "err", err) - } - delete(b.subscriptions, sub.ChannelName()) - } -} - -func (b *eventBroadcaster) broadcast(notification *pq.Notification) { - b.subscriptionsMu.RLock() - defer b.subscriptionsMu.RUnlock() - - event := Event{ - Channel: notification.Channel, - Payload: notification.Extra, - } - - var wg sync.WaitGroup - for sub := range b.subscriptions[event.Channel] { - if sub.InterestedIn(event) { - wg.Add(1) - go func(sub Subscription) { - defer wg.Done() - sub.Send(event) - }(sub) - } - } - wg.Wait() -} - -// Subscription represents a subscription to a Postgres event channel -type Subscription interface { - Events() <-chan Event - Close() - - ChannelName() string - InterestedIn(event Event) bool - Send(event Event) -} - -type subscription struct { - channel string - payloadFilter string - eventBroadcaster *eventBroadcaster - queue *utils.BoundedQueue[Event] - processQueueWorker utils.SleeperTask - chEvents chan Event - chDone chan struct{} - lggr logger.SugaredLogger -} - -var _ Subscription = (*subscription)(nil) - -func (sub *subscription) InterestedIn(event Event) bool { - return sub.payloadFilter == event.Payload || sub.payloadFilter == "" -} - -func (sub *subscription) Send(event Event) { - sub.queue.Add(event) - sub.processQueueWorker.WakeUpIfStarted() -} - -const broadcastTimeout = 10 * time.Second - -func (sub *subscription) processQueue() { - deadline := time.Now().Add(broadcastTimeout) - for !sub.queue.Empty() { - event := sub.queue.Take() - select { - case sub.chEvents <- event: - case <-time.After(time.Until(deadline)): - sub.lggr.Warnf("Postgres event broadcaster: SLOW processQueue(), timed out after %s", broadcastTimeout) - return - case <-sub.chDone: - sub.lggr.Debugw("Postgres event broadcaster: request cancelled during processQueue()") - return - } - } -} - -func (sub *subscription) Events() <-chan Event { - return sub.chEvents -} - -func (sub *subscription) ChannelName() string { - return sub.channel -} - -func (sub *subscription) Close() { - sub.eventBroadcaster.removeSubscription(sub) - // Close chDone before stopping the SleeperTask to avoid deadlocks - close(sub.chDone) - err := sub.processQueueWorker.Stop() - if err != nil { - sub.lggr.Errorw("THIS NEVER RETURNS AN ERROR", "err", err) - } - close(sub.chEvents) -} - -// NullEventBroadcaster implements null pattern for event broadcaster -type NullEventBroadcaster struct { - Sub *NullSubscription -} - -func NewNullEventBroadcaster() *NullEventBroadcaster { - sub := &NullSubscription{make(chan (Event))} - return &NullEventBroadcaster{sub} -} - -var _ EventBroadcaster = &NullEventBroadcaster{} - -func (*NullEventBroadcaster) Name() string { return "NullEventBroadcaster" } - -// Start does no-op. -func (*NullEventBroadcaster) Start(context.Context) error { return nil } - -// Close does no-op. -func (*NullEventBroadcaster) Close() error { return nil } - -// Ready does no-op. -func (*NullEventBroadcaster) Ready() error { return nil } - -// HealthReport does no-op -func (*NullEventBroadcaster) HealthReport() map[string]error { return map[string]error{} } - -func (ne *NullEventBroadcaster) Subscribe(channel, payloadFilter string) (Subscription, error) { - return ne.Sub, nil -} -func (*NullEventBroadcaster) Notify(channel string, payload string) error { return nil } - -var _ Subscription = &NullSubscription{} - -type NullSubscription struct { - Ch chan (Event) -} - -func (ns *NullSubscription) Events() <-chan Event { return ns.Ch } -func (ns *NullSubscription) Close() {} -func (ns *NullSubscription) ChannelName() string { return "" } -func (ns *NullSubscription) InterestedIn(event Event) bool { return false } -func (ns *NullSubscription) Send(event Event) {} diff --git a/core/services/pg/event_broadcaster_test.go b/core/services/pg/event_broadcaster_test.go deleted file mode 100644 index 41dcbb0176f..00000000000 --- a/core/services/pg/event_broadcaster_test.go +++ /dev/null @@ -1,240 +0,0 @@ -package pg_test - -import ( - "sync" - "testing" - "time" - - "github.com/google/uuid" - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" -) - -func TestEventBroadcaster(t *testing.T) { - config, _ := heavyweight.FullTestDBNoFixturesV2(t, nil) - - eventBroadcaster := pg.NewEventBroadcaster(config.Database().URL(), 0, 0, logger.TestLogger(t), uuid.New()) - require.NoError(t, eventBroadcaster.Start(testutils.Context(t))) - t.Cleanup(func() { require.NoError(t, eventBroadcaster.Close()) }) - - t.Run("doesn't broadcast unrelated events (no payload filter)", func(t *testing.T) { - sub, err := eventBroadcaster.Subscribe("foo", "") - require.NoError(t, err) - defer sub.Close() - - go func() { - err := eventBroadcaster.Notify("bar", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("fooo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("fo", "123") - require.NoError(t, err) - }() - - ch := sub.Events() - gomega.NewWithT(t).Consistently(ch).ShouldNot(gomega.Receive()) - }) - - t.Run("doesn't broadcast unrelated events (with payload filter)", func(t *testing.T) { - sub, err := eventBroadcaster.Subscribe("foo", "123") - require.NoError(t, err) - defer sub.Close() - - go func() { - err := eventBroadcaster.Notify("foo", "asdf") - require.NoError(t, err) - err = eventBroadcaster.Notify("bar", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("fooo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("fo", "123") - require.NoError(t, err) - }() - - ch := sub.Events() - gomega.NewWithT(t).Consistently(ch).ShouldNot(gomega.Receive()) - }) - - t.Run("does broadcast related events (no payload filter)", func(t *testing.T) { - sub, err := eventBroadcaster.Subscribe("foo", "") - require.NoError(t, err) - defer sub.Close() - - go func() { - err := eventBroadcaster.Notify("foo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "aslkdjslkdfj") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "true") - require.NoError(t, err) - }() - - ch := sub.Events() - gomega.NewWithT(t).Eventually(ch).Should(gomega.Receive()) - gomega.NewWithT(t).Eventually(ch).Should(gomega.Receive()) - gomega.NewWithT(t).Eventually(ch).Should(gomega.Receive()) - }) - - t.Run("does broadcast related events (with payload filter)", func(t *testing.T) { - sub, err := eventBroadcaster.Subscribe("foo", "123") - require.NoError(t, err) - defer sub.Close() - - go func() { - err := eventBroadcaster.Notify("foo", "asdf") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "true") - require.NoError(t, err) - }() - - ch := sub.Events() - gomega.NewWithT(t).Eventually(ch).Should(gomega.Receive()) - gomega.NewWithT(t).Eventually(ch).Should(gomega.Receive()) - gomega.NewWithT(t).Consistently(ch).ShouldNot(gomega.Receive()) - }) - - t.Run("broadcasts to the correct subscribers", func(t *testing.T) { - sub1, err := eventBroadcaster.Subscribe("foo", "") - require.NoError(t, err) - defer sub1.Close() - - sub2, err := eventBroadcaster.Subscribe("foo", "123") - require.NoError(t, err) - defer sub2.Close() - - sub3, err := eventBroadcaster.Subscribe("bar", "") - require.NoError(t, err) - defer sub3.Close() - - sub4, err := eventBroadcaster.Subscribe("bar", "asdf") - require.NoError(t, err) - defer sub4.Close() - - var wg sync.WaitGroup - wg.Add(5) - - recv := func(ch <-chan pg.Event) pg.Event { - select { - case e := <-ch: - return e - case <-time.After(5 * time.Second): - t.Fatal("did not receive") - } - return pg.Event{} - } - - go func() { - defer wg.Done() - err := eventBroadcaster.Notify("foo", "asdf") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("foo", "true") - require.NoError(t, err) - - err = eventBroadcaster.Notify("bar", "asdf") - require.NoError(t, err) - err = eventBroadcaster.Notify("bar", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("bar", "123") - require.NoError(t, err) - err = eventBroadcaster.Notify("bar", "true") - require.NoError(t, err) - }() - - go func() { - defer wg.Done() - e := recv(sub1.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "asdf", e.Payload) - - e = recv(sub1.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "123", e.Payload) - - e = recv(sub1.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "123", e.Payload) - - e = recv(sub1.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "true", e.Payload) - - gomega.NewWithT(t).Consistently(sub1.Events()).ShouldNot(gomega.Receive()) - }() - - go func() { - defer wg.Done() - e := recv(sub2.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "123", e.Payload) - - e = recv(sub2.Events()) - require.Equal(t, "foo", e.Channel) - require.Equal(t, "123", e.Payload) - - gomega.NewWithT(t).Consistently(sub2.Events()).ShouldNot(gomega.Receive()) - }() - - go func() { - defer wg.Done() - e := recv(sub3.Events()) - require.Equal(t, "bar", e.Channel) - require.Equal(t, "asdf", e.Payload) - - e = recv(sub3.Events()) - require.Equal(t, "bar", e.Channel) - require.Equal(t, "123", e.Payload) - - e = recv(sub3.Events()) - require.Equal(t, "bar", e.Channel) - require.Equal(t, "123", e.Payload) - - e = recv(sub3.Events()) - require.Equal(t, "bar", e.Channel) - require.Equal(t, "true", e.Payload) - - gomega.NewWithT(t).Consistently(sub3.Events()).ShouldNot(gomega.Receive()) - }() - - go func() { - defer wg.Done() - e := recv(sub4.Events()) - require.Equal(t, "bar", e.Channel) - require.Equal(t, "asdf", e.Payload) - - gomega.NewWithT(t).Consistently(sub4.Events()).ShouldNot(gomega.Receive()) - }() - - wg.Wait() - }) - - t.Run("closes events channel on subscription close", func(t *testing.T) { - sub, err := eventBroadcaster.Subscribe("foo", "") - require.NoError(t, err) - - chEvents := sub.Events() - - sub.Close() - - select { - case _, ok := <-chEvents: - if ok { - t.Fatal("expected chEvents to be closed") - } - default: - t.Fatal("expected chEvents to not block") - } - }) -} diff --git a/core/services/pg/lease_lock.go b/core/services/pg/lease_lock.go index e21cec44bda..58ec2781245 100644 --- a/core/services/pg/lease_lock.go +++ b/core/services/pg/lease_lock.go @@ -12,8 +12,8 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // LeaseLock handles taking an exclusive lease on database access. This is not diff --git a/core/services/pg/locked_db_test.go b/core/services/pg/locked_db_test.go index a2aebcd57f4..ed0935c1411 100644 --- a/core/services/pg/locked_db_test.go +++ b/core/services/pg/locked_db_test.go @@ -5,12 +5,12 @@ import ( "testing" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "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/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/stretchr/testify/require" ) @@ -18,8 +18,8 @@ import ( func lease(c *chainlink.Config, s *chainlink.Secrets) { t := true c.Database.Lock.Enabled = &t - c.Database.Lock.LeaseDuration = models.MustNewDuration(10 * time.Second) - c.Database.Lock.LeaseRefreshInterval = models.MustNewDuration(time.Second) + c.Database.Lock.LeaseDuration = commonconfig.MustNewDuration(10 * time.Second) + c.Database.Lock.LeaseRefreshInterval = commonconfig.MustNewDuration(time.Second) } func TestLockedDB_HappyPath(t *testing.T) { diff --git a/core/services/pg/mocks/event_broadcaster.go b/core/services/pg/mocks/event_broadcaster.go deleted file mode 100644 index b4d04b8b999..00000000000 --- a/core/services/pg/mocks/event_broadcaster.go +++ /dev/null @@ -1,141 +0,0 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. - -package mocks - -import ( - context "context" - - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - mock "github.com/stretchr/testify/mock" -) - -// EventBroadcaster is an autogenerated mock type for the EventBroadcaster type -type EventBroadcaster struct { - mock.Mock -} - -// Close provides a mock function with given fields: -func (_m *EventBroadcaster) Close() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// HealthReport provides a mock function with given fields: -func (_m *EventBroadcaster) HealthReport() map[string]error { - ret := _m.Called() - - var r0 map[string]error - if rf, ok := ret.Get(0).(func() map[string]error); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]error) - } - } - - return r0 -} - -// Name provides a mock function with given fields: -func (_m *EventBroadcaster) Name() string { - ret := _m.Called() - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// Notify provides a mock function with given fields: channel, payload -func (_m *EventBroadcaster) Notify(channel string, payload string) error { - ret := _m.Called(channel, payload) - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(channel, payload) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Ready provides a mock function with given fields: -func (_m *EventBroadcaster) Ready() error { - ret := _m.Called() - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Start provides a mock function with given fields: _a0 -func (_m *EventBroadcaster) Start(_a0 context.Context) error { - ret := _m.Called(_a0) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Subscribe provides a mock function with given fields: channel, payloadFilter -func (_m *EventBroadcaster) Subscribe(channel string, payloadFilter string) (pg.Subscription, error) { - ret := _m.Called(channel, payloadFilter) - - var r0 pg.Subscription - var r1 error - if rf, ok := ret.Get(0).(func(string, string) (pg.Subscription, error)); ok { - return rf(channel, payloadFilter) - } - if rf, ok := ret.Get(0).(func(string, string) pg.Subscription); ok { - r0 = rf(channel, payloadFilter) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(pg.Subscription) - } - } - - if rf, ok := ret.Get(1).(func(string, string) error); ok { - r1 = rf(channel, payloadFilter) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// NewEventBroadcaster creates a new instance of EventBroadcaster. 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 NewEventBroadcaster(t interface { - mock.TestingT - Cleanup(func()) -}) *EventBroadcaster { - mock := &EventBroadcaster{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/pg/mocks/subscription.go b/core/services/pg/mocks/subscription.go deleted file mode 100644 index 9cfe4c4f020..00000000000 --- a/core/services/pg/mocks/subscription.go +++ /dev/null @@ -1,81 +0,0 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. - -package mocks - -import ( - pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" - mock "github.com/stretchr/testify/mock" -) - -// Subscription is an autogenerated mock type for the Subscription type -type Subscription struct { - mock.Mock -} - -// ChannelName provides a mock function with given fields: -func (_m *Subscription) ChannelName() string { - ret := _m.Called() - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// Close provides a mock function with given fields: -func (_m *Subscription) Close() { - _m.Called() -} - -// Events provides a mock function with given fields: -func (_m *Subscription) Events() <-chan pg.Event { - ret := _m.Called() - - var r0 <-chan pg.Event - if rf, ok := ret.Get(0).(func() <-chan pg.Event); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(<-chan pg.Event) - } - } - - return r0 -} - -// InterestedIn provides a mock function with given fields: event -func (_m *Subscription) InterestedIn(event pg.Event) bool { - ret := _m.Called(event) - - var r0 bool - if rf, ok := ret.Get(0).(func(pg.Event) bool); ok { - r0 = rf(event) - } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// Send provides a mock function with given fields: event -func (_m *Subscription) Send(event pg.Event) { - _m.Called(event) -} - -// NewSubscription creates a new instance of Subscription. 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 NewSubscription(t interface { - mock.TestingT - Cleanup(func()) -}) *Subscription { - mock := &Subscription{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/services/pg/q.go b/core/services/pg/q.go index 050606c7937..ba2627fa745 100644 --- a/core/services/pg/q.go +++ b/core/services/pg/q.go @@ -118,7 +118,7 @@ type Q struct { Queryer ParentCtx context.Context db *sqlx.DB - logger logger.Logger + logger logger.SugaredLogger config QConfig QueryTimeout time.Duration } @@ -130,7 +130,7 @@ func NewQ(db *sqlx.DB, lggr logger.Logger, config QConfig, qopts ...QOpt) (q Q) q.db = db // skip two levels since we use internal helpers and also want to point up the stack to the caller of the Q method. - q.logger = logger.Helper(lggr, 2) + q.logger = logger.Sugared(logger.Helper(lggr, 2)) q.config = config if q.Queryer == nil { @@ -154,6 +154,7 @@ func PrepareQueryRowx(q Queryer, sql string, dest interface{}, arg interface{}) if err != nil { return errors.Wrap(err, "error preparing named statement") } + defer stmt.Close() return errors.Wrap(stmt.QueryRowx(arg).Scan(dest), "error querying row") } @@ -356,7 +357,7 @@ func (q *queryLogger) postSqlLog(ctx context.Context, begin time.Time) { kvs := []any{"ms", elapsed.Milliseconds(), "timeout", timeout.Milliseconds(), "percent", strconv.FormatFloat(pct, 'f', 1, 64), "sql", q} if elapsed >= timeout { - logger.Criticalw(q.logger, "SLOW SQL QUERY", kvs...) + q.logger.Criticalw("SLOW SQL QUERY", kvs...) } else if errThreshold := timeout / 5; errThreshold > 0 && elapsed > errThreshold { q.logger.Errorw("SLOW SQL QUERY", kvs...) } else if warnThreshold := timeout / 10; warnThreshold > 0 && elapsed > warnThreshold { diff --git a/core/services/pg/transaction.go b/core/services/pg/transaction.go index fd7e74baca3..d60270b4fe8 100644 --- a/core/services/pg/transaction.go +++ b/core/services/pg/transaction.go @@ -78,7 +78,7 @@ func sqlxTransactionQ(ctx context.Context, db txBeginner, lggr logger.Logger, fn panic(fmt.Sprintf("panic in transaction; aborting rollback that took longer than 10s: %s", p)) } } else if err != nil { - lggr.Errorf("Error in transaction, rolling back: %s", err) + lggr.Warnf("Error in transaction, rolling back: %s", err) // An error occurred, rollback and return error if rerr := tx.Rollback(); rerr != nil { err = multierr.Combine(err, errors.WithStack(rerr)) diff --git a/core/services/pipeline/common.go b/core/services/pipeline/common.go index 8cc54d540fb..6efa7aa2148 100644 --- a/core/services/pipeline/common.go +++ b/core/services/pipeline/common.go @@ -20,28 +20,30 @@ import ( pkgerrors "github.com/pkg/errors" "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + cutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" "github.com/smartcontractkit/chainlink/v2/core/logger" cnull "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) const ( + BlockHeaderFeederJobType string = "blockheaderfeeder" + BlockhashStoreJobType string = "blockhashstore" + BootstrapJobType string = "bootstrap" CronJobType string = "cron" DirectRequestJobType string = "directrequest" FluxMonitorJobType string = "fluxmonitor" - OffchainReportingJobType string = "offchainreporting" - OffchainReporting2JobType string = "offchainreporting2" - KeeperJobType string = "keeper" - VRFJobType string = "vrf" - BlockhashStoreJobType string = "blockhashstore" - BlockHeaderFeederJobType string = "blockheaderfeeder" - WebhookJobType string = "webhook" - BootstrapJobType string = "bootstrap" GatewayJobType string = "gateway" + KeeperJobType string = "keeper" LegacyGasStationServerJobType string = "legacygasstationserver" LegacyGasStationSidecarJobType string = "legacygasstationsidecar" + OffchainReporting2JobType string = "offchainreporting2" + OffchainReportingJobType string = "offchainreporting" + StreamJobType string = "stream" + VRFJobType string = "vrf" + WebhookJobType string = "webhook" ) //go:generate mockery --quiet --name Config --output ./mocks/ --case=underscore @@ -64,7 +66,7 @@ type ( Config interface { DefaultHTTPLimit() int64 - DefaultHTTPTimeout() models.Duration + DefaultHTTPTimeout() commonconfig.Duration MaxRunDuration() time.Duration ReaperInterval() time.Duration ReaperThreshold() time.Duration @@ -409,7 +411,7 @@ var ( ) func UnmarshalTaskFromMap(taskType TaskType, taskMap interface{}, ID int, dotID string) (_ Task, err error) { - defer utils.WrapIfError(&err, "UnmarshalTaskFromMap") + defer cutils.WrapIfError(&err, "UnmarshalTaskFromMap") switch taskMap.(type) { default: diff --git a/core/services/pipeline/internal/eautils/eautils.go b/core/services/pipeline/internal/eautils/eautils.go new file mode 100644 index 00000000000..30faa826b22 --- /dev/null +++ b/core/services/pipeline/internal/eautils/eautils.go @@ -0,0 +1,39 @@ +package eautils + +import ( + "encoding/json" + "net/http" +) + +type AdapterStatus struct { + ErrorMessage *string `json:"errorMessage"` + Error any `json:"error"` + StatusCode *int `json:"statusCode"` + ProviderStatusCode *int `json:"providerStatusCode"` +} + +func BestEffortExtractEAStatus(responseBytes []byte) (code int, ok bool) { + var status AdapterStatus + err := json.Unmarshal(responseBytes, &status) + if err != nil { + return 0, false + } + + if status.StatusCode == nil { + return 0, false + } + + if *status.StatusCode != http.StatusOK { + return *status.StatusCode, true + } + + if status.ProviderStatusCode != nil && *status.ProviderStatusCode != http.StatusOK { + return *status.ProviderStatusCode, true + } + + if status.Error != nil { + return http.StatusInternalServerError, true + } + + return *status.StatusCode, true +} diff --git a/core/services/pipeline/internal/eautils/eautils_test.go b/core/services/pipeline/internal/eautils/eautils_test.go new file mode 100644 index 00000000000..80183b80d2b --- /dev/null +++ b/core/services/pipeline/internal/eautils/eautils_test.go @@ -0,0 +1,61 @@ +package eautils + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBestEffortExtractEAStatus(t *testing.T) { + tests := []struct { + name string + arg []byte + expectCode int + expectOk bool + }{ + { + name: "invalid object", + arg: []byte(`{"error": "invalid json object" `), + expectCode: 0, + expectOk: false, + }, + { + name: "no status code in object", + arg: []byte(`{}`), + expectCode: 0, + expectOk: false, + }, + { + name: "invalid status code", + arg: []byte(`{"statusCode":400}`), + expectCode: http.StatusBadRequest, + expectOk: true, + }, + { + name: "invalid provider status code", + arg: []byte(`{"statusCode":200, "providerStatusCode":500}`), + expectCode: http.StatusInternalServerError, + expectOk: true, + }, + { + name: "valid statuses with error message", + arg: []byte(`{"statusCode":200, "providerStatusCode":200, "error": "unexpected error"}`), + expectCode: http.StatusInternalServerError, + expectOk: true, + }, + { + name: "valid status code", + arg: []byte(`{"statusCode":200}`), + expectCode: http.StatusOK, + expectOk: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + code, ok := BestEffortExtractEAStatus(tt.arg) + assert.Equal(t, tt.expectCode, code) + assert.Equal(t, tt.expectOk, ok) + }) + } +} diff --git a/core/services/pipeline/mocks/config.go b/core/services/pipeline/mocks/config.go index eb9a411f423..581a84dc049 100644 --- a/core/services/pipeline/mocks/config.go +++ b/core/services/pipeline/mocks/config.go @@ -1,9 +1,9 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks import ( - models "github.com/smartcontractkit/chainlink/v2/core/store/models" + config "github.com/smartcontractkit/chainlink-common/pkg/config" mock "github.com/stretchr/testify/mock" time "time" @@ -18,6 +18,10 @@ type Config struct { func (_m *Config) DefaultHTTPLimit() int64 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for DefaultHTTPLimit") + } + var r0 int64 if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() @@ -29,14 +33,18 @@ func (_m *Config) DefaultHTTPLimit() int64 { } // DefaultHTTPTimeout provides a mock function with given fields: -func (_m *Config) DefaultHTTPTimeout() models.Duration { +func (_m *Config) DefaultHTTPTimeout() config.Duration { ret := _m.Called() - var r0 models.Duration - if rf, ok := ret.Get(0).(func() models.Duration); ok { + if len(ret) == 0 { + panic("no return value specified for DefaultHTTPTimeout") + } + + var r0 config.Duration + if rf, ok := ret.Get(0).(func() config.Duration); ok { r0 = rf() } else { - r0 = ret.Get(0).(models.Duration) + r0 = ret.Get(0).(config.Duration) } return r0 @@ -46,6 +54,10 @@ func (_m *Config) DefaultHTTPTimeout() models.Duration { func (_m *Config) MaxRunDuration() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for MaxRunDuration") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -60,6 +72,10 @@ func (_m *Config) MaxRunDuration() time.Duration { func (_m *Config) ReaperInterval() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ReaperInterval") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() @@ -74,6 +90,10 @@ func (_m *Config) ReaperInterval() time.Duration { func (_m *Config) ReaperThreshold() time.Duration { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ReaperThreshold") + } + var r0 time.Duration if rf, ok := ret.Get(0).(func() time.Duration); ok { r0 = rf() diff --git a/core/services/pipeline/mocks/orm.go b/core/services/pipeline/mocks/orm.go index 88d067c6ffa..759686204d4 100644 --- a/core/services/pipeline/mocks/orm.go +++ b/core/services/pipeline/mocks/orm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -26,6 +26,10 @@ type ORM struct { func (_m *ORM) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -47,6 +51,10 @@ func (_m *ORM) CreateRun(run *pipeline.Run, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + 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...) @@ -68,6 +76,10 @@ func (_m *ORM) CreateSpec(_a0 pipeline.Pipeline, maxTaskTimeout models.Interval, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for CreateSpec") + } + var r0 int32 var r1 error if rf, ok := ret.Get(0).(func(pipeline.Pipeline, models.Interval, ...pg.QOpt) (int32, error)); ok { @@ -92,6 +104,10 @@ func (_m *ORM) CreateSpec(_a0 pipeline.Pipeline, maxTaskTimeout models.Interval, func (_m *ORM) DeleteRun(id int64) error { ret := _m.Called(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) @@ -106,6 +122,10 @@ func (_m *ORM) DeleteRun(id int64) error { func (_m *ORM) DeleteRunsOlderThan(_a0 context.Context, _a1 time.Duration) error { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for DeleteRunsOlderThan") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Duration) error); ok { r0 = rf(_a0, _a1) @@ -120,6 +140,10 @@ func (_m *ORM) DeleteRunsOlderThan(_a0 context.Context, _a1 time.Duration) error func (_m *ORM) FindRun(id int64) (pipeline.Run, error) { ret := _m.Called(id) + if len(ret) == 0 { + panic("no return value specified for FindRun") + } + var r0 pipeline.Run var r1 error if rf, ok := ret.Get(0).(func(int64) (pipeline.Run, error)); ok { @@ -144,6 +168,10 @@ func (_m *ORM) FindRun(id int64) (pipeline.Run, error) { func (_m *ORM) GetAllRuns() ([]pipeline.Run, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for GetAllRuns") + } + var r0 []pipeline.Run var r1 error if rf, ok := ret.Get(0).(func() ([]pipeline.Run, error)); ok { @@ -170,6 +198,10 @@ func (_m *ORM) GetAllRuns() ([]pipeline.Run, error) { 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() @@ -184,6 +216,10 @@ func (_m *ORM) GetQ() pg.Q { func (_m *ORM) GetUnfinishedRuns(_a0 context.Context, _a1 time.Time, _a2 func(pipeline.Run) error) error { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for GetUnfinishedRuns") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, time.Time, func(pipeline.Run) error) error); ok { r0 = rf(_a0, _a1, _a2) @@ -198,6 +234,10 @@ func (_m *ORM) GetUnfinishedRuns(_a0 context.Context, _a1 time.Time, _a2 func(pi func (_m *ORM) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -221,6 +261,10 @@ func (_m *ORM) InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bool, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + 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...) @@ -242,6 +286,10 @@ func (_m *ORM) InsertFinishedRuns(run []*pipeline.Run, saveSuccessfulTaskRuns bo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + 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...) @@ -263,6 +311,10 @@ func (_m *ORM) InsertRun(run *pipeline.Run, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + 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...) @@ -277,6 +329,10 @@ func (_m *ORM) InsertRun(run *pipeline.Run, qopts ...pg.QOpt) error { func (_m *ORM) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -291,6 +347,10 @@ func (_m *ORM) Name() string { func (_m *ORM) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -305,6 +365,10 @@ func (_m *ORM) Ready() error { func (_m *ORM) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -326,6 +390,10 @@ func (_m *ORM) StoreRun(run *pipeline.Run, qopts ...pg.QOpt) (bool, error) { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for StoreRun") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*pipeline.Run, ...pg.QOpt) (bool, error)); ok { @@ -350,6 +418,10 @@ func (_m *ORM) StoreRun(run *pipeline.Run, qopts ...pg.QOpt) (bool, error) { func (_m *ORM) UpdateTaskRunResult(taskID uuid.UUID, result pipeline.Result) (pipeline.Run, bool, error) { ret := _m.Called(taskID, result) + if len(ret) == 0 { + panic("no return value specified for UpdateTaskRunResult") + } + var r0 pipeline.Run var r1 bool var r2 error diff --git a/core/services/pipeline/mocks/pipeline_param_unmarshaler.go b/core/services/pipeline/mocks/pipeline_param_unmarshaler.go index 3478ce1322d..40f2ba4dd32 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -13,6 +13,10 @@ type PipelineParamUnmarshaler struct { func (_m *PipelineParamUnmarshaler) UnmarshalPipelineParam(val interface{}) error { ret := _m.Called(val) + if len(ret) == 0 { + panic("no return value specified for UnmarshalPipelineParam") + } + var r0 error if rf, ok := ret.Get(0).(func(interface{}) error); ok { r0 = rf(val) diff --git a/core/services/pipeline/mocks/runner.go b/core/services/pipeline/mocks/runner.go index 34b55399752..f6e5033eae9 100644 --- a/core/services/pipeline/mocks/runner.go +++ b/core/services/pipeline/mocks/runner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -24,6 +24,10 @@ type Runner struct { func (_m *Runner) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -38,6 +42,10 @@ func (_m *Runner) Close() error { func (_m *Runner) ExecuteAndInsertFinishedRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger, saveSuccessfulTaskRuns bool) (int64, pipeline.FinalResult, error) { ret := _m.Called(ctx, spec, vars, l, saveSuccessfulTaskRuns) + if len(ret) == 0 { + panic("no return value specified for ExecuteAndInsertFinishedRun") + } + var r0 int64 var r1 pipeline.FinalResult var r2 error @@ -69,6 +77,10 @@ func (_m *Runner) ExecuteAndInsertFinishedRun(ctx context.Context, spec pipeline func (_m *Runner) ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (*pipeline.Run, pipeline.TaskRunResults, error) { ret := _m.Called(ctx, spec, vars, l) + if len(ret) == 0 { + panic("no return value specified for ExecuteRun") + } + var r0 *pipeline.Run var r1 pipeline.TaskRunResults var r2 error @@ -104,6 +116,10 @@ func (_m *Runner) ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipel func (_m *Runner) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -127,6 +143,10 @@ func (_m *Runner) InsertFinishedRun(run *pipeline.Run, saveSuccessfulTaskRuns bo _ca = append(_ca, _va...) ret := _m.Called(_ca...) + 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...) @@ -148,6 +168,10 @@ func (_m *Runner) InsertFinishedRuns(runs []*pipeline.Run, saveSuccessfulTaskRun _ca = append(_ca, _va...) ret := _m.Called(_ca...) + 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...) @@ -162,6 +186,10 @@ func (_m *Runner) InsertFinishedRuns(runs []*pipeline.Run, saveSuccessfulTaskRun func (_m *Runner) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -181,6 +209,10 @@ func (_m *Runner) OnRunFinished(_a0 func(*pipeline.Run)) { func (_m *Runner) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -195,6 +227,10 @@ func (_m *Runner) Ready() error { func (_m *Runner) ResumeRun(taskID uuid.UUID, value interface{}, err error) error { ret := _m.Called(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) @@ -209,6 +245,10 @@ func (_m *Runner) ResumeRun(taskID uuid.UUID, value interface{}, err error) erro func (_m *Runner) Run(ctx context.Context, run *pipeline.Run, l logger.Logger, saveSuccessfulTaskRuns bool, fn func(pg.Queryer) error) (bool, error) { ret := _m.Called(ctx, run, l, saveSuccessfulTaskRuns, fn) + if len(ret) == 0 { + panic("no return value specified for Run") + } + 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 { @@ -233,6 +273,10 @@ func (_m *Runner) Run(ctx context.Context, run *pipeline.Run, l logger.Logger, s func (_m *Runner) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/pipeline/models.go b/core/services/pipeline/models.go index cfabae82772..d2c722f98b8 100644 --- a/core/services/pipeline/models.go +++ b/core/services/pipeline/models.go @@ -28,9 +28,18 @@ type Spec struct { JobID int32 `json:"-"` JobName string `json:"-"` JobType string `json:"-"` + + Pipeline *Pipeline `json:"-" db:"-"` // This may be nil, or may be populated manually as a cache. There is no locking on this, so be careful +} + +func (s *Spec) GetOrParsePipeline() (*Pipeline, error) { + if s.Pipeline != nil { + return s.Pipeline, nil + } + return s.ParsePipeline() } -func (s Spec) Pipeline() (*Pipeline, error) { +func (s *Spec) ParsePipeline() (*Pipeline, error) { return Parse(s.DotDagSource) } @@ -66,7 +75,7 @@ func (r *Run) SetID(value string) error { if err != nil { return err } - r.ID = int64(ID) + r.ID = ID return nil } diff --git a/core/services/pipeline/orm.go b/core/services/pipeline/orm.go index eb242e62765..70ff244ab3c 100644 --- a/core/services/pipeline/orm.go +++ b/core/services/pipeline/orm.go @@ -346,6 +346,7 @@ RETURNING id if errQ != nil { return errors.Wrap(errQ, "inserting finished pipeline runs") } + defer rows.Close() var runIDs []int64 for rows.Next() { diff --git a/core/services/pipeline/orm_test.go b/core/services/pipeline/orm_test.go index dcbbfd9c97e..5578bdcd4ca 100644 --- a/core/services/pipeline/orm_test.go +++ b/core/services/pipeline/orm_test.go @@ -12,7 +12,9 @@ import ( "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" "github.com/smartcontractkit/chainlink/v2/core/bridges" + "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/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -24,7 +26,6 @@ import ( "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" ) type ormconfig struct { @@ -290,7 +291,7 @@ func Test_PipelineORM_StoreRun_DetectsRestarts(t *testing.T) { ds1_id := uuid.New() // insert something for this pipeline_run to trigger an early resume while the pipeline is running - _, err = db.NamedQuery(` + rows, err := db.NamedQuery(` 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) `, pipeline.TaskRun{ @@ -303,6 +304,7 @@ func Test_PipelineORM_StoreRun_DetectsRestarts(t *testing.T) { FinishedAt: null.TimeFrom(now), }) require.NoError(t, err) + t.Cleanup(func() { assert.NoError(t, rows.Close()) }) run.PipelineTaskRuns = []pipeline.TaskRun{ // pending task @@ -347,7 +349,7 @@ func Test_PipelineORM_StoreRun_UpdateTaskRunResult(t *testing.T) { ds1_id := uuid.New() now := time.Now() - address, err := utils.TryParseHex("0x8bd112d3f8f92e41c861939545ad387307af9703") + address, err := hex.DecodeString("0x8bd112d3f8f92e41c861939545ad387307af9703") require.NoError(t, err) cborOutput := map[string]interface{}{ "blockNum": "0x13babbd", @@ -531,7 +533,7 @@ func Test_GetUnfinishedRuns_Keepers(t *testing.T) { FromAddress: cltest.NewEIP55Address(), CreatedAt: timestamp, UpdatedAt: timestamp, - EVMChainID: (*utils.Big)(&cltest.FixtureChainID), + EVMChainID: (*big.Big)(&cltest.FixtureChainID), }, ExternalJobID: uuid.MustParse("0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46"), PipelineSpec: &pipeline.Spec{ @@ -630,7 +632,7 @@ func Test_GetUnfinishedRuns_DirectRequest(t *testing.T) { ContractAddress: cltest.NewEIP55Address(), CreatedAt: timestamp, UpdatedAt: timestamp, - EVMChainID: (*utils.Big)(&cltest.FixtureChainID), + EVMChainID: (*big.Big)(&cltest.FixtureChainID), }, ExternalJobID: uuid.MustParse("0EEC7E1D-D0D2-476C-A1A8-72DFB6633F46"), PipelineSpec: &pipeline.Spec{ diff --git a/core/services/pipeline/runner.go b/core/services/pipeline/runner.go index 768f163f9b1..a432d9fec11 100644 --- a/core/services/pipeline/runner.go +++ b/core/services/pipeline/runner.go @@ -15,6 +15,8 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/services" + commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" + "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -60,7 +62,7 @@ type runner struct { legacyEVMChains legacyevm.LegacyChainContainer ethKeyStore ETHKeyStore vrfKeyStore VRFKeyStore - runReaperWorker utils.SleeperTask + runReaperWorker *commonutils.SleeperTask lggr logger.Logger httpClient *http.Client unrestrictedHTTPClient *http.Client @@ -118,8 +120,8 @@ func NewRunner(orm ORM, btORM bridges.ORM, cfg Config, bridgeCfg BridgeConfig, l httpClient: httpClient, unrestrictedHTTPClient: unrestrictedHTTPClient, } - r.runReaperWorker = utils.NewSleeperTask( - utils.SleeperFuncTask(r.runReaper, "PipelineRunnerReaper"), + r.runReaperWorker = commonutils.NewSleeperTask( + commonutils.SleeperFuncTask(r.runReaper, "PipelineRunnerReaper"), ) return r } @@ -211,35 +213,62 @@ func (r *runner) OnRunFinished(fn func(*Run)) { r.runFinished = fn } -// Be careful with the ctx passed in here: it applies to requests in individual -// tasks but should _not_ apply to the scheduler or run itself +// github.com/smartcontractkit/libocr/offchainreporting2plus/internal/protocol.ReportingPluginTimeoutWarningGracePeriod +var overtime = 100 * time.Millisecond + +func init() { + // undocumented escape hatch + if v := env.PipelineOvertime.Get(); v != "" { + d, err := time.ParseDuration(v) + if err == nil { + overtime = d + } + } +} + func (r *runner) ExecuteRun( ctx context.Context, spec Spec, vars Vars, l logger.Logger, ) (*Run, TaskRunResults, error) { - run := NewRun(spec, vars) - - pipeline, err := r.initializePipeline(run) + // Pipeline runs may return results after the context is cancelled, so we modify the + // deadline to give them time to return before the parent context deadline. + var cancel func() + ctx, cancel = commonutils.ContextWithDeadlineFn(ctx, func(orig time.Time) time.Time { + if tenPct := time.Until(orig) / 10; overtime > tenPct { + return orig.Add(-tenPct) + } + return orig.Add(-overtime) + }) + defer cancel() - if err != nil { - return run, nil, err + var pipeline *Pipeline + if spec.Pipeline != nil { + // assume if set that it has been pre-initialized + pipeline = spec.Pipeline + } else { + var err error + pipeline, err = r.InitializePipeline(spec) + if err != nil { + return nil, nil, err + } } + run := NewRun(spec, vars) taskRunResults := r.run(ctx, pipeline, run, vars, l) if run.Pending { - return run, nil, pkgerrors.Wrapf(err, "unexpected async run for spec ID %v, tried executing via ExecuteAndInsertFinishedRun", spec.ID) + return run, nil, fmt.Errorf("unexpected async run for spec ID %v, tried executing via ExecuteRun", spec.ID) } return run, taskRunResults, nil } -func (r *runner) initializePipeline(run *Run) (*Pipeline, error) { - pipeline, err := Parse(run.PipelineSpec.DotDagSource) +func (r *runner) InitializePipeline(spec Spec) (pipeline *Pipeline, err error) { + pipeline, err = spec.GetOrParsePipeline() if err != nil { - return nil, err + return } // initialize certain task params @@ -255,7 +284,7 @@ func (r *runner) initializePipeline(run *Run) (*Pipeline, error) { task.(*BridgeTask).config = r.config task.(*BridgeTask).bridgeConfig = r.bridgeConfig task.(*BridgeTask).orm = r.btORM - task.(*BridgeTask).specId = run.PipelineSpec.ID + task.(*BridgeTask).specId = spec.ID // URL is "safe" because it comes from the node's own database. We // must use the unrestrictedHTTPClient because some node operators // may run external adapters on their own hardware @@ -263,8 +292,8 @@ func (r *runner) initializePipeline(run *Run) (*Pipeline, error) { case TaskTypeETHCall: task.(*ETHCallTask).legacyChains = r.legacyEVMChains task.(*ETHCallTask).config = r.config - task.(*ETHCallTask).specGasLimit = run.PipelineSpec.GasLimit - task.(*ETHCallTask).jobType = run.PipelineSpec.JobType + task.(*ETHCallTask).specGasLimit = spec.GasLimit + task.(*ETHCallTask).jobType = spec.JobType case TaskTypeVRF: task.(*VRFTask).keyStore = r.vrfKeyStore case TaskTypeVRFV2: @@ -273,28 +302,18 @@ func (r *runner) initializePipeline(run *Run) (*Pipeline, error) { task.(*VRFTaskV2Plus).keyStore = r.vrfKeyStore case TaskTypeEstimateGasLimit: task.(*EstimateGasLimitTask).legacyChains = r.legacyEVMChains - task.(*EstimateGasLimitTask).specGasLimit = run.PipelineSpec.GasLimit - task.(*EstimateGasLimitTask).jobType = run.PipelineSpec.JobType + task.(*EstimateGasLimitTask).specGasLimit = spec.GasLimit + task.(*EstimateGasLimitTask).jobType = spec.JobType case TaskTypeETHTx: task.(*ETHTxTask).keyStore = r.ethKeyStore task.(*ETHTxTask).legacyChains = r.legacyEVMChains - task.(*ETHTxTask).specGasLimit = run.PipelineSpec.GasLimit - task.(*ETHTxTask).jobType = run.PipelineSpec.JobType - task.(*ETHTxTask).forwardingAllowed = run.PipelineSpec.ForwardingAllowed + task.(*ETHTxTask).specGasLimit = spec.GasLimit + task.(*ETHTxTask).jobType = spec.JobType + task.(*ETHTxTask).forwardingAllowed = spec.ForwardingAllowed default: } } - // retain old UUID values - for _, taskRun := range run.PipelineTaskRuns { - task := pipeline.ByDotID(taskRun.DotID) - if task != nil && task.Base() != nil { - task.Base().uuid = taskRun.ID - } else { - return nil, pkgerrors.Errorf("failed to match a pipeline task for dot ID: %v", taskRun.DotID) - } - } - return pipeline, nil } @@ -519,11 +538,21 @@ 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) { - pipeline, err := r.initializePipeline(run) + pipeline, err := r.InitializePipeline(run.PipelineSpec) if err != nil { return false, err } + // retain old UUID values + for _, taskRun := range run.PipelineTaskRuns { + task := pipeline.ByDotID(taskRun.DotID) + if task != nil && task.Base() != nil { + task.Base().uuid = taskRun.ID + } else { + return false, pkgerrors.Errorf("failed to match a pipeline task for dot ID: %v", taskRun.DotID) + } + } + preinsert := pipeline.RequiresPreInsert() q := r.orm.GetQ().WithOpts(pg.WithParentCtx(ctx)) diff --git a/core/services/pipeline/runner_test.go b/core/services/pipeline/runner_test.go index 695590e7bd0..5b4aaef7e88 100644 --- a/core/services/pipeline/runner_test.go +++ b/core/services/pipeline/runner_test.go @@ -942,3 +942,43 @@ en->de require.NoError(t, err) assert.Equal(t, inputBytes, result.Value) } + +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() + relayExtenders := evmtest.NewChainRelayExtenders(t, evmtest.TestChainOpts{DB: db, GeneralConfig: cfg, KeyStore: ethKeyStore}) + legacyChains := evmrelay.NewLegacyChainsFromRelayerExtenders(relayExtenders) + lggr := logger.TestLogger(t) + r := pipeline.NewRunner(nil, nil, cfg.JobPipeline(), cfg.WebServer(), legacyChains, ethKeyStore, nil, lggr, nil, nil) + + template := ` +succeed [type=memo value=%d] +succeed; +` + + spec := pipeline.Spec{DotDagSource: fmt.Sprintf(template, 1)} + vars := pipeline.NewVarsFrom(nil) + + _, trrs, err := r.ExecuteRun(testutils.Context(t), spec, vars, lggr) + require.NoError(t, err) + require.Len(t, trrs, 1) + assert.Equal(t, "1", trrs[0].Result.Value.(pipeline.ObjectParam).DecimalValue.Decimal().String()) + + // does not automatically cache + require.Nil(t, spec.Pipeline) + + // initialize it + spec.Pipeline, err = spec.ParsePipeline() + require.NoError(t, err) + + // even though this is set to 2, it should use the cached version + spec.DotDagSource = fmt.Sprintf(template, 2) + + _, trrs, err = r.ExecuteRun(testutils.Context(t), spec, vars, lggr) + require.NoError(t, err) + require.Len(t, trrs, 1) + assert.Equal(t, "1", trrs[0].Result.Value.(pipeline.ObjectParam).DecimalValue.Decimal().String()) + }) +} diff --git a/core/services/pipeline/scheduler.go b/core/services/pipeline/scheduler.go index 7c6fd78d0c2..7663ed948ff 100644 --- a/core/services/pipeline/scheduler.go +++ b/core/services/pipeline/scheduler.go @@ -33,7 +33,7 @@ func (s *scheduler) newMemoryTaskRun(task Task, vars Vars) *memoryTaskRun { // if we're confident that indices are within range for _, i := range task.Inputs() { if i.PropagateResult { - inputs = append(inputs, input{index: int32(i.InputTask.OutputIndex()), result: s.results[i.InputTask.ID()].Result}) + inputs = append(inputs, input{index: i.InputTask.OutputIndex(), result: s.results[i.InputTask.ID()].Result}) } } sort.Slice(inputs, func(i, j int) bool { diff --git a/core/services/pipeline/task.bridge.go b/core/services/pipeline/task.bridge.go index fbf861857f5..1da34d19134 100644 --- a/core/services/pipeline/task.bridge.go +++ b/core/services/pipeline/task.bridge.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/internal/eautils" ) // NOTE: These metrics generate a new label per bridge, this should be safe @@ -74,7 +75,7 @@ var _ Task = (*BridgeTask)(nil) var zeroURL = new(url.URL) -const stalenessCap = time.Duration(30 * time.Minute) +const stalenessCap = 30 * time.Minute func (t *BridgeTask) Type() TaskType { return TaskTypeBridge @@ -166,8 +167,14 @@ func (t *BridgeTask) Run(ctx context.Context, lggr logger.Logger, vars Vars, inp } var cachedResponse bool - responseBytes, statusCode, headers, elapsed, err := makeHTTPRequest(requestCtx, lggr, "POST", URLParam(url), reqHeaders, requestData, t.httpClient, t.config.DefaultHTTPLimit()) - if err != nil { + responseBytes, statusCode, headers, elapsed, err := makeHTTPRequest(requestCtx, lggr, "POST", url, reqHeaders, requestData, t.httpClient, t.config.DefaultHTTPLimit()) + + // check for external adapter response object status + if code, ok := eautils.BestEffortExtractEAStatus(responseBytes); ok { + statusCode = code + } + + if err != nil || statusCode != http.StatusOK { promBridgeErrors.WithLabelValues(t.Name).Inc() if cacheTTL == 0 { return Result{Error: err}, RunInfo{IsRetryable: isRetryableHTTPError(statusCode, err)} diff --git a/core/services/pipeline/task.bridge_test.go b/core/services/pipeline/task.bridge_test.go index 03a804c9c12..7673add1e35 100644 --- a/core/services/pipeline/task.bridge_test.go +++ b/core/services/pipeline/task.bridge_test.go @@ -19,8 +19,8 @@ import ( "github.com/shopspring/decimal" "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/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -31,6 +31,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/internal/eautils" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -58,11 +59,43 @@ type adapterResponseData struct { // adapterResponse is the HTTP response as defined by the external adapter: // https://github.com/smartcontractkit/bnc-adapter type adapterResponse struct { - Data adapterResponseData `json:"data"` - ErrorMessage null.String `json:"errorMessage"` + eautils.AdapterStatus + Data adapterResponseData `json:"data"` } -func (pr adapterResponse) Result() *decimal.Decimal { +func (pr *adapterResponse) SetStatusCode(code int) { + pr.StatusCode = &code +} + +func (pr *adapterResponse) UnsetStatusCode() { + pr.StatusCode = nil +} + +func (pr *adapterResponse) SetProviderStatusCode(code int) { + pr.ProviderStatusCode = &code +} + +func (pr *adapterResponse) UnsetProviderStatusCode() { + pr.ProviderStatusCode = nil +} + +func (pr *adapterResponse) SetError(msg string) { + pr.Error = msg +} + +func (pr *adapterResponse) UnsetError() { + pr.Error = nil +} + +func (pr *adapterResponse) SetErrorMessage(msg string) { + pr.ErrorMessage = &msg +} + +func (pr *adapterResponse) UnsetErrorMessage() { + pr.ErrorMessage = nil +} + +func (pr *adapterResponse) Result() *decimal.Decimal { return pr.Data.Result } @@ -270,7 +303,7 @@ func TestBridgeTask_DoesNotReturnStaleResults(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.WebServer.BridgeCacheTTL = models.MustNewDuration(30 * time.Second) + c.WebServer.BridgeCacheTTL = commonconfig.MustNewDuration(30 * time.Second) }) queryer := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) s1 := httptest.NewServer(fakeIntermittentlyFailingPriceResponder(t, utils.MustUnmarshalToMap(btcUSDPairing), decimal.NewFromInt(9700), "", nil)) @@ -294,7 +327,7 @@ func TestBridgeTask_DoesNotReturnStaleResults(t *testing.T) { task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) // Insert entry 1m in the past, stale value, should not be used in case of EA failure. - err = queryer.ExecQ(`INSERT INTO bridge_last_value(dot_id, spec_id, value, finished_at) + err = queryer.ExecQ(`INSERT INTO bridge_last_value(dot_id, spec_id, value, finished_at) VALUES($1, $2, $3, $4) ON CONFLICT ON CONSTRAINT bridge_last_value_pkey DO UPDATE SET value = $3, finished_at = $4;`, task.DotID(), specID, big.NewInt(9700).Bytes(), time.Now().Add(-1*time.Minute)) require.NoError(t, err) @@ -336,7 +369,7 @@ func TestBridgeTask_DoesNotReturnStaleResults(t *testing.T) { require.Equal(t, string(big.NewInt(9700).Bytes()), result2.Value) cfg2 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.WebServer.BridgeCacheTTL = models.MustNewDuration(0 * time.Second) + c.WebServer.BridgeCacheTTL = commonconfig.MustNewDuration(0 * time.Second) }) task.HelperSetDependencies(cfg2.JobPipeline(), cfg2.WebServer(), orm, specID, uuid.UUID{}, c) @@ -785,9 +818,10 @@ func TestBridgeTask_ErrorMessage(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusTooManyRequests) - err := json.NewEncoder(w).Encode(adapterResponse{ - ErrorMessage: null.StringFrom("could not hit data fetcher"), - }) + + resp := &adapterResponse{} + resp.SetErrorMessage("could not hit data fetcher") + err := json.NewEncoder(w).Encode(resp) require.NoError(t, err) }) @@ -1015,3 +1049,93 @@ func TestBridgeTask_Headers(t *testing.T) { assert.Equal(t, []string{"Content-Length", "38", "Content-Type", "footype", "User-Agent", "Go-http-client/1.1", "X-Header-1", "foo", "X-Header-2", "bar"}, allHeaders(headers)) }) } + +func TestBridgeTask_AdapterResponseStatusFailure(t *testing.T) { + t.Parallel() + + db := pgtest.NewSqlxDB(t) + cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.WebServer.BridgeCacheTTL = commonconfig.MustNewDuration(1 * time.Minute) + }) + + testAdapterResponse := &adapterResponse{ + Data: adapterResponseData{Result: &decimal.Zero}, + } + + queryer := pg.NewQ(db, logger.TestLogger(t), cfg.Database()) + s1 := httptest.NewServer( + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err := json.NewEncoder(w).Encode(testAdapterResponse) + require.NoError(t, err) + })) + defer s1.Close() + + feedURL, err := url.ParseRequestURI(s1.URL) + require.NoError(t, err) + + orm := bridges.NewORM(db, logger.TestLogger(t), cfg.Database()) + _, bridge := cltest.MustCreateBridge(t, db, cltest.BridgeOpts{URL: feedURL.String()}, cfg.Database()) + + task := pipeline.BridgeTask{ + BaseTask: pipeline.NewBaseTask(0, "bridge", nil, nil, 0), + Name: bridge.Name.String(), + 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))) + require.NoError(t, err) + task.HelperSetDependencies(cfg.JobPipeline(), cfg.WebServer(), orm, specID, uuid.UUID{}, c) + + // Insert entry 1m in the past, stale value, should not be used in case of EA failure. + err = queryer.ExecQ(`INSERT INTO bridge_last_value(dot_id, spec_id, value, finished_at) + VALUES($1, $2, $3, $4) ON CONFLICT ON CONSTRAINT bridge_last_value_pkey + DO UPDATE SET value = $3, finished_at = $4;`, task.DotID(), specID, big.NewInt(9700).Bytes(), time.Now()) + require.NoError(t, err) + + vars := pipeline.NewVarsFrom( + map[string]interface{}{ + "jobRun": map[string]interface{}{ + "meta": map[string]interface{}{ + "shouldFail": true, + }, + }, + }, + ) + + // expect all external adapter response status failures to be served from the cache + testAdapterResponse.SetStatusCode(http.StatusBadRequest) + result, runInfo := task.Run(testutils.Context(t), logger.TestLogger(t), vars, nil) + + require.NoError(t, result.Error) + require.NotNil(t, result.Value) + require.False(t, runInfo.IsRetryable) + require.False(t, runInfo.IsPending) + + testAdapterResponse.SetStatusCode(http.StatusOK) + testAdapterResponse.SetProviderStatusCode(http.StatusBadRequest) + result, runInfo = task.Run(testutils.Context(t), logger.TestLogger(t), vars, nil) + + require.NoError(t, result.Error) + require.NotNil(t, result.Value) + require.False(t, runInfo.IsRetryable) + require.False(t, runInfo.IsPending) + + testAdapterResponse.SetStatusCode(http.StatusOK) + testAdapterResponse.SetProviderStatusCode(http.StatusOK) + testAdapterResponse.SetError("some error") + result, runInfo = task.Run(testutils.Context(t), logger.TestLogger(t), vars, nil) + + require.NoError(t, result.Error) + require.NotNil(t, result.Value) + require.False(t, runInfo.IsRetryable) + require.False(t, runInfo.IsPending) + + testAdapterResponse.SetStatusCode(http.StatusInternalServerError) + result, runInfo = task.Run(testutils.Context(t), logger.TestLogger(t), vars, nil) + + require.NoError(t, result.Error) + require.NotNil(t, result.Value) + require.False(t, runInfo.IsRetryable) + require.False(t, runInfo.IsPending) +} diff --git a/core/services/pipeline/task.estimategas.go b/core/services/pipeline/task.estimategas.go index 1c0159819b4..43c148b287f 100644 --- a/core/services/pipeline/task.estimategas.go +++ b/core/services/pipeline/task.estimategas.go @@ -12,9 +12,9 @@ import ( "github.com/shopspring/decimal" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Return types: diff --git a/core/services/pipeline/task.eth_abi_decode_log_test.go b/core/services/pipeline/task.eth_abi_decode_log_test.go index f8958f3517e..62cd005a047 100644 --- a/core/services/pipeline/task.eth_abi_decode_log_test.go +++ b/core/services/pipeline/task.eth_abi_decode_log_test.go @@ -10,10 +10,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestETHABIDecodeLogTask(t *testing.T) { diff --git a/core/services/pipeline/task.eth_abi_decode_test.go b/core/services/pipeline/task.eth_abi_decode_test.go index b0f03402278..3c7f5b4776b 100644 --- a/core/services/pipeline/task.eth_abi_decode_test.go +++ b/core/services/pipeline/task.eth_abi_decode_test.go @@ -10,9 +10,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var testsABIDecode = []struct { diff --git a/core/services/pipeline/task.eth_call.go b/core/services/pipeline/task.eth_call.go index 3862ea10301..56b2df08c4e 100644 --- a/core/services/pipeline/task.eth_call.go +++ b/core/services/pipeline/task.eth_call.go @@ -13,9 +13,9 @@ import ( "go.uber.org/multierr" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Return types: diff --git a/core/services/pipeline/task.eth_tx.go b/core/services/pipeline/task.eth_tx.go index c421b340c91..1687c974140 100644 --- a/core/services/pipeline/task.eth_tx.go +++ b/core/services/pipeline/task.eth_tx.go @@ -13,12 +13,12 @@ import ( "go.uber.org/multierr" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + clnull "github.com/smartcontractkit/chainlink-common/pkg/utils/null" 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/logger" - clnull "github.com/smartcontractkit/chainlink/v2/core/null" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Return types: @@ -189,7 +189,7 @@ func decodeMeta(metaMap MapParam) (*txmgr.TxMeta, error) { i, err2 := strconv.ParseInt(data.(string), 10, 32) return int32(i), err2 case reflect.TypeOf(common.Hash{}): - hb, err := utils.TryParseHex(data.(string)) + hb, err := hex.DecodeString(data.(string)) if err != nil { return nil, err } @@ -220,7 +220,7 @@ func decodeTransmitChecker(checkerMap MapParam) (txmgr.TransmitCheckerSpec, erro case stringType: switch to { case reflect.TypeOf(common.Address{}): - ab, err := utils.TryParseHex(data.(string)) + ab, err := hex.DecodeString(data.(string)) if err != nil { return nil, err } diff --git a/core/services/pipeline/task.eth_tx_test.go b/core/services/pipeline/task.eth_tx_test.go index a0ff54d4448..5f5019d1967 100644 --- a/core/services/pipeline/task.eth_tx_test.go +++ b/core/services/pipeline/task.eth_tx_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + clnull "github.com/smartcontractkit/chainlink-common/pkg/utils/null" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -19,7 +20,6 @@ import ( "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" - clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" keystoremocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" diff --git a/core/services/pipeline/task.hexdecode.go b/core/services/pipeline/task.hexdecode.go index 7feca555111..893130bcf2c 100644 --- a/core/services/pipeline/task.hexdecode.go +++ b/core/services/pipeline/task.hexdecode.go @@ -7,8 +7,8 @@ import ( "github.com/pkg/errors" "go.uber.org/multierr" + commonhex "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Return types: @@ -40,8 +40,8 @@ func (t *HexDecodeTask) Run(_ context.Context, _ logger.Logger, vars Vars, input return Result{Error: err}, runInfo } - if utils.HasHexPrefix(input.String()) { - noHexPrefix := utils.RemoveHexPrefix(input.String()) + if commonhex.HasPrefix(input.String()) { + noHexPrefix := commonhex.TrimPrefix(input.String()) bs, err := hex.DecodeString(noHexPrefix) if err == nil { return Result{Value: bs}, runInfo diff --git a/core/services/pipeline/task.http_test.go b/core/services/pipeline/task.http_test.go index c0dd93df430..36ccc147a78 100644 --- a/core/services/pipeline/task.http_test.go +++ b/core/services/pipeline/task.http_test.go @@ -14,7 +14,6 @@ import ( "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -264,9 +263,9 @@ func TestHTTPTask_ErrorMessage(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusTooManyRequests) - err := json.NewEncoder(w).Encode(adapterResponse{ - ErrorMessage: null.StringFrom("could not hit data fetcher"), - }) + resp := &adapterResponse{} + resp.SetErrorMessage("could not hit data fetcher") + err := json.NewEncoder(w).Encode(resp) require.NoError(t, err) }) diff --git a/core/services/pipeline/task.vrfv2.go b/core/services/pipeline/task.vrfv2.go index a871e543496..2c2c85eaedf 100644 --- a/core/services/pipeline/task.vrfv2.go +++ b/core/services/pipeline/task.vrfv2.go @@ -39,7 +39,7 @@ func (t *VRFTaskV2) Type() TaskType { return TaskTypeVRFV2 } -func (t *VRFTaskV2) Run(_ context.Context, _ logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { +func (t *VRFTaskV2) Run(_ context.Context, lggr logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { if len(inputs) != 1 { return Result{Error: ErrWrongInputCardinality}, runInfo } @@ -134,7 +134,8 @@ func (t *VRFTaskV2) Run(_ context.Context, _ logger.Logger, vars Vars, inputs [] return Result{Error: err}, runInfo } results := make(map[string]interface{}) - results["output"] = hexutil.Encode(b) + output := hexutil.Encode(b) + results["output"] = output // RequestID needs to be a [32]byte for EvmTxMeta. results["requestID"] = hexutil.Encode(requestId.Bytes()) @@ -142,5 +143,7 @@ func (t *VRFTaskV2) Run(_ context.Context, _ logger.Logger, vars Vars, inputs [] results["proof"] = onChainProof results["requestCommitment"] = rc + lggr.Debugw("Completed VRF V2 task run", "reqID", requestId.String(), "output", output) + return Result{Value: results}, runInfo } diff --git a/core/services/pipeline/task.vrfv2plus.go b/core/services/pipeline/task.vrfv2plus.go index a596bfa3092..c029af68cbe 100644 --- a/core/services/pipeline/task.vrfv2plus.go +++ b/core/services/pipeline/task.vrfv2plus.go @@ -42,7 +42,7 @@ func (t *VRFTaskV2Plus) Type() TaskType { return TaskTypeVRFV2Plus } -func (t *VRFTaskV2Plus) Run(_ context.Context, _ logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { +func (t *VRFTaskV2Plus) Run(_ context.Context, lggr logger.Logger, vars Vars, inputs []Result) (result Result, runInfo RunInfo) { if len(inputs) != 1 { return Result{Error: ErrWrongInputCardinality}, runInfo } @@ -142,7 +142,8 @@ func (t *VRFTaskV2Plus) Run(_ context.Context, _ logger.Logger, vars Vars, input return Result{Error: err}, runInfo } results := make(map[string]interface{}) - results["output"] = hexutil.Encode(b) + output := hexutil.Encode(b) + results["output"] = output // RequestID needs to be a [32]byte for EvmTxMeta. results["requestID"] = hexutil.Encode(requestId.Bytes()) @@ -150,5 +151,7 @@ func (t *VRFTaskV2Plus) Run(_ context.Context, _ logger.Logger, vars Vars, input results["proof"] = onChainProof results["requestCommitment"] = rc + lggr.Debugw("Completed VRF V2 task run", "reqID", requestId.String(), "output", output) + return Result{Value: results}, runInfo } diff --git a/core/services/pipeline/task_params.go b/core/services/pipeline/task_params.go index dc020c30715..72d0d619429 100644 --- a/core/services/pipeline/task_params.go +++ b/core/services/pipeline/task_params.go @@ -13,6 +13,7 @@ import ( "github.com/pkg/errors" "github.com/shopspring/decimal" + commonhex "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -122,8 +123,8 @@ func (b *BytesParam) UnmarshalPipelineParam(val interface{}) error { switch v := val.(type) { case string: // first check if this is a valid hex-encoded string - if utils.HasHexPrefix(v) { - noHexPrefix := utils.RemoveHexPrefix(v) + if commonhex.HasPrefix(v) { + noHexPrefix := commonhex.TrimPrefix(v) bs, err := hex.DecodeString(noHexPrefix) if err == nil { *b = bs @@ -333,7 +334,7 @@ func (p *MaybeInt32Param) UnmarshalPipelineParam(val interface{}) error { case int16: n = int32(v) case int32: - n = int32(v) + n = v case int64: if v > math.MaxInt32 || v < math.MinInt32 { return errors.Wrap(ErrBadInput, "overflows int32") @@ -452,7 +453,7 @@ func (a *AddressParam) UnmarshalPipelineParam(val interface{}) error { case []byte: switch len(v) { case 42: - bs, err := utils.TryParseHex(string(v)) + bs, err := commonhex.DecodeString(string(v)) if err == nil { *a = AddressParam(common.BytesToAddress(bs)) return nil @@ -763,7 +764,7 @@ func (p *MaybeBigIntParam) UnmarshalPipelineParam(val interface{}) error { case int32: n = big.NewInt(int64(v)) case int64: - n = big.NewInt(int64(v)) + n = big.NewInt(v) case float64: // when decoding from db: JSON numbers are floats if v < math.MinInt64 || v > math.MaxUint64 { return errors.Wrapf(ErrBadInput, "cannot cast %v to u/int64", v) diff --git a/core/services/promreporter/prom_reporter.go b/core/services/promreporter/prom_reporter.go index 3e1444a6da1..a302a6fa220 100644 --- a/core/services/promreporter/prom_reporter.go +++ b/core/services/promreporter/prom_reporter.go @@ -17,10 +17,11 @@ import ( "go.uber.org/multierr" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) //go:generate mockery --quiet --name PrometheusBackend --output ../../internal/mocks/ --case=underscore @@ -31,7 +32,7 @@ type ( chains legacyevm.LegacyChainContainer lggr logger.Logger backend PrometheusBackend - newHeads *utils.Mailbox[*evmtypes.Head] + newHeads *mailbox.Mailbox[*evmtypes.Head] chStop services.StopChan wgDone sync.WaitGroup reportPeriod time.Duration @@ -109,7 +110,7 @@ func NewPromReporter(db *sql.DB, chainContainer legacyevm.LegacyChainContainer, chains: chainContainer, lggr: lggr.Named("PromReporter"), backend: backend, - newHeads: utils.NewSingleMailbox[*evmtypes.Head](), + newHeads: mailbox.NewSingle[*evmtypes.Head](), chStop: chStop, reportPeriod: period, } diff --git a/core/services/promreporter/prom_reporter_test.go b/core/services/promreporter/prom_reporter_test.go index 54e3a5d3fab..60d6d9388fa 100644 --- a/core/services/promreporter/prom_reporter_test.go +++ b/core/services/promreporter/prom_reporter_test.go @@ -7,14 +7,16 @@ import ( "time" "github.com/jmoiron/sqlx" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" @@ -24,11 +26,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/promreporter" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func newHead() evmtypes.Head { - return evmtypes.Head{Number: 42, EVMChainID: utils.NewBigI(0)} + return evmtypes.Head{Number: 42, EVMChainID: ubig.NewI(0)} } func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainContainer { @@ -76,8 +77,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { }). Return() - require.NoError(t, reporter.Start(testutils.Context(t))) - defer func() { assert.NoError(t, reporter.Close()) }() + servicetest.Run(t, reporter) head := newHead() reporter.OnNewLongestChain(testutils.Context(t), &head) @@ -107,13 +107,12 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { }). Return() reporter := promreporter.NewPromReporter(db.DB, newLegacyChainContainer(t, db), logger.TestLogger(t), backend, 10*time.Millisecond) - require.NoError(t, reporter.Start(testutils.Context(t))) - defer func() { assert.NoError(t, reporter.Close()) }() + servicetest.Run(t, reporter) etx := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, fromAddress) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, fromAddress) - require.NoError(t, utils.JustError(db.Exec(`UPDATE evm.tx_attempts SET broadcast_before_block_num = 7 WHERE eth_tx_id = $1`, etx.ID))) + require.NoError(t, txStore.UpdateTxAttemptBroadcastBeforeBlockNum(testutils.Context(t), etx.ID, 7)) head := newHead() reporter.OnNewLongestChain(testutils.Context(t), &head) @@ -143,8 +142,7 @@ func Test_PromReporter_OnNewLongestChain(t *testing.T) { subscribeCalls.Add(1) }). Return() - require.NoError(t, reporter.Start(testutils.Context(t))) - defer func() { assert.NoError(t, reporter.Close()) }() + servicetest.Run(t, reporter) head := newHead() reporter.OnNewLongestChain(testutils.Context(t), &head) diff --git a/core/services/relay/evm/binding.go b/core/services/relay/evm/binding.go new file mode 100644 index 00000000000..e78d9f0a770 --- /dev/null +++ b/core/services/relay/evm/binding.go @@ -0,0 +1,15 @@ +package evm + +import ( + "context" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +type readBinding interface { + GetLatestValue(ctx context.Context, params, returnVal any) error + Bind(binding commontypes.BoundContract) error + SetCodec(codec commontypes.RemoteCodec) + Register() error + Unregister() error +} diff --git a/core/services/relay/evm/bindings.go b/core/services/relay/evm/bindings.go new file mode 100644 index 00000000000..1a23128d19f --- /dev/null +++ b/core/services/relay/evm/bindings.go @@ -0,0 +1,61 @@ +package evm + +import ( + "fmt" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +// key is contract name +type contractBindings map[string]readBindings + +// key is read name +type readBindings map[string]readBinding + +func (b contractBindings) GetReadBinding(contractName, readName string) (readBinding, error) { + rb, rbExists := b[contractName] + if !rbExists { + return nil, fmt.Errorf("%w: no contract named %s", commontypes.ErrInvalidType, contractName) + } + + reader, readerExists := rb[readName] + if !readerExists { + return nil, fmt.Errorf("%w: no readName named %s in contract %s", commontypes.ErrInvalidType, readName, contractName) + } + return reader, nil +} + +func (b contractBindings) AddReadBinding(contractName, readName string, reader readBinding) { + rbs, rbsExists := b[contractName] + if !rbsExists { + rbs = readBindings{} + b[contractName] = rbs + } + rbs[readName] = reader +} + +func (b contractBindings) Bind(boundContracts []commontypes.BoundContract) error { + for _, bc := range boundContracts { + rbs, rbsExist := b[bc.Name] + if !rbsExist { + return fmt.Errorf("%w: no contract named %s", commontypes.ErrInvalidConfig, bc.Name) + } + for _, r := range rbs { + if err := r.Bind(bc); err != nil { + return err + } + } + } + return nil +} + +func (b contractBindings) ForEach(fn func(readBinding) error) error { + for _, rbs := range b { + for _, rb := range rbs { + if err := fn(rb); err != nil { + return err + } + } + } + return nil +} diff --git a/core/services/relay/evm/chain_reader.go b/core/services/relay/evm/chain_reader.go new file mode 100644 index 00000000000..dba05af7e3c --- /dev/null +++ b/core/services/relay/evm/chain_reader.go @@ -0,0 +1,292 @@ +package evm + +import ( + "context" + "fmt" + "reflect" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/google/uuid" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + commonservices "github.com/smartcontractkit/chainlink-common/pkg/services" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type ChainReaderService interface { + services.ServiceCtx + commontypes.ChainReader +} + +type chainReader struct { + lggr logger.Logger + lp logpoller.LogPoller + client evmclient.Client + contractBindings contractBindings + parsed *parsedTypes + codec commontypes.RemoteCodec + commonservices.StateMachine +} + +// NewChainReaderService is a constructor for ChainReader, returns nil if there is any error +func NewChainReaderService(lggr logger.Logger, lp logpoller.LogPoller, chain legacyevm.Chain, config types.ChainReaderConfig) (ChainReaderService, error) { + cr := &chainReader{ + lggr: lggr.Named("ChainReader"), + lp: lp, + client: chain.Client(), + contractBindings: contractBindings{}, + parsed: &parsedTypes{encoderDefs: map[string]types.CodecEntry{}, decoderDefs: map[string]types.CodecEntry{}}, + } + + var err error + if err = cr.init(config.Contracts); err != nil { + return nil, err + } + + if cr.codec, err = cr.parsed.toCodec(); err != nil { + return nil, err + } + + err = cr.contractBindings.ForEach(func(b readBinding) error { + b.SetCodec(cr.codec) + return nil + }) + + return cr, err +} + +func (cr *chainReader) Name() string { return cr.lggr.Name() } + +var _ commontypes.ContractTypeProvider = &chainReader{} + +func (cr *chainReader) GetLatestValue(ctx context.Context, contractName, method string, params any, returnVal any) error { + b, err := cr.contractBindings.GetReadBinding(contractName, method) + if err != nil { + return err + } + + return b.GetLatestValue(ctx, params, returnVal) +} + +func (cr *chainReader) Bind(_ context.Context, bindings []commontypes.BoundContract) error { + return cr.contractBindings.Bind(bindings) +} + +func (cr *chainReader) init(chainContractReaders map[string]types.ChainContractReader) error { + for contractName, chainContractReader := range chainContractReaders { + contractAbi, err := abi.JSON(strings.NewReader(chainContractReader.ContractABI)) + if err != nil { + return err + } + + for typeName, chainReaderDefinition := range chainContractReader.Configs { + switch chainReaderDefinition.ReadType { + case types.Method: + err = cr.addMethod(contractName, typeName, contractAbi, *chainReaderDefinition) + case types.Event: + err = cr.addEvent(contractName, typeName, contractAbi, *chainReaderDefinition) + default: + return fmt.Errorf( + "%w: invalid chain reader definition read type: %s", + commontypes.ErrInvalidConfig, + chainReaderDefinition.ReadType) + } + + if err != nil { + return err + } + } + } + return nil +} + +func (cr *chainReader) Start(_ context.Context) error { + return cr.StartOnce("ChainReader", func() error { + return cr.contractBindings.ForEach(readBinding.Register) + }) +} + +func (cr *chainReader) Close() error { + return cr.StopOnce("ChainReader", func() error { + return cr.contractBindings.ForEach(readBinding.Unregister) + }) +} + +func (cr *chainReader) Ready() error { return nil } +func (cr *chainReader) HealthReport() map[string]error { + return map[string]error{cr.Name(): nil} +} + +func (cr *chainReader) CreateContractType(contractName, methodName string, forEncoding bool) (any, error) { + return cr.codec.CreateType(wrapItemType(contractName, methodName, forEncoding), forEncoding) +} + +func wrapItemType(contractName, methodName string, isParams bool) string { + if isParams { + return fmt.Sprintf("params.%s.%s", contractName, methodName) + } + return fmt.Sprintf("return.%s.%s", contractName, methodName) +} + +func (cr *chainReader) addMethod( + contractName, + methodName string, + abi abi.ABI, + chainReaderDefinition types.ChainReaderDefinition) error { + method, methodExists := abi.Methods[chainReaderDefinition.ChainSpecificName] + if !methodExists { + return fmt.Errorf("%w: method %s doesn't exist", commontypes.ErrInvalidConfig, chainReaderDefinition.ChainSpecificName) + } + + if len(chainReaderDefinition.EventInputFields) != 0 { + return fmt.Errorf( + "%w: method %s has event topic fields defined, but is not an event", + commontypes.ErrInvalidConfig, + chainReaderDefinition.ChainSpecificName) + } + + cr.contractBindings.AddReadBinding(contractName, methodName, &methodBinding{ + contractName: contractName, + method: methodName, + client: cr.client, + }) + + if err := cr.addEncoderDef(contractName, methodName, method.Inputs, method.ID, chainReaderDefinition); err != nil { + return err + } + + return cr.addDecoderDef(contractName, methodName, method.Outputs, chainReaderDefinition) +} + +func (cr *chainReader) addEvent(contractName, eventName string, a abi.ABI, chainReaderDefinition types.ChainReaderDefinition) error { + event, eventExists := a.Events[chainReaderDefinition.ChainSpecificName] + if !eventExists { + return fmt.Errorf("%w: event %s doesn't exist", commontypes.ErrInvalidConfig, chainReaderDefinition.ChainSpecificName) + } + + filterArgs, topicInfo, indexArgNames := setupEventInput(event, chainReaderDefinition) + if err := verifyEventInputsUsed(chainReaderDefinition, indexArgNames); err != nil { + return err + } + + if err := topicInfo.Init(); err != nil { + return err + } + + // Encoder def's codec won't be used to encode, only for its type as input for GetLatestValue + if err := cr.addEncoderDef(contractName, eventName, filterArgs, nil, chainReaderDefinition); err != nil { + return err + } + + inputInfo, inputModifier, err := cr.getEventInput(chainReaderDefinition, contractName, eventName) + if err != nil { + return err + } + + cr.contractBindings.AddReadBinding(contractName, eventName, &eventBinding{ + contractName: contractName, + eventName: eventName, + lp: cr.lp, + hash: event.ID, + inputInfo: inputInfo, + inputModifier: inputModifier, + topicInfo: topicInfo, + id: wrapItemType(contractName, eventName, false) + uuid.NewString(), + }) + + return cr.addDecoderDef(contractName, eventName, event.Inputs, chainReaderDefinition) +} + +func (cr *chainReader) getEventInput(def types.ChainReaderDefinition, contractName, eventName string) ( + types.CodecEntry, codec.Modifier, error) { + inputInfo := cr.parsed.encoderDefs[wrapItemType(contractName, eventName, true)] + inMod, err := def.InputModifications.ToModifier(evmDecoderHooks...) + if err != nil { + return nil, nil, err + } + + // initialize the modification + if _, err = inMod.RetypeToOffChain(reflect.PointerTo(inputInfo.CheckedType()), ""); err != nil { + return nil, nil, err + } + + return inputInfo, inMod, nil +} + +func verifyEventInputsUsed(chainReaderDefinition types.ChainReaderDefinition, indexArgNames map[string]bool) error { + for _, value := range chainReaderDefinition.EventInputFields { + if !indexArgNames[abi.ToCamelCase(value)] { + return fmt.Errorf("%w: %s is not an indexed argument of event %s", commontypes.ErrInvalidConfig, value, chainReaderDefinition.ChainSpecificName) + } + } + return nil +} + +func (cr *chainReader) addEncoderDef(contractName, methodName string, args abi.Arguments, prefix []byte, chainReaderDefinition types.ChainReaderDefinition) error { + // ABI.Pack prepends the method.ID to the encodings, we'll need the encoder to do the same. + inputMod, err := chainReaderDefinition.InputModifications.ToModifier(evmDecoderHooks...) + if err != nil { + return err + } + input := types.NewCodecEntry(args, prefix, inputMod) + + if err := input.Init(); err != nil { + return err + } + + cr.parsed.encoderDefs[wrapItemType(contractName, methodName, true)] = input + return nil +} + +func (cr *chainReader) addDecoderDef(contractName, methodName string, outputs abi.Arguments, def types.ChainReaderDefinition) error { + mod, err := def.OutputModifications.ToModifier(evmDecoderHooks...) + if err != nil { + return err + } + output := types.NewCodecEntry(outputs, nil, mod) + cr.parsed.decoderDefs[wrapItemType(contractName, methodName, false)] = output + return output.Init() +} + +func setupEventInput(event abi.Event, def types.ChainReaderDefinition) ([]abi.Argument, types.CodecEntry, map[string]bool) { + topicFieldDefs := map[string]bool{} + for _, value := range def.EventInputFields { + capFirstValue := abi.ToCamelCase(value) + topicFieldDefs[capFirstValue] = true + } + + filterArgs := make([]abi.Argument, 0, types.MaxTopicFields) + inputArgs := make([]abi.Argument, 0, len(event.Inputs)) + indexArgNames := map[string]bool{} + + for _, input := range event.Inputs { + if !input.Indexed { + continue + } + + filterWith := topicFieldDefs[abi.ToCamelCase(input.Name)] + if filterWith { + // When presenting the filter off-chain, + // the user will provide the unhashed version of the input + // The reader will hash topics if needed. + inputUnindexed := input + inputUnindexed.Indexed = false + filterArgs = append(filterArgs, inputUnindexed) + } + + inputArgs = append(inputArgs, input) + indexArgNames[abi.ToCamelCase(input.Name)] = true + } + + return filterArgs, types.NewCodecEntry(inputArgs, nil, nil), indexArgNames +} diff --git a/core/services/relay/evm/chain_reader_test.go b/core/services/relay/evm/chain_reader_test.go new file mode 100644 index 00000000000..02e9d4e3f6a --- /dev/null +++ b/core/services/relay/evm/chain_reader_test.go @@ -0,0 +1,426 @@ +package evm_test + +import ( + "crypto/ecdsa" + "fmt" + "math" + "math/big" + "os" + "reflect" + "strconv" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core" + evmtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/smartcontractkit/libocr/commontypes" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + clcommontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . + + commontestutils "github.com/smartcontractkit/chainlink-common/pkg/loop/testutils" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/chain_reader_example" + "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/evm" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +const ( + commonGasLimitOnEvms = uint64(4712388) + triggerWithDynamicTopic = "TriggeredEventWithDynamicTopic" + triggerWithAllTopics = "TriggeredWithFourTopics" +) + +func TestChainReader(t *testing.T) { + t.Parallel() + it := &chainReaderInterfaceTester{} + RunChainReaderInterfaceTests(t, it) + RunChainReaderInterfaceTests(t, commontestutils.WrapChainReaderTesterForLoop(it)) + t.Run("Dynamically typed topics can be used to filter and have type correct in return", func(t *testing.T) { + it.Setup(t) + + anyString := "foo" + tx, err := it.evmTest.LatestValueHolderTransactor.TriggerEventWithDynamicTopic(it.auth, anyString) + require.NoError(t, err) + it.sim.Commit() + it.incNonce() + it.awaitTx(t, tx) + ctx := testutils.Context(t) + + cr := it.GetChainReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + + input := struct{ Field string }{Field: anyString} + tp := cr.(clcommontypes.ContractTypeProvider) + output, err := tp.CreateContractType(AnyContractName, triggerWithDynamicTopic, false) + require.NoError(t, err) + rOutput := reflect.Indirect(reflect.ValueOf(output)) + + require.Eventually(t, func() bool { + return cr.GetLatestValue(ctx, AnyContractName, triggerWithDynamicTopic, input, output) == nil + }, it.MaxWaitTimeForEvents(), time.Millisecond*10) + + assert.Equal(t, &anyString, rOutput.FieldByName("Field").Interface()) + topic, err := abi.MakeTopics([]any{anyString}) + require.NoError(t, err) + assert.Equal(t, &topic[0][0], rOutput.FieldByName("FieldHash").Interface()) + }) + + t.Run("Multiple topics can filter together", func(t *testing.T) { + it.Setup(t) + triggerFourTopics(t, it, int32(1), int32(2), int32(3)) + triggerFourTopics(t, it, int32(2), int32(2), int32(3)) + triggerFourTopics(t, it, int32(1), int32(3), int32(3)) + triggerFourTopics(t, it, int32(1), int32(2), int32(4)) + + ctx := testutils.Context(t) + cr := it.GetChainReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + var latest struct{ Field1, Field2, Field3 int32 } + params := struct{ Field1, Field2, Field3 int32 }{Field1: 1, Field2: 2, Field3: 3} + + time.Sleep(it.MaxWaitTimeForEvents()) + + require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, triggerWithAllTopics, params, &latest)) + assert.Equal(t, int32(1), latest.Field1) + assert.Equal(t, int32(2), latest.Field2) + assert.Equal(t, int32(3), latest.Field3) + }) +} + +func triggerFourTopics(t *testing.T, it *chainReaderInterfaceTester, i1, i2, i3 int32) { + tx, err := it.evmTest.LatestValueHolderTransactor.TriggerWithFourTopics(it.auth, i1, i2, i3) + require.NoError(t, err) + require.NoError(t, err) + it.sim.Commit() + it.incNonce() + it.awaitTx(t, tx) +} + +type chainReaderInterfaceTester struct { + chain *mocks.Chain + address string + address2 string + chainConfig types.ChainReaderConfig + auth *bind.TransactOpts + sim *backends.SimulatedBackend + pk *ecdsa.PrivateKey + evmTest *chain_reader_example.LatestValueHolder + cr evm.ChainReaderService +} + +func (it *chainReaderInterfaceTester) MaxWaitTimeForEvents() time.Duration { + // From trial and error, when running on CI, sometimes the boxes get slow + maxWaitTime := time.Second * 20 + maxWaitTimeStr, ok := os.LookupEnv("MAX_WAIT_TIME_FOR_EVENTS_S") + if ok { + wiatS, err := strconv.ParseInt(maxWaitTimeStr, 10, 64) + if err != nil { + fmt.Printf("Error parsing MAX_WAIT_TIME_FOR_EVENTS_S: %v, defaulting to %v\n", err, maxWaitTime) + } + maxWaitTime = time.Second * time.Duration(wiatS) + } + + return maxWaitTime +} + +func (it *chainReaderInterfaceTester) Setup(t *testing.T) { + t.Cleanup(func() { + // DB may be closed by the test already, ignore errors + if it.cr != nil { + _ = it.cr.Close() + } + it.cr = nil + it.evmTest = nil + }) + + // can re-use the same chain for tests, just make new contract for each test + if it.chain != nil { + it.deployNewContracts(t) + return + } + + it.chain = &mocks.Chain{} + it.setupChainNoClient(t) + + testStruct := CreateTestStruct(0, it) + + it.chainConfig = types.ChainReaderConfig{ + Contracts: map[string]types.ChainContractReader{ + AnyContractName: { + ContractABI: chain_reader_example.LatestValueHolderMetaData.ABI, + Configs: map[string]*types.ChainReaderDefinition{ + MethodTakingLatestParamsReturningTestStruct: { + ChainSpecificName: "getElementAtIndex", + OutputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + }, + MethodReturningUint64: { + ChainSpecificName: "getPrimitiveValue", + }, + DifferentMethodReturningUint64: { + ChainSpecificName: "getDifferentPrimitiveValue", + }, + MethodReturningUint64Slice: { + ChainSpecificName: "getSliceValue", + }, + EventName: { + ChainSpecificName: "Triggered", + ReadType: types.Event, + OutputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + }, + EventWithFilterName: { + ChainSpecificName: "Triggered", + ReadType: types.Event, + EventInputFields: []string{"Field"}, + }, + triggerWithDynamicTopic: { + ChainSpecificName: triggerWithDynamicTopic, + ReadType: types.Event, + EventInputFields: []string{"fieldHash"}, + InputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"FieldHash": "Field"}}, + }, + }, + triggerWithAllTopics: { + ChainSpecificName: triggerWithAllTopics, + ReadType: types.Event, + EventInputFields: []string{"Field1", "Field2", "Field3"}, + }, + MethodReturningSeenStruct: { + ChainSpecificName: "returnSeen", + InputModifications: codec.ModifiersConfig{ + &codec.HardCodeModifierConfig{ + OnChainValues: map[string]any{ + "BigField": testStruct.BigField.String(), + "Account": hexutil.Encode(testStruct.Account), + }, + }, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + OutputModifications: codec.ModifiersConfig{ + &codec.HardCodeModifierConfig{OffChainValues: map[string]any{"ExtraField": anyExtraValue}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + }, + }, + }, + AnySecondContractName: { + ContractABI: chain_reader_example.LatestValueHolderMetaData.ABI, + Configs: map[string]*types.ChainReaderDefinition{ + MethodReturningUint64: { + ChainSpecificName: "getDifferentPrimitiveValue", + }, + }, + }, + }, + } + it.chain.On("Client").Return(client.NewSimulatedBackendClient(t, it.sim, big.NewInt(1337))) + it.deployNewContracts(t) +} + +func (it *chainReaderInterfaceTester) Name() string { + return "EVM" +} + +func (it *chainReaderInterfaceTester) GetAccountBytes(i int) []byte { + account := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + account[i%20] += byte(i) + account[(i+3)%20] += byte(i + 3) + return account[:] +} + +func (it *chainReaderInterfaceTester) GetChainReader(t *testing.T) clcommontypes.ChainReader { + ctx := testutils.Context(t) + if it.cr != nil { + return it.cr + } + + lggr := logger.NullLogger + db := pgtest.NewSqlxDB(t) + lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, db, lggr, pgtest.NewQConfig(true)), it.chain.Client(), lggr, time.Millisecond, false, 0, 1, 1, 10000) + require.NoError(t, lp.Start(ctx)) + it.chain.On("LogPoller").Return(lp) + cr, err := evm.NewChainReaderService(lggr, lp, it.chain, it.chainConfig) + require.NoError(t, err) + require.NoError(t, cr.Start(ctx)) + it.cr = cr + return cr +} + +func (it *chainReaderInterfaceTester) SetLatestValue(t *testing.T, testStruct *TestStruct) { + it.sendTxWithTestStruct(t, testStruct, (*chain_reader_example.LatestValueHolderTransactor).AddTestStruct) +} + +func (it *chainReaderInterfaceTester) TriggerEvent(t *testing.T, testStruct *TestStruct) { + it.sendTxWithTestStruct(t, testStruct, (*chain_reader_example.LatestValueHolderTransactor).TriggerEvent) +} + +func (it *chainReaderInterfaceTester) GetBindings(t *testing.T) []clcommontypes.BoundContract { + return []clcommontypes.BoundContract{ + {Name: AnyContractName, Address: it.address, Pending: true}, + {Name: AnySecondContractName, Address: it.address2, Pending: true}, + } +} + +type testStructFn = func(*chain_reader_example.LatestValueHolderTransactor, *bind.TransactOpts, int32, string, uint8, [32]uint8, common.Address, []common.Address, *big.Int, chain_reader_example.MidLevelTestStruct) (*evmtypes.Transaction, error) + +func (it *chainReaderInterfaceTester) sendTxWithTestStruct(t *testing.T, testStruct *TestStruct, fn testStructFn) { + tx, err := fn( + &it.evmTest.LatestValueHolderTransactor, + it.auth, + *testStruct.Field, + testStruct.DifferentField, + uint8(testStruct.OracleID), + convertOracleIDs(testStruct.OracleIDs), + common.Address(testStruct.Account), + convertAccounts(testStruct.Accounts), + testStruct.BigField, + midToInternalType(testStruct.NestedStruct), + ) + require.NoError(t, err) + it.sim.Commit() + it.incNonce() + it.awaitTx(t, tx) +} + +func convertOracleIDs(oracleIDs [32]commontypes.OracleID) [32]byte { + convertedIds := [32]byte{} + for i, id := range oracleIDs { + convertedIds[i] = byte(id) + } + return convertedIds +} + +func convertAccounts(accounts [][]byte) []common.Address { + convertedAccounts := make([]common.Address, len(accounts)) + for i, a := range accounts { + convertedAccounts[i] = common.Address(a) + } + return convertedAccounts +} + +func (it *chainReaderInterfaceTester) setupChainNoClient(t require.TestingT) { + privateKey, err := crypto.GenerateKey() + require.NoError(t, err) + it.pk = privateKey + + it.auth, err = bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(1337)) + require.NoError(t, err) + + it.sim = backends.NewSimulatedBackend(core.GenesisAlloc{it.auth.From: {Balance: big.NewInt(math.MaxInt64)}}, commonGasLimitOnEvms*5000) + it.sim.Commit() +} + +func (it *chainReaderInterfaceTester) deployNewContracts(t *testing.T) { + it.address = it.deployNewContract(t) + it.address2 = it.deployNewContract(t) +} + +func (it *chainReaderInterfaceTester) deployNewContract(t *testing.T) string { + ctx := testutils.Context(t) + gasPrice, err := it.sim.SuggestGasPrice(ctx) + require.NoError(t, err) + it.auth.GasPrice = gasPrice + + // 105528 was in the error: gas too low: have 0, want 105528 + // Not sure if there's a better way to get it. + it.auth.GasLimit = 10552800 + + address, tx, ts, err := chain_reader_example.DeployLatestValueHolder(it.auth, it.sim) + + require.NoError(t, err) + it.sim.Commit() + if it.evmTest == nil { + it.evmTest = ts + } + it.incNonce() + it.awaitTx(t, tx) + return address.String() +} + +func (it *chainReaderInterfaceTester) awaitTx(t *testing.T, tx *evmtypes.Transaction) { + ctx := testutils.Context(t) + receipt, err := it.sim.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + require.Equal(t, evmtypes.ReceiptStatusSuccessful, receipt.Status) +} + +func (it *chainReaderInterfaceTester) incNonce() { + if it.auth.Nonce == nil { + it.auth.Nonce = big.NewInt(1) + } else { + it.auth.Nonce = it.auth.Nonce.Add(it.auth.Nonce, big.NewInt(1)) + } +} + +func getAccounts(first TestStruct) []common.Address { + accountBytes := make([]common.Address, len(first.Accounts)) + for i, account := range first.Accounts { + accountBytes[i] = common.Address(account) + } + return accountBytes +} + +func argsFromTestStruct(ts TestStruct) []any { + return []any{ + ts.Field, + ts.DifferentField, + uint8(ts.OracleID), + getOracleIDs(ts), + common.Address(ts.Account), + getAccounts(ts), + ts.BigField, + midToInternalType(ts.NestedStruct), + } +} + +func getOracleIDs(first TestStruct) [32]byte { + oracleIDs := [32]byte{} + for i, oracleID := range first.OracleIDs { + oracleIDs[i] = byte(oracleID) + } + return oracleIDs +} + +func toInternalType(testStruct TestStruct) chain_reader_example.TestStruct { + return chain_reader_example.TestStruct{ + Field: *testStruct.Field, + DifferentField: testStruct.DifferentField, + OracleId: byte(testStruct.OracleID), + OracleIds: convertOracleIDs(testStruct.OracleIDs), + Account: common.Address(testStruct.Account), + Accounts: convertAccounts(testStruct.Accounts), + BigField: testStruct.BigField, + NestedStruct: midToInternalType(testStruct.NestedStruct), + } +} + +func midToInternalType(m MidLevelTestStruct) chain_reader_example.MidLevelTestStruct { + return chain_reader_example.MidLevelTestStruct{ + FixedBytes: m.FixedBytes, + Inner: chain_reader_example.InnerTestStruct{ + IntVal: int64(m.Inner.I), + S: m.Inner.S, + }, + } +} diff --git a/core/services/relay/evm/codec.go b/core/services/relay/evm/codec.go new file mode 100644 index 00000000000..a87976da54f --- /dev/null +++ b/core/services/relay/evm/codec.go @@ -0,0 +1,146 @@ +package evm + +import ( + "encoding/json" + "fmt" + "math/big" + "reflect" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/mitchellh/mapstructure" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +// decodeAccountAndAllowArraySliceHook allows: +// +// strings to be converted to [32]byte allowing config to represent them as 0x... +// slices or arrays to be converted to a pointer to that type +// +// BigIntHook allows *big.Int to be represented as any integer type or a string and to go back to them. +// Useful for config, or if when a model may use a go type that isn't a *big.Int when Pack expects one. +// Eg: int32 in a go struct from a plugin could require a *big.Int in Pack for int24, if it fits, we shouldn't care. +// SliceToArrayVerifySizeHook verifies that slices have the correct size when converting to an array +// sizeVerifyBigIntHook allows our custom types that verify the number fits in the on-chain type to be converted as-if +// it was a *big.Int +var evmDecoderHooks = []mapstructure.DecodeHookFunc{decodeAccountAndAllowArraySliceHook, codec.BigIntHook, codec.SliceToArrayVerifySizeHook, sizeVerifyBigIntHook} + +// NewCodec creates a new [commontypes.RemoteCodec] for EVM. +// Note that names in the ABI are converted to Go names using [abi.ToCamelCase], +// this is per convention in [abi.MakeTopics], [abi.Arguments.Pack] etc. +// This allows names on-chain to be in go convention when generated. +// It means that if you need to use a [codec.Modifier] to reference a field +// you need to use the Go name instead of the name on-chain. +// eg: rename FooBar -> Bar, not foo_bar_ to Bar if the name on-chain is foo_bar_ +func NewCodec(conf types.CodecConfig) (commontypes.RemoteCodec, error) { + parsed := &parsedTypes{ + encoderDefs: map[string]types.CodecEntry{}, + decoderDefs: map[string]types.CodecEntry{}, + } + + for k, v := range conf.Configs { + args := abi.Arguments{} + if err := json.Unmarshal(([]byte)(v.TypeABI), &args); err != nil { + return nil, err + } + + mod, err := v.ModifierConfigs.ToModifier(evmDecoderHooks...) + if err != nil { + return nil, err + } + + item := types.NewCodecEntry(args, nil, mod) + if err = item.Init(); err != nil { + return nil, err + } + + parsed.encoderDefs[k] = item + parsed.decoderDefs[k] = item + } + + return parsed.toCodec() +} + +type evmCodec struct { + *encoder + *decoder + *parsedTypes +} + +func (c *evmCodec) CreateType(itemType string, forEncoding bool) (any, error) { + var itemTypes map[string]types.CodecEntry + if forEncoding { + itemTypes = c.encoderDefs + } else { + itemTypes = c.decoderDefs + } + + def, ok := itemTypes[itemType] + if !ok { + return nil, fmt.Errorf("%w: cannot find type name %s", commontypes.ErrInvalidType, itemType) + } + + return reflect.New(def.CheckedType()).Interface(), nil +} + +var bigIntType = reflect.TypeOf((*big.Int)(nil)) + +func sizeVerifyBigIntHook(from, to reflect.Type, data any) (any, error) { + if from.Implements(types.SizedBigIntType()) && + !to.Implements(types.SizedBigIntType()) && + !reflect.PointerTo(to).Implements(types.SizedBigIntType()) { + return codec.BigIntHook(from, bigIntType, reflect.ValueOf(data).Convert(bigIntType).Interface()) + } + + if !to.Implements(types.SizedBigIntType()) { + return data, nil + } + + var err error + data, err = codec.BigIntHook(from, bigIntType, data) + if err != nil { + return nil, err + } + + bi, ok := data.(*big.Int) + if !ok { + return data, nil + } + + converted := reflect.ValueOf(bi).Convert(to).Interface().(types.SizedBigInt) + return converted, converted.Verify() +} + +func decodeAccountAndAllowArraySliceHook(from, to reflect.Type, data any) (any, error) { + if from.Kind() == reflect.String && + (to == reflect.TypeOf(common.Address{}) || to == reflect.TypeOf(&common.Address{})) { + return decodeAddress(data) + } + + if from.Kind() == reflect.Pointer && to.Kind() != reflect.Pointer && from != nil && + (from.Elem().Kind() == reflect.Slice || from.Elem().Kind() == reflect.Array) { + return reflect.ValueOf(data).Elem().Interface(), nil + } + + return data, nil +} + +func decodeAddress(data any) (any, error) { + decoded, err := hexutil.Decode(data.(string)) + if err != nil { + return nil, fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) + } else if len(decoded) != common.AddressLength { + return nil, fmt.Errorf( + "%w: wrong number size for address expected %v got %v", + commontypes.ErrSliceWrongLen, + common.AddressLength, len(decoded)) + } + + return common.Address(decoded), nil +} diff --git a/core/services/relay/evm/codec_fuzz_test.go b/core/services/relay/evm/codec_fuzz_test.go new file mode 100644 index 00000000000..5870e9d77ad --- /dev/null +++ b/core/services/relay/evm/codec_fuzz_test.go @@ -0,0 +1,12 @@ +package evm_test + +import ( + "testing" + + "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" +) + +func FuzzCodec(f *testing.F) { + tester := &codecInterfaceTester{} + interfacetests.RunCodecInterfaceFuzzTests(f, tester) +} diff --git a/core/services/relay/evm/codec_test.go b/core/services/relay/evm/codec_test.go new file mode 100644 index 00000000000..b13051cb010 --- /dev/null +++ b/core/services/relay/evm/codec_test.go @@ -0,0 +1,210 @@ +package evm_test + +import ( + "encoding/json" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common/hexutil" + ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + looptestutils "github.com/smartcontractkit/chainlink-common/pkg/loop/testutils" //nolint common practice to import test mods with . + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . + + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/chain_reader_example" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +const anyExtraValue = 3 + +func TestCodec(t *testing.T) { + tester := &codecInterfaceTester{} + RunCodecInterfaceTests(t, tester) + RunCodecInterfaceTests(t, looptestutils.WrapCodecTesterForLoop(tester)) + + anyN := 10 + c := tester.GetCodec(t) + t.Run("GetMaxEncodingSize delegates to GetMaxSize", func(t *testing.T) { + actual, err := c.GetMaxEncodingSize(testutils.Context(t), anyN, sizeItemType) + assert.NoError(t, err) + + expected, err := types.GetMaxSize(anyN, parseDefs(t)[sizeItemType]) + require.NoError(t, err) + assert.Equal(t, expected, actual) + }) + + t.Run("GetMaxDecodingSize delegates to GetMaxSize", func(t *testing.T) { + actual, err := c.GetMaxDecodingSize(testutils.Context(t), anyN, sizeItemType) + assert.NoError(t, err) + + expected, err := types.GetMaxSize(anyN, parseDefs(t)[sizeItemType]) + require.NoError(t, err) + assert.Equal(t, expected, actual) + }) +} + +type codecInterfaceTester struct{} + +func (it *codecInterfaceTester) Setup(_ *testing.T) {} + +func (it *codecInterfaceTester) GetAccountBytes(i int) []byte { + account := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + // fuzz tests can make -ve numbers + if i < 0 { + i = -i + } + account[i%20] += byte(i) + account[(i+3)%20] += byte(i + 3) + return account[:] +} + +func (it *codecInterfaceTester) EncodeFields(t *testing.T, request *EncodeRequest) []byte { + if request.TestOn == TestItemType { + return encodeFieldsOnItem(t, request) + } + + return encodeFieldsOnSliceOrArray(t, request) +} + +func (it *codecInterfaceTester) GetCodec(t *testing.T) commontypes.Codec { + codecConfig := types.CodecConfig{Configs: map[string]types.ChainCodecConfig{}} + testStruct := CreateTestStruct(0, it) + for k, v := range codecDefs { + defBytes, err := json.Marshal(v) + require.NoError(t, err) + entry := codecConfig.Configs[k] + entry.TypeABI = string(defBytes) + + if k != sizeItemType && k != NilType { + entry.ModifierConfigs = codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + } + } + + if k == TestItemWithConfigExtra { + hardCode := &codec.HardCodeModifierConfig{ + OnChainValues: map[string]any{ + "BigField": testStruct.BigField.String(), + "Account": hexutil.Encode(testStruct.Account), + }, + OffChainValues: map[string]any{"ExtraField": anyExtraValue}, + } + entry.ModifierConfigs = append(entry.ModifierConfigs, hardCode) + } + codecConfig.Configs[k] = entry + } + + c, err := evm.NewCodec(codecConfig) + require.NoError(t, err) + return c +} + +func (it *codecInterfaceTester) IncludeArrayEncodingSizeEnforcement() bool { + return true +} +func (it *codecInterfaceTester) Name() string { + return "EVM" +} + +func encodeFieldsOnItem(t *testing.T, request *EncodeRequest) ocr2types.Report { + return packArgs(t, argsFromTestStruct(request.TestStructs[0]), parseDefs(t)[TestItemType], request) +} + +func encodeFieldsOnSliceOrArray(t *testing.T, request *EncodeRequest) []byte { + oargs := parseDefs(t)[request.TestOn] + args := make([]any, 1) + + switch request.TestOn { + case TestItemArray1Type: + args[0] = [1]chain_reader_example.TestStruct{toInternalType(request.TestStructs[0])} + case TestItemArray2Type: + args[0] = [2]chain_reader_example.TestStruct{toInternalType(request.TestStructs[0]), toInternalType(request.TestStructs[1])} + default: + tmp := make([]chain_reader_example.TestStruct, len(request.TestStructs)) + for i, ts := range request.TestStructs { + tmp[i] = toInternalType(ts) + } + args[0] = tmp + } + + return packArgs(t, args, oargs, request) +} + +func packArgs(t *testing.T, allArgs []any, oargs abi.Arguments, request *EncodeRequest) []byte { + // extra capacity in case we add an argument + args := make(abi.Arguments, len(oargs), len(oargs)+1) + copy(args, oargs) + // decoding has extra field to decode + if request.ExtraField { + fakeType, err := abi.NewType("int32", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + args = append(args, abi.Argument{Name: "FakeField", Type: fakeType}) + allArgs = append(allArgs, 11) + } + + if request.MissingField { + args = args[1:] //nolint we know it's non-zero len + allArgs = allArgs[1:] //nolint we know it's non-zero len + } + + bytes, err := args.Pack(allArgs...) + require.NoError(t, err) + return bytes +} + +var inner = []abi.ArgumentMarshaling{ + {Name: "IntVal", Type: "int64"}, + {Name: "S", Type: "string"}, +} + +var nested = []abi.ArgumentMarshaling{ + {Name: "FixedBytes", Type: "bytes2"}, + {Name: "Inner", Type: "tuple", Components: inner}, +} + +var ts = []abi.ArgumentMarshaling{ + {Name: "Field", Type: "int32"}, + {Name: "DifferentField", Type: "string"}, + {Name: "OracleId", Type: "uint8"}, + {Name: "OracleIds", Type: "uint8[32]"}, + {Name: "Account", Type: "address"}, + {Name: "Accounts", Type: "address[]"}, + {Name: "BigField", Type: "int192"}, + {Name: "NestedStruct", Type: "tuple", Components: nested}, +} + +const sizeItemType = "item for size" + +var codecDefs = map[string][]abi.ArgumentMarshaling{ + TestItemType: ts, + TestItemSliceType: { + {Name: "", Type: "tuple[]", Components: ts}, + }, + TestItemArray1Type: { + {Name: "", Type: "tuple[1]", Components: ts}, + }, + TestItemArray2Type: { + {Name: "", Type: "tuple[2]", Components: ts}, + }, + sizeItemType: { + {Name: "Stuff", Type: "int256[]"}, + {Name: "OtherStuff", Type: "int256"}, + }, + TestItemWithConfigExtra: ts, + NilType: {}, +} + +func parseDefs(t *testing.T) map[string]abi.Arguments { + bytes, err := json.Marshal(codecDefs) + require.NoError(t, err) + var results map[string]abi.Arguments + require.NoError(t, json.Unmarshal(bytes, &results)) + return results +} diff --git a/core/services/relay/evm/config_poller.go b/core/services/relay/evm/config_poller.go index fe39ed0e343..dc75fe037fe 100644 --- a/core/services/relay/evm/config_poller.go +++ b/core/services/relay/evm/config_poller.go @@ -17,6 +17,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/relay/evm/config_poller_test.go b/core/services/relay/evm/config_poller_test.go index 0a433c3bc54..79533a06f01 100644 --- a/core/services/relay/evm/config_poller_test.go +++ b/core/services/relay/evm/config_poller_test.go @@ -7,8 +7,6 @@ import ( "time" "github.com/ethereum/go-ethereum" - "github.com/smartcontractkit/libocr/gethwrappers2/ocrconfigurationstoreevmsimple" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" @@ -22,17 +20,20 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + "github.com/smartcontractkit/libocr/gethwrappers2/ocrconfigurationstoreevmsimple" testoffchainaggregator2 "github.com/smartcontractkit/libocr/gethwrappers2/testocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" + evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -85,11 +86,9 @@ func TestConfigPoller(t *testing.T) { db := pgtest.NewSqlxDB(t) cfg := pgtest.NewQConfig(false) ethClient = evmclient.NewSimulatedBackendClient(t, b, testutils.SimulatedChainID) - ctx := testutils.Context(t) lorm := logpoller.NewORM(testutils.SimulatedChainID, db, lggr, cfg) lp = logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000) - require.NoError(t, lp.Start(ctx)) - t.Cleanup(func() { lp.Close() }) + servicetest.Run(t, lp) } t.Run("LatestConfig errors if there is no config in logs and config store is unconfigured", func(t *testing.T) { @@ -328,12 +327,12 @@ func setConfig(t *testing.T, pluginConfig median.OffchainConfig, ocrContract *oc for i := 0; i < 4; i++ { oracles = append(oracles, confighelper2.OracleIdentityExtra{ OracleIdentity: confighelper2.OracleIdentity{ - OnchainPublicKey: utils.RandomAddress().Bytes(), - TransmitAccount: ocrtypes2.Account(utils.RandomAddress().Hex()), - OffchainPublicKey: utils.RandomBytes32(), + OnchainPublicKey: evmutils.RandomAddress().Bytes(), + TransmitAccount: ocrtypes2.Account(evmutils.RandomAddress().Hex()), + OffchainPublicKey: evmutils.RandomBytes32(), PeerID: utils.MustNewPeerID(), }, - ConfigEncryptionPublicKey: utils.RandomBytes32(), + ConfigEncryptionPublicKey: evmutils.RandomBytes32(), }) } // Gnerate OnchainConfig diff --git a/core/services/relay/evm/contract_transmitter.go b/core/services/relay/evm/contract_transmitter.go index 470b5bae076..76360e34e1a 100644 --- a/core/services/relay/evm/contract_transmitter.go +++ b/core/services/relay/evm/contract_transmitter.go @@ -16,10 +16,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ContractTransmitter interface { diff --git a/core/services/relay/evm/decoder.go b/core/services/relay/evm/decoder.go new file mode 100644 index 00000000000..f16875d80f6 --- /dev/null +++ b/core/services/relay/evm/decoder.go @@ -0,0 +1,102 @@ +package evm + +import ( + "context" + "fmt" + "reflect" + + "github.com/mitchellh/mapstructure" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type decoder struct { + Definitions map[string]types.CodecEntry +} + +var _ commontypes.Decoder = &decoder{} + +func (m *decoder) Decode(_ context.Context, raw []byte, into any, itemType string) error { + info, ok := m.Definitions[itemType] + if !ok { + return fmt.Errorf("%w: cannot find definition for %s", commontypes.ErrInvalidType, itemType) + } + + decode, err := extractDecoding(info, raw) + if err != nil { + return err + } + + rDecode := reflect.ValueOf(decode) + switch rDecode.Kind() { + case reflect.Array: + return m.decodeArray(into, rDecode) + case reflect.Slice: + iInto := reflect.Indirect(reflect.ValueOf(into)) + length := rDecode.Len() + iInto.Set(reflect.MakeSlice(iInto.Type(), length, length)) + return setElements(length, rDecode, iInto) + default: + return mapstructureDecode(decode, into) + } +} + +func (m *decoder) decodeArray(into any, rDecode reflect.Value) error { + iInto := reflect.Indirect(reflect.ValueOf(into)) + length := rDecode.Len() + if length != iInto.Len() { + return commontypes.ErrSliceWrongLen + } + iInto.Set(reflect.New(iInto.Type()).Elem()) + return setElements(length, rDecode, iInto) +} + +func (m *decoder) GetMaxDecodingSize(_ context.Context, n int, itemType string) (int, error) { + entry, ok := m.Definitions[itemType] + if !ok { + return 0, fmt.Errorf("%w: nil entry", commontypes.ErrInvalidType) + } + return entry.GetMaxSize(n) +} + +func extractDecoding(info types.CodecEntry, raw []byte) (any, error) { + unpacked := map[string]any{} + args := info.Args() + if err := args.UnpackIntoMap(unpacked, raw); err != nil { + return nil, fmt.Errorf("%w: %w: for args %#v", commontypes.ErrInvalidEncoding, err, args) + } + var decode any = unpacked + + if noName, ok := unpacked[""]; ok { + decode = noName + } + return decode, nil +} + +func setElements(length int, rDecode reflect.Value, iInto reflect.Value) error { + for i := 0; i < length; i++ { + if err := mapstructureDecode(rDecode.Index(i).Interface(), iInto.Index(i).Addr().Interface()); err != nil { + return err + } + } + + return nil +} + +func mapstructureDecode(src, dest any) error { + mDecoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ + DecodeHook: mapstructure.ComposeDecodeHookFunc(evmDecoderHooks...), + Result: dest, + Squash: true, + }) + if err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) + } + + if err = mDecoder.Decode(src); err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) + } + return nil +} diff --git a/core/services/relay/evm/encoder.go b/core/services/relay/evm/encoder.go new file mode 100644 index 00000000000..ae60e4ab35a --- /dev/null +++ b/core/services/relay/evm/encoder.go @@ -0,0 +1,145 @@ +package evm + +import ( + "context" + "fmt" + "reflect" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type encoder struct { + Definitions map[string]types.CodecEntry +} + +var _ commontypes.Encoder = &encoder{} + +func (e *encoder) Encode(_ context.Context, item any, itemType string) (res []byte, err error) { + // nil values can cause abi.Arguments.Pack to panic. + defer func() { + if r := recover(); r != nil { + res = nil + err = fmt.Errorf("%w: cannot encode type", commontypes.ErrInvalidType) + } + }() + info, ok := e.Definitions[itemType] + if !ok { + return nil, fmt.Errorf("%w: cannot find definition for %s", commontypes.ErrInvalidType, itemType) + } + + if len(info.Args()) == 0 { + return info.EncodingPrefix(), nil + } else if item == nil { + return nil, fmt.Errorf("%w: cannot encode nil value for %s", commontypes.ErrInvalidType, itemType) + } + + return encode(reflect.ValueOf(item), info) +} + +func (e *encoder) GetMaxEncodingSize(_ context.Context, n int, itemType string) (int, error) { + entry, ok := e.Definitions[itemType] + if !ok { + return 0, fmt.Errorf("%w: nil entry", commontypes.ErrInvalidType) + } + return entry.GetMaxSize(n) +} + +func encode(item reflect.Value, info types.CodecEntry) ([]byte, error) { + for item.Kind() == reflect.Pointer { + item = reflect.Indirect(item) + } + switch item.Kind() { + case reflect.Array, reflect.Slice: + native, err := representArray(item, info) + if err != nil { + return nil, err + } + return pack(info, native) + case reflect.Struct, reflect.Map: + values, err := unrollItem(item, info) + if err != nil { + return nil, err + } + return pack(info, values...) + default: + return nil, fmt.Errorf("%w: cannot encode kind %v", commontypes.ErrInvalidType, item.Kind()) + } +} + +func representArray(item reflect.Value, info types.CodecEntry) (any, error) { + length := item.Len() + checkedType := info.CheckedType() + checked := reflect.New(checkedType) + iChecked := reflect.Indirect(checked) + switch checkedType.Kind() { + case reflect.Array: + if checkedType.Len() != length { + return nil, commontypes.ErrSliceWrongLen + } + case reflect.Slice: + iChecked.Set(reflect.MakeSlice(checkedType, length, length)) + default: + return nil, fmt.Errorf("%w: cannot encode %v as array", commontypes.ErrInvalidType, checkedType.Kind()) + } + + checkedElm := checkedType.Elem() + for i := 0; i < length; i++ { + tmp := reflect.New(checkedElm) + if err := mapstructureDecode(item.Index(i).Interface(), tmp.Interface()); err != nil { + return nil, err + } + iChecked.Index(i).Set(tmp.Elem()) + } + native, err := info.ToNative(checked) + if err != nil { + return nil, err + } + + return native.Elem().Interface(), nil +} + +func unrollItem(item reflect.Value, info types.CodecEntry) ([]any, error) { + checkedType := info.CheckedType() + if item.CanAddr() { + item = item.Addr() + } + + if item.Type() == reflect.PointerTo(checkedType) { + var err error + if item, err = info.ToNative(item); err != nil { + return nil, err + } + } else if !info.IsNativePointer(item.Type()) { + var err error + checked := reflect.New(checkedType) + if err = mapstructureDecode(item.Interface(), checked.Interface()); err != nil { + return nil, err + } + if item, err = info.ToNative(checked); err != nil { + return nil, err + } + } + + item = reflect.Indirect(item) + length := item.NumField() + values := make([]any, length) + iType := item.Type() + for i := 0; i < length; i++ { + if iType.Field(i).IsExported() { + values[i] = item.Field(i).Interface() + } + } + return values, nil +} + +func pack(info types.CodecEntry, values ...any) ([]byte, error) { + bytes, err := info.Args().Pack(values...) + if err != nil { + return nil, fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) + } + + withPrefix := info.EncodingPrefix() + return append(withPrefix, bytes...), nil +} diff --git a/core/services/relay/evm/event_binding.go b/core/services/relay/evm/event_binding.go new file mode 100644 index 00000000000..b7148348e4b --- /dev/null +++ b/core/services/relay/evm/event_binding.go @@ -0,0 +1,291 @@ +package evm + +import ( + "context" + "fmt" + "reflect" + "strings" + "sync" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type eventBinding struct { + address common.Address + contractName string + eventName string + lp logpoller.LogPoller + hash common.Hash + codec commontypes.RemoteCodec + pending bool + bound bool + registerCalled bool + lock sync.Mutex + inputInfo types.CodecEntry + inputModifier codec.Modifier + topicInfo types.CodecEntry + // used to allow Register and Unregister to be unique in case two bindings have the same event. + // otherwise, if one unregisters, it'll unregister both with the LogPoller. + id string +} + +var _ readBinding = &eventBinding{} + +func (e *eventBinding) SetCodec(codec commontypes.RemoteCodec) { + e.codec = codec +} + +func (e *eventBinding) Register() error { + e.lock.Lock() + defer e.lock.Unlock() + + e.registerCalled = true + if !e.bound || e.lp.HasFilter(e.id) { + return nil + } + + if err := e.lp.RegisterFilter(logpoller.Filter{ + Name: e.id, + EventSigs: evmtypes.HashArray{e.hash}, + Addresses: evmtypes.AddressArray{e.address}, + }); err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInternal, err) + } + return nil +} + +func (e *eventBinding) Unregister() error { + e.lock.Lock() + defer e.lock.Unlock() + + if !e.lp.HasFilter(e.id) { + return nil + } + + if err := e.lp.UnregisterFilter(e.id); err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInternal, err) + } + return nil +} + +func (e *eventBinding) GetLatestValue(ctx context.Context, params, into any) error { + if !e.bound { + return fmt.Errorf("%w: event not bound", commontypes.ErrInvalidType) + } + + confs := logpoller.Finalized + if e.pending { + confs = logpoller.Unconfirmed + } + + if len(e.inputInfo.Args()) == 0 { + return e.getLatestValueWithoutFilters(ctx, confs, into) + } + + return e.getLatestValueWithFilters(ctx, confs, params, into) +} + +func (e *eventBinding) Bind(binding commontypes.BoundContract) error { + if err := e.Unregister(); err != nil { + return err + } + + e.address = common.HexToAddress(binding.Address) + e.pending = binding.Pending + e.bound = true + + if e.registerCalled { + return e.Register() + } + return nil +} + +func (e *eventBinding) getLatestValueWithoutFilters(ctx context.Context, confs logpoller.Confirmations, into any) error { + log, err := e.lp.LatestLogByEventSigWithConfs(e.hash, e.address, confs) + if err = wrapInternalErr(err); err != nil { + return err + } + + return e.decodeLog(ctx, log, into) +} + +func (e *eventBinding) getLatestValueWithFilters( + ctx context.Context, confs logpoller.Confirmations, params, into any) error { + offChain, err := e.convertToOffChainType(params) + if err != nil { + return err + } + + checkedParams, err := e.inputModifier.TransformToOnChain(offChain, "" /* unused */) + if err != nil { + return err + } + + nativeParams, err := e.inputInfo.ToNative(reflect.ValueOf(checkedParams)) + if err != nil { + return err + } + + filtersAndIndices, err := e.encodeParams(nativeParams) + if err != nil { + return err + } + + fai := filtersAndIndices[0] + remainingFilters := filtersAndIndices[1:] + + logs, err := e.lp.IndexedLogs(e.hash, e.address, 1, []common.Hash{fai}, confs) + if err != nil { + return wrapInternalErr(err) + } + + // TODO: there should be a better way to ask log poller to filter these + // First, you should be able to ask for as many topics to match + // Second, you should be able to get the latest only + var logToUse *logpoller.Log + for _, log := range logs { + tmp := log + if compareLogs(&tmp, logToUse) > 0 && matchesRemainingFilters(&tmp, remainingFilters) { + // copy so that it's not pointing to the changing variable + logToUse = &tmp + } + } + + if logToUse == nil { + return fmt.Errorf("%w: no events found", commontypes.ErrNotFound) + } + + return e.decodeLog(ctx, logToUse, into) +} + +func (e *eventBinding) convertToOffChainType(params any) (any, error) { + itemType := wrapItemType(e.contractName, e.eventName, true) + offChain, err := e.codec.CreateType(itemType, true) + if err != nil { + return nil, err + } + + if err = mapstructureDecode(params, offChain); err != nil { + return nil, err + } + + return offChain, nil +} + +func compareLogs(log, use *logpoller.Log) int64 { + if use == nil { + return 1 + } + + if log.BlockNumber != use.BlockNumber { + return log.BlockNumber - use.BlockNumber + } + + return log.LogIndex - use.LogIndex +} + +func matchesRemainingFilters(log *logpoller.Log, filters []common.Hash) bool { + for i, rfai := range filters { + if !reflect.DeepEqual(rfai[:], log.Topics[i+2]) { + return false + } + } + + return true +} + +func (e *eventBinding) encodeParams(item reflect.Value) ([]common.Hash, error) { + for item.Kind() == reflect.Pointer { + item = reflect.Indirect(item) + } + + var topics []any + switch item.Kind() { + case reflect.Array, reflect.Slice: + native, err := representArray(item, e.inputInfo) + if err != nil { + return nil, err + } + topics = []any{native} + case reflect.Struct, reflect.Map: + var err error + if topics, err = unrollItem(item, e.inputInfo); err != nil { + return nil, err + } + default: + return nil, fmt.Errorf("%w: cannot encode kind %v", commontypes.ErrInvalidType, item.Kind()) + } + + // abi params allow you to Pack a pointers, but MakeTopics doesn't work with pointers. + if err := e.derefTopics(topics); err != nil { + return nil, err + } + + hashes, err := abi.MakeTopics(topics) + if err != nil { + return nil, wrapInternalErr(err) + } + + if len(hashes) != 1 { + return nil, fmt.Errorf("%w: expected 1 filter set, got %d", commontypes.ErrInternal, len(hashes)) + } + + return hashes[0], nil +} + +func (e *eventBinding) derefTopics(topics []any) error { + for i, topic := range topics { + rTopic := reflect.ValueOf(topic) + if rTopic.Kind() == reflect.Pointer { + if rTopic.IsNil() { + return fmt.Errorf( + "%w: input topic %s cannot be nil", commontypes.ErrInvalidType, e.inputInfo.Args()[i].Name) + } + topics[i] = rTopic.Elem().Interface() + } + } + return nil +} + +func (e *eventBinding) decodeLog(ctx context.Context, log *logpoller.Log, into any) error { + dataType := wrapItemType(e.contractName, e.eventName, false) + if err := e.codec.Decode(ctx, log.Data, into, dataType); err != nil { + return err + } + + topics := make([]common.Hash, len(e.topicInfo.Args())) + if len(log.Topics) < len(topics)+1 { + return fmt.Errorf("%w: not enough topics to decode", commontypes.ErrInvalidType) + } + + for i := 0; i < len(topics); i++ { + topics[i] = common.Hash(log.Topics[i+1]) + } + + topicsInto := map[string]any{} + if err := abi.ParseTopicsIntoMap(topicsInto, e.topicInfo.Args(), topics); err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInvalidType, err) + } + + return mapstructureDecode(topicsInto, into) +} + +func wrapInternalErr(err error) error { + if err == nil { + return nil + } + + errStr := err.Error() + if strings.Contains(errStr, "not found") || strings.Contains(errStr, "no rows") { + return fmt.Errorf("%w: %w", commontypes.ErrNotFound, err) + } + return fmt.Errorf("%w: %w", commontypes.ErrInternal, err) +} diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index b3e22ec5dbc..34d353c48d4 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -12,6 +12,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/jmoiron/sqlx" pkgerrors "github.com/pkg/errors" + "golang.org/x/exp/maps" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" @@ -26,13 +27,11 @@ import ( txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "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/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" mercuryconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config" "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/relay/evm/functions" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" @@ -46,13 +45,14 @@ import ( var _ commontypes.Relayer = &Relayer{} //nolint:staticcheck type Relayer struct { - db *sqlx.DB - chain legacyevm.Chain - lggr logger.Logger - ks CSAETHKeystore - mercuryPool wsrpc.Pool - eventBroadcaster pg.EventBroadcaster - pgCfg pg.QConfig + db *sqlx.DB + chain legacyevm.Chain + lggr logger.Logger + ks CSAETHKeystore + mercuryPool wsrpc.Pool + pgCfg pg.QConfig + chainReader commontypes.ChainReader + codec commontypes.Codec } type CSAETHKeystore interface { @@ -64,7 +64,6 @@ type RelayerOpts struct { *sqlx.DB pg.QConfig CSAETHKeystore - pg.EventBroadcaster MercuryPool wsrpc.Pool } @@ -79,9 +78,6 @@ func (c RelayerOpts) Validate() error { if c.CSAETHKeystore == nil { err = errors.Join(err, errors.New("nil Keystore")) } - if c.EventBroadcaster == nil { - err = errors.Join(err, errors.New("nil Eventbroadcaster")) - } if err != nil { err = fmt.Errorf("invalid RelayerOpts: %w", err) @@ -96,13 +92,12 @@ func NewRelayer(lggr logger.Logger, chain legacyevm.Chain, opts RelayerOpts) (*R } lggr = lggr.Named("Relayer") return &Relayer{ - db: opts.DB, - chain: chain, - lggr: lggr, - ks: opts.CSAETHKeystore, - mercuryPool: opts.MercuryPool, - eventBroadcaster: opts.EventBroadcaster, - pgCfg: opts.QConfig, + db: opts.DB, + chain: chain, + lggr: lggr, + ks: opts.CSAETHKeystore, + mercuryPool: opts.MercuryPool, + pgCfg: opts.QConfig, }, nil } @@ -121,11 +116,12 @@ func (r *Relayer) Close() error { // Ready does noop: always ready func (r *Relayer) Ready() error { - return nil + return r.chain.Ready() } func (r *Relayer) HealthReport() (report map[string]error) { report = make(map[string]error) + maps.Copy(report, r.chain.HealthReport()) return } @@ -150,7 +146,7 @@ func (r *Relayer) NewMercuryProvider(rargs commontypes.RelayArgs, pargs commonty if relayConfig.ChainID.String() != r.chain.ID().String() { return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) } - cw, err := newConfigProvider(lggr, r.chain, relayOpts, r.eventBroadcaster) + cw, err := newConfigProvider(lggr, r.chain, relayOpts) if err != nil { return nil, pkgerrors.WithStack(err) } @@ -188,8 +184,7 @@ func (r *Relayer) NewMercuryProvider(rargs commontypes.RelayArgs, pargs commonty } transmitter := mercury.NewTransmitter(lggr, cw.ContractConfigTracker(), client, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.db, r.pgCfg, transmitterCodec) - chainReader := NewChainReader(r.chain.HeadTracker()) - return NewMercuryProvider(cw, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, chainReader, lggr), nil + return NewMercuryProvider(cw, r.chainReader, r.codec, NewMercuryChainReader(r.chain.HeadTracker()), transmitter, reportCodecV1, reportCodecV2, reportCodecV3, lggr), nil } func (r *Relayer) NewFunctionsProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.FunctionsProvider, error) { @@ -210,7 +205,7 @@ func (r *Relayer) NewConfigProvider(args commontypes.RelayArgs) (commontypes.Con return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) } - configProvider, err := newConfigProvider(lggr, r.chain, relayOpts, r.eventBroadcaster) + configProvider, err := newConfigProvider(lggr, r.chain, relayOpts) if err != nil { // Never return (*configProvider)(nil) return nil, err @@ -320,7 +315,7 @@ func (c *configWatcher) ContractConfigTracker() ocrtypes.ContractConfigTracker { return c.configPoller } -func newConfigProvider(lggr logger.Logger, chain legacyevm.Chain, opts *types.RelayOpts, eventBroadcaster pg.EventBroadcaster) (*configWatcher, error) { +func newConfigProvider(lggr logger.Logger, chain legacyevm.Chain, opts *types.RelayOpts) (*configWatcher, error) { if !common.IsHexAddress(opts.ContractID) { return nil, pkgerrors.Errorf("invalid contractID, expected hex address") } @@ -342,7 +337,6 @@ func newConfigProvider(lggr logger.Logger, chain legacyevm.Chain, opts *types.Re chain.LogPoller(), aggregatorAddress, *relayConfig.FeedID, - eventBroadcaster, // TODO: Does mercury need to support config contract? DF-19182 ) } else { @@ -372,7 +366,12 @@ func newConfigProvider(lggr logger.Logger, chain legacyevm.Chain, opts *types.Re return newConfigWatcher(lggr, aggregatorAddress, contractABI, offchainConfigDigester, cp, chain, relayConfig.FromBlock, opts.New), nil } -func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keystore.Eth) (*contractTransmitter, error) { +type configTransmitterOpts struct { + // override the gas limit default provided in the config watcher + pluginGasLimit *uint32 +} + +func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, ethKeystore keystore.Eth, configWatcher *configWatcher, opts configTransmitterOpts) (*contractTransmitter, error) { var relayConfig types.RelayConfig if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { return nil, err @@ -414,6 +413,9 @@ func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, tra if ocr2Limit != nil { gasLimit = *ocr2Limit } + if opts.pluginGasLimit != nil { + gasLimit = *opts.pluginGasLimit + } transmitter, err := ocrcommon.NewTransmitter( configWatcher.chain.TxManager(), @@ -441,55 +443,6 @@ func newContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, tra ) } -func newPipelineContractTransmitter(lggr logger.Logger, rargs commontypes.RelayArgs, transmitterID string, pluginGasLimit *uint32, configWatcher *configWatcher, spec job.Job, pr pipeline.Runner) (*contractTransmitter, error) { - var relayConfig types.RelayConfig - if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { - return nil, err - } - - if !relayConfig.EffectiveTransmitterID.Valid { - return nil, pkgerrors.New("EffectiveTransmitterID must be specified") - } - effectiveTransmitterAddress := common.HexToAddress(relayConfig.EffectiveTransmitterID.String) - transmitterAddress := common.HexToAddress(transmitterID) - scoped := configWatcher.chain.Config() - strategy := txmgrcommon.NewQueueingTxStrategy(rargs.ExternalJobID, scoped.OCR2().DefaultTransactionQueueDepth(), scoped.Database().DefaultQueryTimeout()) - - var checker txm.TransmitCheckerSpec - if configWatcher.chain.Config().OCR2().SimulateTransactions() { - checker.CheckerType = txm.TransmitCheckerTypeSimulate - } - - gasLimit := configWatcher.chain.Config().EVM().GasEstimator().LimitDefault() - ocr2Limit := configWatcher.chain.Config().EVM().GasEstimator().LimitJobType().OCR2() - if ocr2Limit != nil { - gasLimit = *ocr2Limit - } - if pluginGasLimit != nil { - gasLimit = *pluginGasLimit - } - - return NewOCRContractTransmitter( - configWatcher.contractAddress, - configWatcher.chain.Client(), - configWatcher.contractABI, - ocrcommon.NewPipelineTransmitter( - lggr, - transmitterAddress, - gasLimit, - effectiveTransmitterAddress, - strategy, - checker, - pr, - spec, - configWatcher.chain.ID().String(), - ), - configWatcher.chain.LogPoller(), - lggr, - nil, - ) -} - func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.MedianProvider, error) { lggr := r.lggr.Named("MedianProvider").Named(rargs.ExternalJobID.String()) relayOpts := types.NewRelayOpts(rargs) @@ -501,14 +454,18 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp if expectedChainID != r.chain.ID().String() { return nil, fmt.Errorf("internal error: chain id in spec does not match this relayer's chain: have %s expected %s", relayConfig.ChainID.String(), r.chain.ID().String()) } + if !common.IsHexAddress(relayOpts.ContractID) { + return nil, fmt.Errorf("invalid contractID %s, expected hex address", relayOpts.ContractID) + } + contractID := common.HexToAddress(relayOpts.ContractID) - configWatcher, err := newConfigProvider(lggr, r.chain, relayOpts, r.eventBroadcaster) + configWatcher, err := newConfigProvider(lggr, r.chain, relayOpts) if err != nil { return nil, err } reportCodec := evmreportcodec.ReportCodec{} - contractTransmitter, err := newContractTransmitter(lggr, rargs, pargs.TransmitterID, configWatcher, r.ks.Eth()) + contractTransmitter, err := newContractTransmitter(lggr, rargs, pargs.TransmitterID, r.ks.Eth(), configWatcher, configTransmitterOpts{}) if err != nil { return nil, err } @@ -517,13 +474,48 @@ func (r *Relayer) NewMedianProvider(rargs commontypes.RelayArgs, pargs commontyp if err != nil { return nil, err } - return &medianProvider{ + + medianProvider := medianProvider{ lggr: lggr.Named("MedianProvider"), configWatcher: configWatcher, reportCodec: reportCodec, contractTransmitter: contractTransmitter, medianContract: medianContract, - }, nil + } + + // allow fallback until chain reader is default and median contract is removed, but still log just in case + var chainReaderService ChainReaderService + if relayConfig.ChainReader != nil { + if chainReaderService, err = NewChainReaderService(lggr, r.chain.LogPoller(), r.chain, *relayConfig.ChainReader); err != nil { + return nil, err + } + + boundContracts := []commontypes.BoundContract{{Name: "median", Pending: true, Address: contractID.String()}} + if err = chainReaderService.Bind(context.Background(), boundContracts); err != nil { + return nil, err + } + } else { + lggr.Info("ChainReader missing from RelayConfig; falling back to internal MedianContract") + } + medianProvider.chainReader = chainReaderService + + if relayConfig.Codec != nil { + medianProvider.codec, err = NewCodec(*relayConfig.Codec) + if err != nil { + return nil, err + } + } else { + lggr.Info("Codec missing from RelayConfig; falling back to internal MedianContract") + } + + return &medianProvider, nil +} + +func (r *Relayer) NewAutomationProvider(rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.AutomationProvider, error) { + lggr := r.lggr.Named("AutomationProvider").Named(rargs.ExternalJobID.String()) + ocr2keeperRelayer := NewOCR2KeeperRelayer(r.db, r.chain, lggr.Named("OCR2KeeperRelayer"), r.ks.Eth(), r.pgCfg) + + return ocr2keeperRelayer.NewOCR2KeeperProvider(rargs, pargs) } var _ commontypes.MedianProvider = (*medianProvider)(nil) @@ -534,14 +526,20 @@ type medianProvider struct { contractTransmitter ContractTransmitter reportCodec median.ReportCodec medianContract *medianContract - - ms services.MultiStart + chainReader ChainReaderService + codec commontypes.Codec + ms services.MultiStart } func (p *medianProvider) Name() string { return p.lggr.Name() } func (p *medianProvider) Start(ctx context.Context) error { - return p.ms.Start(ctx, p.configWatcher, p.contractTransmitter, p.medianContract) + srvcs := []services.StartClose{p.configWatcher, p.contractTransmitter, p.medianContract} + if p.chainReader != nil { + srvcs = append(srvcs, p.chainReader) + } + + return p.ms.Start(ctx, srvcs...) } func (p *medianProvider) Close() error { return p.ms.Close() } @@ -579,3 +577,11 @@ func (p *medianProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigeste func (p *medianProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker { return p.configWatcher.ContractConfigTracker() } + +func (p *medianProvider) ChainReader() commontypes.ChainReader { + return p.chainReader +} + +func (p *medianProvider) Codec() commontypes.Codec { + return p.codec +} diff --git a/core/services/relay/evm/evm_test.go b/core/services/relay/evm/evm_test.go index 8f49128ff2d..41e51a7ab8f 100644 --- a/core/services/relay/evm/evm_test.go +++ b/core/services/relay/evm/evm_test.go @@ -15,10 +15,9 @@ import ( func TestRelayerOpts_Validate(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) type fields struct { - DB *sqlx.DB - QConfig pg.QConfig - CSAETHKeystore evm.CSAETHKeystore - EventBroadcaster pg.EventBroadcaster + DB *sqlx.DB + QConfig pg.QConfig + CSAETHKeystore evm.CSAETHKeystore } tests := []struct { name string @@ -28,23 +27,19 @@ func TestRelayerOpts_Validate(t *testing.T) { { name: "all invalid", fields: fields{ - DB: nil, - QConfig: nil, - CSAETHKeystore: nil, - EventBroadcaster: nil, + DB: nil, + QConfig: nil, + CSAETHKeystore: nil, }, wantErrContains: `nil DB nil QConfig -nil Keystore -nil Eventbroadcaster`, +nil Keystore`, }, { name: "missing db, keystore", fields: fields{ - DB: nil, - QConfig: cfg.Database(), - CSAETHKeystore: nil, - EventBroadcaster: pg.NewNullEventBroadcaster(), + DB: nil, + QConfig: cfg.Database(), }, wantErrContains: `nil DB nil Keystore`, @@ -53,10 +48,9 @@ nil Keystore`, for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { c := evm.RelayerOpts{ - DB: tt.fields.DB, - QConfig: tt.fields.QConfig, - CSAETHKeystore: tt.fields.CSAETHKeystore, - EventBroadcaster: tt.fields.EventBroadcaster, + DB: tt.fields.DB, + QConfig: tt.fields.QConfig, + CSAETHKeystore: tt.fields.CSAETHKeystore, } err := c.Validate() if tt.wantErrContains != "" { diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go index 10e5d543b1a..b957ab56f3b 100644 --- a/core/services/relay/evm/functions.go +++ b/core/services/relay/evm/functions.go @@ -18,6 +18,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -85,6 +86,14 @@ func (p *functionsProvider) Name() string { return p.configWatcher.Name() } +func (p *functionsProvider) ChainReader() commontypes.ChainReader { + return nil +} + +func (p *functionsProvider) Codec() commontypes.Codec { + return nil +} + func NewFunctionsProvider(chain legacyevm.Chain, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs, lggr logger.Logger, ethKeystore keystore.Eth, pluginType functionsRelay.FunctionsPluginType) (evmRelayTypes.FunctionsProvider, error) { relayOpts := evmRelayTypes.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() diff --git a/core/services/relay/evm/functions/config_poller_test.go b/core/services/relay/evm/functions/config_poller_test.go index 085f0c6e317..2cf373d2e86 100644 --- a/core/services/relay/evm/functions/config_poller_test.go +++ b/core/services/relay/evm/functions/config_poller_test.go @@ -20,15 +20,17 @@ import ( confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - functionsConfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" + functionsConfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -78,11 +80,9 @@ func runTest(t *testing.T, pluginType functions.FunctionsPluginType, expectedDig ethClient := evmclient.NewSimulatedBackendClient(t, b, big.NewInt(1337)) defer ethClient.Close() lggr := logger.TestLogger(t) - ctx := testutils.Context(t) lorm := logpoller.NewORM(big.NewInt(1337), db, lggr, cfg) lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000) - defer lp.Close() - require.NoError(t, lp.Start(ctx)) + servicetest.Run(t, lp) configPoller, err := functions.NewFunctionsConfigPoller(pluginType, lp, lggr) require.NoError(t, err) require.NoError(t, configPoller.UpdateRoutes(ocrAddress, ocrAddress)) @@ -159,12 +159,12 @@ func setFunctionsConfig(t *testing.T, pluginConfig *functionsConfig.ReportingPlu for i := 0; i < 4; i++ { oracles = append(oracles, confighelper2.OracleIdentityExtra{ OracleIdentity: confighelper2.OracleIdentity{ - OnchainPublicKey: utils.RandomAddress().Bytes(), - TransmitAccount: ocrtypes2.Account(utils.RandomAddress().String()), - OffchainPublicKey: utils.RandomBytes32(), + OnchainPublicKey: evmutils.RandomAddress().Bytes(), + TransmitAccount: ocrtypes2.Account(evmutils.RandomAddress().String()), + OffchainPublicKey: evmutils.RandomBytes32(), PeerID: utils.MustNewPeerID(), }, - ConfigEncryptionPublicKey: utils.RandomBytes32(), + ConfigEncryptionPublicKey: evmutils.RandomBytes32(), }) } diff --git a/core/services/relay/evm/functions/contract_transmitter.go b/core/services/relay/evm/functions/contract_transmitter.go index 17baab4525c..2a62db31a8c 100644 --- a/core/services/relay/evm/functions/contract_transmitter.go +++ b/core/services/relay/evm/functions/contract_transmitter.go @@ -18,12 +18,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/pg" evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type FunctionsContractTransmitter interface { diff --git a/core/services/relay/evm/functions/logpoller_wrapper.go b/core/services/relay/evm/functions/logpoller_wrapper.go index 95f45022ab3..e76b567b42b 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper.go +++ b/core/services/relay/evm/functions/logpoller_wrapper.go @@ -11,6 +11,7 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" @@ -107,7 +108,7 @@ func NewLogPollerWrapper(routerContractAddress common.Address, pluginConfig conf client: client, subscribers: make(map[string]evmRelayTypes.RouteUpdateSubscriber), stopCh: make(services.StopChan), - lggr: lggr, + lggr: lggr.Named("LogPollerWrapper"), }, nil } @@ -135,16 +136,10 @@ func (l *logPollerWrapper) Close() error { } func (l *logPollerWrapper) HealthReport() map[string]error { - return make(map[string]error) -} - -func (l *logPollerWrapper) Name() string { - return "LogPollerWrapper" + return map[string]error{l.Name(): l.Ready()} } -func (l *logPollerWrapper) Ready() error { - return nil -} +func (l *logPollerWrapper) Name() string { return l.lggr.Name() } // methods of LogPollerWrapper func (l *logPollerWrapper) LatestEvents() ([]evmRelayTypes.OracleRequest, []evmRelayTypes.OracleResponse, error) { diff --git a/core/services/relay/evm/functions/logpoller_wrapper_test.go b/core/services/relay/evm/functions/logpoller_wrapper_test.go index 2108e822d5e..9df285b4c25 100644 --- a/core/services/relay/evm/functions/logpoller_wrapper_test.go +++ b/core/services/relay/evm/functions/logpoller_wrapper_test.go @@ -12,11 +12,11 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_coordinator" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" @@ -95,13 +95,12 @@ func TestLogPollerWrapper_SingleSubscriberEmptyEvents(t *testing.T) { subscriber := newSubscriber(1) lpWrapper.SubscribeToUpdates("mock_subscriber", subscriber) - require.NoError(t, lpWrapper.Start(testutils.Context(t))) + servicetest.Run(t, lpWrapper) subscriber.updates.Wait() reqs, resps, err := lpWrapper.LatestEvents() require.NoError(t, err) require.Equal(t, 0, len(reqs)) require.Equal(t, 0, len(resps)) - lpWrapper.Close() } func TestLogPollerWrapper_ErrorOnZeroAddresses(t *testing.T) { @@ -111,10 +110,9 @@ func TestLogPollerWrapper_ErrorOnZeroAddresses(t *testing.T) { client.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(addr(t, "00"), nil) - require.NoError(t, lpWrapper.Start(testutils.Context(t))) + servicetest.Run(t, lpWrapper) _, _, err := lpWrapper.LatestEvents() require.Error(t, err) - lpWrapper.Close() } func TestLogPollerWrapper_LatestEvents_ReorgHandling(t *testing.T) { @@ -135,7 +133,7 @@ func TestLogPollerWrapper_LatestEvents_ReorgHandling(t *testing.T) { // On the 3rd query, the original request log appears again lp.On("Logs", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]logpoller.Log{mockedLog}, nil).Once() - require.NoError(t, lpWrapper.Start(testutils.Context(t))) + servicetest.Run(t, lpWrapper) subscriber.updates.Wait() oracleRequests, _, err := lpWrapper.LatestEvents() diff --git a/core/services/relay/evm/functions/offchain_config_digester.go b/core/services/relay/evm/functions/offchain_config_digester.go index b4467543d98..29547e794ce 100644 --- a/core/services/relay/evm/functions/offchain_config_digester.go +++ b/core/services/relay/evm/functions/offchain_config_digester.go @@ -10,13 +10,13 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" + evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) var ( - _ types.OffchainConfigDigester = &functionsOffchainConfigDigester{} - _ relaytypes.RouteUpdateSubscriber = &functionsOffchainConfigDigester{} - FunctionsDigestPrefix = types.ConfigDigestPrefixEVM + _ types.OffchainConfigDigester = &functionsOffchainConfigDigester{} + _ evmRelayTypes.RouteUpdateSubscriber = &functionsOffchainConfigDigester{} + FunctionsDigestPrefix = types.ConfigDigestPrefixEVM // In order to support multiple OCR plugins with a single jobspec & OCR2Base contract, each plugin must have a unique config digest. // This is accomplished by overriding the single config digest from the contract with a unique prefix for each plugin via this custom offchain digester & config poller. ThresholdDigestPrefix = types.ConfigDigestPrefix(7) diff --git a/core/services/relay/evm/median.go b/core/services/relay/evm/median.go index 3f86d6f8233..e3200d8e867 100644 --- a/core/services/relay/evm/median.go +++ b/core/services/relay/evm/median.go @@ -15,7 +15,6 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" offchain_aggregator_wrapper "github.com/smartcontractkit/chainlink/v2/core/internal/gethwrappers2/generated/offchainaggregator" "github.com/smartcontractkit/chainlink/v2/core/logger" diff --git a/core/services/relay/evm/median_test.go b/core/services/relay/evm/median_test.go new file mode 100644 index 00000000000..9c474006aa7 --- /dev/null +++ b/core/services/relay/evm/median_test.go @@ -0,0 +1,47 @@ +package evm + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +func TestNewMedianProvider(t *testing.T) { + lggr := logger.TestLogger(t) + + chain := mocks.NewChain(t) + chainID := testutils.NewRandomEVMChainID() + chain.On("ID").Return(chainID) + contractID := testutils.NewAddress() + relayer := Relayer{lggr: lggr, chain: chain} + + pargs := commontypes.PluginArgs{} + + t.Run("wrong chainID", func(t *testing.T) { + relayConfigBadChainID := evmtypes.RelayConfig{} + rc, err2 := json.Marshal(&relayConfigBadChainID) + rargs2 := commontypes.RelayArgs{ContractID: contractID.String(), RelayConfig: rc} + require.NoError(t, err2) + _, err2 = relayer.NewMedianProvider(rargs2, pargs) + assert.ErrorContains(t, err2, "chain id in spec does not match") + }) + + t.Run("invalid contractID", func(t *testing.T) { + relayConfig := evmtypes.RelayConfig{ChainID: big.New(chainID)} + rc, err2 := json.Marshal(&relayConfig) + require.NoError(t, err2) + rargsBadContractID := commontypes.RelayArgs{ContractID: "NotAContractID", RelayConfig: rc} + _, err2 = relayer.NewMedianProvider(rargsBadContractID, pargs) + assert.ErrorContains(t, err2, "invalid contractID") + }) +} diff --git a/core/services/relay/evm/mercury/config_digest_test.go b/core/services/relay/evm/mercury/config_digest_test.go index 3e94d075dce..fe718e92fe5 100644 --- a/core/services/relay/evm/mercury/config_digest_test.go +++ b/core/services/relay/evm/mercury/config_digest_test.go @@ -107,7 +107,7 @@ func GenHash(t *testing.T) gopter.Gen { array, ok := byteArray.(*gopter.GenResult).Retrieve() require.True(t, ok, "failed to retrieve gen result") for i, byteVal := range array.([]interface{}) { - rv[i] = byte(byteVal.(uint8)) + rv[i] = byteVal.(uint8) } return rv }, @@ -199,7 +199,7 @@ func GenBytes(t *testing.T) gopter.Gen { iArray := array.([]interface{}) rv := make([]byte, len(iArray)) for i, byteVal := range iArray { - rv[i] = byte(byteVal.(uint8)) + rv[i] = byteVal.(uint8) } return rv }, diff --git a/core/services/relay/evm/mercury/config_poller.go b/core/services/relay/evm/mercury/config_poller.go index 8964a283049..98ef78020c7 100644 --- a/core/services/relay/evm/mercury/config_poller.go +++ b/core/services/relay/evm/mercury/config_poller.go @@ -91,8 +91,6 @@ type ConfigPoller struct { destChainLogPoller logpoller.LogPoller addr common.Address feedId common.Hash - notifyCh chan struct{} - subscription pg.Subscription } func FilterName(addr common.Address, feedID common.Hash) string { @@ -100,43 +98,30 @@ func FilterName(addr common.Address, feedID common.Hash) string { } // NewConfigPoller creates a new Mercury ConfigPoller -func NewConfigPoller(lggr logger.Logger, destChainPoller logpoller.LogPoller, addr common.Address, feedId common.Hash, eventBroadcaster pg.EventBroadcaster) (*ConfigPoller, error) { +func NewConfigPoller(lggr logger.Logger, destChainPoller logpoller.LogPoller, addr common.Address, feedId common.Hash) (*ConfigPoller, error) { err := destChainPoller.RegisterFilter(logpoller.Filter{Name: FilterName(addr, feedId), EventSigs: []common.Hash{FeedScopedConfigSet}, Addresses: []common.Address{addr}}) if err != nil { return nil, err } - subscription, err := eventBroadcaster.Subscribe(pg.ChannelInsertOnEVMLogs, "") - if err != nil { - return nil, err - } - cp := &ConfigPoller{ lggr: lggr, destChainLogPoller: destChainPoller, addr: addr, feedId: feedId, - notifyCh: make(chan struct{}, 1), - subscription: subscription, } return cp, nil } -// Start the subscription to Postgres' notify events. -func (cp *ConfigPoller) Start() { - go cp.startLogSubscription() -} +func (cp *ConfigPoller) Start() {} -// Close the subscription to Postgres' notify events. func (cp *ConfigPoller) Close() error { - cp.subscription.Close() return nil } -// Notify abstracts the logpoller.LogPoller Notify() implementation func (cp *ConfigPoller) Notify() <-chan struct{} { - return cp.notifyCh + return nil // rely on libocr's builtin config polling } // Replay abstracts the logpoller.LogPoller Replay() implementation @@ -190,42 +175,3 @@ func (cp *ConfigPoller) LatestBlockHeight(ctx context.Context) (blockHeight uint } return uint64(latest.BlockNumber), nil } - -func (cp *ConfigPoller) startLogSubscription() { - // trim the leading 0x to make it comparable to pg's hex encoding. - addressPgHex := cp.addr.Hex()[2:] - feedIdPgHex := cp.feedId.Hex()[2:] - - for { - event, ok := <-cp.subscription.Events() - if !ok { - cp.lggr.Debug("eventBroadcaster subscription closed, exiting notify loop") - return - } - - // Event payload should look like: "
:," - addressTopicValues := strings.Split(event.Payload, ":") - if len(addressTopicValues) < 2 { - cp.lggr.Warnf("invalid event from %s channel: %s", pg.ChannelInsertOnEVMLogs, event.Payload) - continue - } - - address := addressTopicValues[0] - if address != addressPgHex { - continue - } - - topicValues := strings.Split(addressTopicValues[1], ",") - if len(topicValues) <= feedIdTopicIndex { - continue - } - if topicValues[feedIdTopicIndex] != feedIdPgHex { - continue - } - - select { - case cp.notifyCh <- struct{}{}: - default: - } - } -} diff --git a/core/services/relay/evm/mercury/config_poller_test.go b/core/services/relay/evm/mercury/config_poller_test.go index 1b3ba72128d..f828938f954 100644 --- a/core/services/relay/evm/mercury/config_poller_test.go +++ b/core/services/relay/evm/mercury/config_poller_test.go @@ -6,7 +6,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/onsi/gomega" "github.com/pkg/errors" confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" @@ -16,17 +15,16 @@ import ( "github.com/stretchr/testify/require" "github.com/umbracle/ethgo/abi" + evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestMercuryConfigPoller(t *testing.T) { - feedID := utils.NewHash() + feedID := evmutils.NewHash() feedIDBytes := [32]byte(feedID) th := SetupTH(t, feedID) - th.subscription.On("Events").Return(nil) notify := th.configPoller.Notify() assert.Empty(t, notify) @@ -42,12 +40,12 @@ func TestMercuryConfigPoller(t *testing.T) { for i := 0; i < n; i++ { oracles = append(oracles, confighelper2.OracleIdentityExtra{ OracleIdentity: confighelper2.OracleIdentity{ - OnchainPublicKey: utils.RandomAddress().Bytes(), - TransmitAccount: ocrtypes2.Account(utils.RandomAddress().String()), - OffchainPublicKey: utils.RandomBytes32(), + OnchainPublicKey: evmutils.RandomAddress().Bytes(), + TransmitAccount: ocrtypes2.Account(evmutils.RandomAddress().String()), + OffchainPublicKey: evmutils.RandomBytes32(), PeerID: utils.MustNewPeerID(), }, - ConfigEncryptionPublicKey: utils.RandomBytes32(), + ConfigEncryptionPublicKey: evmutils.RandomBytes32(), }) } f := uint8(1) @@ -114,54 +112,6 @@ func TestMercuryConfigPoller(t *testing.T) { assert.Equal(t, offchainConfig, newConfig.OffchainConfig) } -func TestNotify(t *testing.T) { - testutils.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/BCF-2746") - feedIDStr := "8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1" - feedIDBytes, err := hexutil.Decode("0x" + feedIDStr) - require.NoError(t, err) - feedID := common.BytesToHash(feedIDBytes) - - eventCh := make(chan pg.Event) - - th := SetupTH(t, feedID) - th.subscription.On("Events").Return((<-chan pg.Event)(eventCh)) - - addressPgHex := th.verifierAddress.Hex()[2:] - - notify := th.configPoller.Notify() - assert.Empty(t, notify) - - eventCh <- pg.Event{} // Empty event - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex} // missing topic values - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1"} // missing feedId topic value - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex + ":8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1,val2"} // wrong index - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1,val2,8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1"} // wrong index - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1,0x8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1"} // 0x prefix - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: "wrong_address:val1,8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1"} // wrong address - assert.Empty(t, notify) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1,8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1"} // expected event to notify on - assert.Eventually(t, func() bool { <-notify; return true }, time.Second, 10*time.Millisecond) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1,8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1"} // try second time - assert.Eventually(t, func() bool { <-notify; return true }, time.Second, 10*time.Millisecond) - - eventCh <- pg.Event{Payload: addressPgHex + ":val1,8257737fdf4f79639585fd0ed01bea93c248a9ad940e98dd27f41c9b6230fed1:additional"} // additional colon separated parts - assert.Eventually(t, func() bool { <-notify; return true }, time.Second, 10*time.Millisecond) -} - func onchainPublicKeyToAddress(publicKeys []types.OnchainPublicKey) (addresses []common.Address, err error) { for _, signer := range publicKeys { if len(signer) != 20 { diff --git a/core/services/relay/evm/mercury/helpers_test.go b/core/services/relay/evm/mercury/helpers_test.go index 3a58a25a557..f1686ee00c8 100644 --- a/core/services/relay/evm/mercury/helpers_test.go +++ b/core/services/relay/evm/mercury/helpers_test.go @@ -17,18 +17,19 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/llo-feeds/generated/verifier_proxy" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" - pgmocks "github.com/smartcontractkit/chainlink/v2/core/services/pg/mocks" reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec" reportcodecv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec" reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -142,8 +143,6 @@ type TestHarness struct { verifierAddress common.Address verifierContract *verifier.Verifier logPoller logpoller.LogPoller - eventBroadcaster *pgmocks.EventBroadcaster - subscription *pgmocks.Subscription } func SetupTH(t *testing.T, feedID common.Hash) TestHarness { @@ -167,17 +166,11 @@ func SetupTH(t *testing.T, feedID common.Hash) TestHarness { cfg := pgtest.NewQConfig(false) ethClient := evmclient.NewSimulatedBackendClient(t, b, big.NewInt(1337)) lggr := logger.TestLogger(t) - ctx := testutils.Context(t) lorm := logpoller.NewORM(big.NewInt(1337), db, lggr, cfg) lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000) - eventBroadcaster := pgmocks.NewEventBroadcaster(t) - subscription := pgmocks.NewSubscription(t) - require.NoError(t, lp.Start(ctx)) - t.Cleanup(func() { lp.Close() }) - - eventBroadcaster.On("Subscribe", "evm.insert_on_logs", "").Return(subscription, nil) + servicetest.Run(t, lp) - configPoller, err := NewConfigPoller(lggr, lp, verifierAddress, feedID, eventBroadcaster) + configPoller, err := NewConfigPoller(lggr, lp, verifierAddress, feedID) require.NoError(t, err) configPoller.Start() @@ -189,7 +182,5 @@ func SetupTH(t *testing.T, feedID common.Hash) TestHarness { verifierAddress: verifierAddress, verifierContract: verifierContract, logPoller: lp, - eventBroadcaster: eventBroadcaster, - subscription: subscription, } } diff --git a/core/services/relay/evm/mercury/mocks/async_deleter.go b/core/services/relay/evm/mercury/mocks/async_deleter.go index c0f583efd18..b706e9c771e 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index d5346ad28cc..40a51b9d92d 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -21,8 +21,8 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -89,7 +89,7 @@ var ( ) type Transmitter interface { - relaymercury.Transmitter + mercury.Transmitter services.Service } diff --git a/core/services/relay/evm/mercury/v1/data_source.go b/core/services/relay/evm/mercury/v1/data_source.go index bc94166e566..ce48ec6cf94 100644 --- a/core/services/relay/evm/mercury/v1/data_source.go +++ b/core/services/relay/evm/mercury/v1/data_source.go @@ -1,4 +1,4 @@ -package mercury_v1 +package v1 import ( "context" @@ -13,8 +13,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v1types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + v1 "github.com/smartcontractkit/chainlink-data-streams/mercury/v1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -41,7 +42,7 @@ var ( ) ) -const nBlocksObservation int = relaymercuryv1.MaxAllowedBlocks +const nBlocksObservation int = v1.MaxAllowedBlocks type Runner interface { ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error) @@ -66,7 +67,7 @@ type datasource struct { mu sync.RWMutex chEnhancedTelem chan<- ocrcommon.EnhancedTelemetryMercuryData - chainReader relaymercury.ChainReader + mercuryChainReader mercury.ChainReader fetcher Fetcher initialBlockNumber *int64 @@ -74,10 +75,10 @@ type datasource struct { zeroBlocksCounter prometheus.Counter } -var _ relaymercuryv1.DataSource = &datasource{} +var _ v1.DataSource = &datasource{} -func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, chainReader relaymercury.ChainReader, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { - return &datasource{pr, jb, spec, lggr, s, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, chainReader, fetcher, initialBlockNumber, insufficientBlocksCount.WithLabelValues(feedID.String()), zeroBlocksCount.WithLabelValues(feedID.String())} +func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, mercuryChainReader mercury.ChainReader, fetcher Fetcher, initialBlockNumber *int64, feedID mercuryutils.FeedID) *datasource { + return &datasource{pr, jb, spec, lggr, s, orm, reportcodec.ReportCodec{}, feedID, sync.RWMutex{}, enhancedTelemChan, mercuryChainReader, fetcher, initialBlockNumber, insufficientBlocksCount.WithLabelValues(feedID.String()), zeroBlocksCount.WithLabelValues(feedID.String())} } type ErrEmptyLatestReport struct { @@ -90,7 +91,7 @@ func (e ErrEmptyLatestReport) Error() string { return fmt.Sprintf("FetchInitialMaxFinalizedBlockNumber returned empty LatestReport; this is a new feed. No initialBlockNumber was set, tried to use current block number to determine maxFinalizedBlockNumber but got error: %v", e.Err) } -func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedBlockNum bool) (obs relaymercuryv1.Observation, pipelineExecutionErr error) { +func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedBlockNum bool) (obs v1types.Observation, pipelineExecutionErr error) { // setLatestBlocks must come chronologically before observations, along // with observationTimestamp, to avoid front-running @@ -204,9 +205,9 @@ func toBigInt(val interface{}) (*big.Int, error) { } type parseOutput struct { - benchmarkPrice relaymercury.ObsResult[*big.Int] - bid relaymercury.ObsResult[*big.Int] - ask relaymercury.ObsResult[*big.Int] + benchmarkPrice mercury.ObsResult[*big.Int] + bid mercury.ObsResult[*big.Int] + ask mercury.ObsResult[*big.Int] } // parse expects the output of observe to be three values, in the following order: @@ -290,8 +291,9 @@ func (ds *datasource) executeRun(ctx context.Context) (*pipeline.Run, pipeline.T return run, trrs, err } -func (ds *datasource) setLatestBlocks(ctx context.Context, obs *relaymercuryv1.Observation) error { - latestBlocks, err := ds.chainReader.LatestHeads(ctx, nBlocksObservation) +func (ds *datasource) setLatestBlocks(ctx context.Context, obs *v1types.Observation) error { + latestBlocks, err := ds.mercuryChainReader.LatestHeads(ctx, nBlocksObservation) + if err != nil { ds.lggr.Errorw("failed to read latest blocks", "error", err) return err @@ -318,7 +320,7 @@ func (ds *datasource) setLatestBlocks(ctx context.Context, obs *relaymercuryv1.O for _, block := range latestBlocks { obs.LatestBlocks = append( obs.LatestBlocks, - relaymercuryv1.NewBlock(int64(block.Number), block.Hash, block.Timestamp)) + v1types.NewBlock(int64(block.Number), block.Hash, block.Timestamp)) } return nil diff --git a/core/services/relay/evm/mercury/v1/data_source_test.go b/core/services/relay/evm/mercury/v1/data_source_test.go index d8d7d39dbb8..e0769fe5b64 100644 --- a/core/services/relay/evm/mercury/v1/data_source_test.go +++ b/core/services/relay/evm/mercury/v1/data_source_test.go @@ -1,4 +1,4 @@ -package mercury_v1 +package v1 import ( "context" @@ -15,25 +15,25 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" + mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + commonmocks "github.com/smartcontractkit/chainlink/v2/common/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "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/services/relay/evm" mercurymocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/mocks" mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) -var _ relaymercury.MercuryServerFetcher = &mockFetcher{} +var _ mercurytypes.ServerFetcher = &mockFetcher{} type mockFetcher struct { num *int64 @@ -71,10 +71,10 @@ func (m *mockORM) LatestReport(ctx context.Context, feedID [32]byte, qopts ...pg type mockChainReader struct { err error - obs []relaymercury.Head + obs []mercurytypes.Head } -func (m *mockChainReader) LatestHeads(context.Context, int) ([]relaymercury.Head, error) { +func (m *mockChainReader) LatestHeads(context.Context, int) ([]mercurytypes.Head, error) { return m.obs, m.err } @@ -118,7 +118,7 @@ func TestMercury_Observe(t *testing.T) { ds.spec = spec h := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) - ds.chainReader = evm.NewChainReader(h) + ds.mercuryChainReader = evm.NewMercuryChainReader(h) head := &evmtypes.Head{ Number: int64(rand.Int31()), @@ -210,7 +210,7 @@ func TestMercury_Observe(t *testing.T) { t.Run("if no current block available", func(t *testing.T) { h2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) h2.On("LatestChain").Return((*evmtypes.Head)(nil)) - ds.chainReader = evm.NewChainReader(h2) + ds.mercuryChainReader = evm.NewMercuryChainReader(h2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -221,7 +221,7 @@ func TestMercury_Observe(t *testing.T) { }) }) - ds.chainReader = evm.NewChainReader(h) + ds.mercuryChainReader = evm.NewMercuryChainReader(h) t.Run("when fetchMaxFinalizedBlockNum=false", func(t *testing.T) { t.Run("when run execution fails, returns error", func(t *testing.T) { @@ -321,7 +321,7 @@ func TestMercury_Observe(t *testing.T) { t.Run("when chain length is zero", func(t *testing.T) { ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return((*evmtypes.Head)(nil)) - ds.chainReader = evm.NewChainReader(ht2) + ds.mercuryChainReader = evm.NewMercuryChainReader(ht2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -346,7 +346,7 @@ func TestMercury_Observe(t *testing.T) { ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return(h6) - ds.chainReader = evm.NewChainReader(ht2) + ds.mercuryChainReader = evm.NewMercuryChainReader(ht2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -369,7 +369,7 @@ func TestMercury_Observe(t *testing.T) { ht2 := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) ht2.On("LatestChain").Return(heads[len(heads)-1]) - ds.chainReader = evm.NewChainReader(ht2) + ds.mercuryChainReader = evm.NewMercuryChainReader(ht2) obs, err := ds.Observe(ctx, repts, true) assert.NoError(t, err) @@ -384,14 +384,14 @@ func TestMercury_Observe(t *testing.T) { }) t.Run("when chain reader returns an error", func(t *testing.T) { - ds.chainReader = &mockChainReader{ + ds.mercuryChainReader = &mockChainReader{ err: io.EOF, obs: nil, } obs, err := ds.Observe(ctx, repts, true) assert.Error(t, err) - assert.Equal(t, obs, relaymercuryv1.Observation{}) + assert.Equal(t, obs, v1.Observation{}) }) }) } @@ -414,9 +414,9 @@ func TestMercury_SetLatestBlocks(t *testing.T) { t.Run("returns head from headtracker if present", func(t *testing.T) { headTracker := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) headTracker.On("LatestChain").Return(&h, nil) - ds.chainReader = evm.NewChainReader(headTracker) + ds.mercuryChainReader = evm.NewMercuryChainReader(headTracker) - obs := relaymercuryv1.Observation{} + obs := v1.Observation{} err := ds.setLatestBlocks(testutils.Context(t), &obs) assert.NoError(t, err) @@ -432,9 +432,8 @@ func TestMercury_SetLatestBlocks(t *testing.T) { headTracker := commonmocks.NewHeadTracker[*evmtypes.Head, common.Hash](t) // This can happen in some cases e.g. RPC node is offline headTracker.On("LatestChain").Return((*evmtypes.Head)(nil)) - - ds.chainReader = evm.NewChainReader(headTracker) - obs := relaymercuryv1.Observation{} + ds.mercuryChainReader = evm.NewChainReader(headTracker) + obs := v1.Observation{} err := ds.setLatestBlocks(testutils.Context(t), &obs) assert.NoError(t, err) diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go index 28688e3b17a..8f2eac59c33 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec.go @@ -11,8 +11,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - reportcodec "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - + v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" reporttypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/types" @@ -25,7 +24,7 @@ import ( var ReportTypes = reporttypes.GetSchema() var maxReportLength = 32 * len(ReportTypes) // each arg is 256 bit EVM word -var _ reportcodec.ReportCodec = &ReportCodec{} +var _ v1.ReportCodec = &ReportCodec{} type ReportCodec struct { logger logger.Logger @@ -36,7 +35,7 @@ func NewReportCodec(feedID [32]byte, lggr logger.Logger) *ReportCodec { return &ReportCodec{lggr, feedID} } -func (r *ReportCodec) BuildReport(rf reportcodec.ReportFields) (ocrtypes.Report, error) { +func (r *ReportCodec) BuildReport(rf v1.ReportFields) (ocrtypes.Report, error) { var merr error if rf.BenchmarkPrice == nil { merr = errors.Join(merr, errors.New("benchmarkPrice may not be nil")) diff --git a/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go index f630b4522b4..3e898d6c1da 100644 --- a/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v1/reportcodec/report_codec_test.go @@ -11,15 +11,14 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - - "github.com/smartcontractkit/chainlink/v2/core/utils" + v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) var hash = hexutil.MustDecode("0x552c2cea3ab43bae137d89ee6142a01db3ae2b5678bc3c9bd5f509f537bea57b") -func newValidReportFields() relaymercuryv1.ReportFields { - return relaymercuryv1.ReportFields{ +func newValidReportFields() v1.ReportFields { + return v1.ReportFields{ Timestamp: 242, BenchmarkPrice: big.NewInt(243), Bid: big.NewInt(244), @@ -35,7 +34,7 @@ func Test_ReportCodec(t *testing.T) { r := ReportCodec{} t.Run("BuildReport errors on zero fields", func(t *testing.T) { - _, err := r.BuildReport(relaymercuryv1.ReportFields{}) + _, err := r.BuildReport(v1.ReportFields{}) require.Error(t, err) assert.Contains(t, err.Error(), "benchmarkPrice may not be nil") assert.Contains(t, err.Error(), "bid may not be nil") diff --git a/core/services/relay/evm/mercury/v2/data_source.go b/core/services/relay/evm/mercury/v2/data_source.go index ec6cf5ad106..7c2d6424fae 100644 --- a/core/services/relay/evm/mercury/v2/data_source.go +++ b/core/services/relay/evm/mercury/v2/data_source.go @@ -1,4 +1,4 @@ -package mercury_v2 +package v2 import ( "context" @@ -10,8 +10,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v2types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" + v2 "github.com/smartcontractkit/chainlink-data-streams/mercury/v2" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -52,13 +53,13 @@ type datasource struct { chEnhancedTelem chan<- ocrcommon.EnhancedTelemetryMercuryData } -var _ relaymercuryv2.DataSource = &datasource{} +var _ v2.DataSource = &datasource{} func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, feedID mercuryutils.FeedID, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, fetcher LatestReportFetcher, linkFeedID, nativeFeedID mercuryutils.FeedID) *datasource { return &datasource{pr, jb, spec, feedID, lggr, s, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan} } -func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs relaymercuryv2.Observation, pipelineExecutionErr error) { +func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs v2types.Observation, pipelineExecutionErr error) { var wg sync.WaitGroup ctx, cancel := context.WithCancel(ctx) @@ -116,8 +117,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam obs.LinkPrice.Val, obs.LinkPrice.Err = ds.fetcher.LatestPrice(ctx, ds.linkFeedID) if obs.LinkPrice.Val == nil && obs.LinkPrice.Err == nil { mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.linkFeedID.String()).Inc() - ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", relaymercuryv2.MissingPrice), "linkFeedID", ds.linkFeedID) - obs.LinkPrice.Val = relaymercuryv2.MissingPrice + ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", v2.MissingPrice), "linkFeedID", ds.linkFeedID) + obs.LinkPrice.Val = v2.MissingPrice } else if obs.LinkPrice.Err != nil { mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.linkFeedID.String()).Inc() ds.lggr.Errorw("Mercury server returned error querying LINK price feed", "err", obs.LinkPrice.Err, "linkFeedID", ds.linkFeedID) @@ -134,8 +135,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam obs.NativePrice.Val, obs.NativePrice.Err = ds.fetcher.LatestPrice(ctx, ds.nativeFeedID) if obs.NativePrice.Val == nil && obs.NativePrice.Err == nil { mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.nativeFeedID.String()).Inc() - ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", relaymercuryv2.MissingPrice), "nativeFeedID", ds.nativeFeedID) - obs.NativePrice.Val = relaymercuryv2.MissingPrice + ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", v2.MissingPrice), "nativeFeedID", ds.nativeFeedID) + obs.NativePrice.Val = v2.MissingPrice } else if obs.NativePrice.Err != nil { mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.nativeFeedID.String()).Inc() ds.lggr.Errorw("Mercury server returned error querying native price feed", "err", obs.NativePrice.Err, "nativeFeedID", ds.nativeFeedID) @@ -184,7 +185,7 @@ func toBigInt(val interface{}) (*big.Int, error) { } type parseOutput struct { - benchmarkPrice relaymercury.ObsResult[*big.Int] + benchmarkPrice mercury.ObsResult[*big.Int] } func (ds *datasource) parse(trrs pipeline.TaskRunResults) (o parseOutput, merr error) { diff --git a/core/services/relay/evm/mercury/v2/data_source_test.go b/core/services/relay/evm/mercury/v2/data_source_test.go index d1030327e10..c9ae37ae018 100644 --- a/core/services/relay/evm/mercury/v2/data_source_test.go +++ b/core/services/relay/evm/mercury/v2/data_source_test.go @@ -1,4 +1,4 @@ -package mercury_v2 +package v2 import ( "context" @@ -8,11 +8,11 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v2 "github.com/smartcontractkit/chainlink-data-streams/mercury/v2" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" @@ -22,7 +22,7 @@ import ( reportcodecv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec" ) -var _ relaymercury.MercuryServerFetcher = &mockFetcher{} +var _ mercury.ServerFetcher = &mockFetcher{} type mockFetcher struct { ts int64 @@ -279,9 +279,9 @@ func Test_Datasource(t *testing.T) { obs, err := ds.Observe(ctx, repts, false) assert.NoError(t, err) - assert.Equal(t, obs.LinkPrice.Val, relaymercuryv2.MissingPrice) + assert.Equal(t, obs.LinkPrice.Val, v2.MissingPrice) assert.Nil(t, obs.LinkPrice.Err) - assert.Equal(t, obs.NativePrice.Val, relaymercuryv2.MissingPrice) + assert.Equal(t, obs.NativePrice.Val, v2.MissingPrice) assert.Nil(t, obs.NativePrice.Err) }) }) diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go index 6b13b3b6ef8..33c5fa9a326 100644 --- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec.go @@ -9,7 +9,7 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - reportcodec "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" @@ -20,7 +20,7 @@ var ReportTypes = reporttypes.GetSchema() var maxReportLength = 32 * len(ReportTypes) // each arg is 256 bit EVM word var zero = big.NewInt(0) -var _ reportcodec.ReportCodec = &ReportCodec{} +var _ v2.ReportCodec = &ReportCodec{} type ReportCodec struct { logger logger.Logger @@ -31,7 +31,7 @@ func NewReportCodec(feedID [32]byte, lggr logger.Logger) *ReportCodec { return &ReportCodec{lggr, feedID} } -func (r *ReportCodec) BuildReport(rf reportcodec.ReportFields) (ocrtypes.Report, error) { +func (r *ReportCodec) BuildReport(rf v2.ReportFields) (ocrtypes.Report, error) { var merr error if rf.BenchmarkPrice == nil { merr = errors.Join(merr, errors.New("benchmarkPrice may not be nil")) diff --git a/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go index 3a58337b4ce..36b3a443880 100644 --- a/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v2/reportcodec/report_codec_test.go @@ -9,11 +9,11 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" + v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" ) -func newValidReportFields() relaymercuryv2.ReportFields { - return relaymercuryv2.ReportFields{ +func newValidReportFields() v2.ReportFields { + return v2.ReportFields{ Timestamp: 242, BenchmarkPrice: big.NewInt(243), ValidFromTimestamp: 123, @@ -27,7 +27,7 @@ func Test_ReportCodec_BuildReport(t *testing.T) { r := ReportCodec{} t.Run("BuildReport errors on zero values", func(t *testing.T) { - _, err := r.BuildReport(relaymercuryv2.ReportFields{}) + _, err := r.BuildReport(v2.ReportFields{}) require.Error(t, err) assert.Contains(t, err.Error(), "benchmarkPrice may not be nil") assert.Contains(t, err.Error(), "linkFee may not be nil") diff --git a/core/services/relay/evm/mercury/v3/data_source.go b/core/services/relay/evm/mercury/v3/data_source.go index d5e1e5716dd..a751149f378 100644 --- a/core/services/relay/evm/mercury/v3/data_source.go +++ b/core/services/relay/evm/mercury/v3/data_source.go @@ -1,4 +1,4 @@ -package mercury_v3 +package v3 import ( "context" @@ -11,8 +11,9 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v3types "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" + v3 "github.com/smartcontractkit/chainlink-data-streams/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" @@ -53,13 +54,13 @@ type datasource struct { chEnhancedTelem chan<- ocrcommon.EnhancedTelemetryMercuryData } -var _ relaymercuryv3.DataSource = &datasource{} +var _ v3.DataSource = &datasource{} func NewDataSource(orm types.DataSourceORM, pr pipeline.Runner, jb job.Job, spec pipeline.Spec, feedID mercuryutils.FeedID, lggr logger.Logger, s ocrcommon.Saver, enhancedTelemChan chan ocrcommon.EnhancedTelemetryMercuryData, fetcher LatestReportFetcher, linkFeedID, nativeFeedID mercuryutils.FeedID) *datasource { return &datasource{pr, jb, spec, feedID, lggr, s, orm, reportcodec.ReportCodec{}, fetcher, linkFeedID, nativeFeedID, sync.RWMutex{}, enhancedTelemChan} } -func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs relaymercuryv3.Observation, pipelineExecutionErr error) { +func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestamp, fetchMaxFinalizedTimestamp bool) (obs v3types.Observation, pipelineExecutionErr error) { var wg sync.WaitGroup ctx, cancel := context.WithCancel(ctx) @@ -119,8 +120,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam obs.LinkPrice.Val, obs.LinkPrice.Err = ds.fetcher.LatestPrice(ctx, ds.linkFeedID) if obs.LinkPrice.Val == nil && obs.LinkPrice.Err == nil { mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.linkFeedID.String()).Inc() - ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", relaymercuryv3.MissingPrice), "linkFeedID", ds.linkFeedID) - obs.LinkPrice.Val = relaymercuryv3.MissingPrice + ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing LINK feed, using sentinel value of %s", v3.MissingPrice), "linkFeedID", ds.linkFeedID) + obs.LinkPrice.Val = v3.MissingPrice } else if obs.LinkPrice.Err != nil { mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.linkFeedID.String()).Inc() ds.lggr.Errorw("Mercury server returned error querying LINK price feed", "err", obs.LinkPrice.Err, "linkFeedID", ds.linkFeedID) @@ -137,8 +138,8 @@ func (ds *datasource) Observe(ctx context.Context, repts ocrtypes.ReportTimestam obs.NativePrice.Val, obs.NativePrice.Err = ds.fetcher.LatestPrice(ctx, ds.nativeFeedID) if obs.NativePrice.Val == nil && obs.NativePrice.Err == nil { mercurytypes.PriceFeedMissingCount.WithLabelValues(ds.nativeFeedID.String()).Inc() - ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", relaymercuryv3.MissingPrice), "nativeFeedID", ds.nativeFeedID) - obs.NativePrice.Val = relaymercuryv3.MissingPrice + ds.lggr.Warnw(fmt.Sprintf("Mercury server was missing native feed, using sentinel value of %s", v3.MissingPrice), "nativeFeedID", ds.nativeFeedID) + obs.NativePrice.Val = v3.MissingPrice } else if obs.NativePrice.Err != nil { mercurytypes.PriceFeedErrorCount.WithLabelValues(ds.nativeFeedID.String()).Inc() ds.lggr.Errorw("Mercury server returned error querying native price feed", "err", obs.NativePrice.Err, "nativeFeedID", ds.nativeFeedID) @@ -187,9 +188,9 @@ func toBigInt(val interface{}) (*big.Int, error) { } type parseOutput struct { - benchmarkPrice relaymercury.ObsResult[*big.Int] - bid relaymercury.ObsResult[*big.Int] - ask relaymercury.ObsResult[*big.Int] + benchmarkPrice mercury.ObsResult[*big.Int] + bid mercury.ObsResult[*big.Int] + ask mercury.ObsResult[*big.Int] } func (ds *datasource) parse(trrs pipeline.TaskRunResults) (o parseOutput, merr error) { diff --git a/core/services/relay/evm/mercury/v3/data_source_test.go b/core/services/relay/evm/mercury/v3/data_source_test.go index e03e321d093..4ff713abb21 100644 --- a/core/services/relay/evm/mercury/v3/data_source_test.go +++ b/core/services/relay/evm/mercury/v3/data_source_test.go @@ -1,4 +1,4 @@ -package mercury_v3 +package v3 import ( "context" @@ -8,8 +8,8 @@ import ( "github.com/pkg/errors" "github.com/stretchr/testify/assert" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + relaymercuryv3 "github.com/smartcontractkit/chainlink-data-streams/mercury/v3" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -22,7 +22,7 @@ import ( reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" ) -var _ relaymercury.MercuryServerFetcher = &mockFetcher{} +var _ mercurytypes.ServerFetcher = &mockFetcher{} type mockFetcher struct { ts int64 diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go index 6b379dc1948..601431838d2 100644 --- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go +++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec.go @@ -3,14 +3,13 @@ package reportcodec import ( "errors" "fmt" - "math/big" pkgerrors "github.com/pkg/errors" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - reportcodec "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" @@ -21,7 +20,7 @@ var ReportTypes = reporttypes.GetSchema() var maxReportLength = 32 * len(ReportTypes) // each arg is 256 bit EVM word var zero = big.NewInt(0) -var _ reportcodec.ReportCodec = &ReportCodec{} +var _ v3.ReportCodec = &ReportCodec{} type ReportCodec struct { logger logger.Logger @@ -32,7 +31,7 @@ func NewReportCodec(feedID [32]byte, lggr logger.Logger) *ReportCodec { return &ReportCodec{lggr, feedID} } -func (r *ReportCodec) BuildReport(rf reportcodec.ReportFields) (ocrtypes.Report, error) { +func (r *ReportCodec) BuildReport(rf v3.ReportFields) (ocrtypes.Report, error) { var merr error if rf.BenchmarkPrice == nil { merr = errors.Join(merr, errors.New("benchmarkPrice may not be nil")) diff --git a/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go b/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go index 88416f7ea61..752e6ce34b5 100644 --- a/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go +++ b/core/services/relay/evm/mercury/v3/reportcodec/report_codec_test.go @@ -9,11 +9,11 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" + v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" ) -func newValidReportFields() relaymercuryv3.ReportFields { - return relaymercuryv3.ReportFields{ +func newValidReportFields() v3.ReportFields { + return v3.ReportFields{ Timestamp: 242, BenchmarkPrice: big.NewInt(243), Bid: big.NewInt(244), @@ -29,7 +29,7 @@ func Test_ReportCodec_BuildReport(t *testing.T) { r := ReportCodec{} t.Run("BuildReport errors on zero values", func(t *testing.T) { - _, err := r.BuildReport(relaymercuryv3.ReportFields{}) + _, err := r.BuildReport(v3.ReportFields{}) require.Error(t, err) assert.Contains(t, err.Error(), "benchmarkPrice may not be nil") assert.Contains(t, err.Error(), "linkFee may not be nil") diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache.go b/core/services/relay/evm/mercury/wsrpc/cache/cache.go index cab5654081b..712e62e5c0e 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache.go @@ -213,12 +213,14 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest if time.Now().Before(v.expiresAt) { // CACHE HIT promCacheHitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() + m.lggr.Tracew("LatestReport CACHE HIT (hot path)", "feedID", feedIDHex) defer v.RUnlock() return v.val, nil } else if v.fetching { // CACHE WAIT promCacheWaitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() + m.lggr.Tracew("LatestReport CACHE WAIT (hot path)", "feedID", feedIDHex) // if someone else is fetching then wait for the fetch to complete ch := v.fetchCh v.RUnlock() @@ -234,11 +236,13 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest if time.Now().Before(v.expiresAt) { // CACHE HIT promCacheHitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() - defer v.RUnlock() + m.lggr.Tracew("LatestReport CACHE HIT (cold path)", "feedID", feedIDHex) + defer v.Unlock() return v.val, nil } else if v.fetching { // CACHE WAIT promCacheWaitCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() + m.lggr.Tracew("LatestReport CACHE WAIT (cold path)", "feedID", feedIDHex) // if someone else is fetching then wait for the fetch to complete ch := v.fetchCh v.Unlock() @@ -246,6 +250,7 @@ func (m *memCache) LatestReport(ctx context.Context, req *pb.LatestReportRequest } // CACHE MISS promCacheMissCount.WithLabelValues(m.client.ServerURL(), feedIDHex).Inc() + m.lggr.Tracew("LatestReport CACHE MISS (cold path)", "feedID", feedIDHex) // initiate the fetch and wait for result ch := v.initiateFetch() v.Unlock() @@ -328,7 +333,7 @@ func (m *memCache) fetch(req *pb.LatestReportRequest, v *cacheVal) { func (m *memCache) Start(context.Context) error { return m.StartOnce(m.Name(), func() error { - m.lggr.Debugw("MemCache starting", "config", m.cfg) + m.lggr.Debugw("MemCache starting", "config", m.cfg, "serverURL", m.client.ServerURL()) m.wg.Add(1) go m.runloop() return nil diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go b/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go index 3171c8ab643..7101cec39f3 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache_set.go @@ -46,7 +46,7 @@ func newCacheSet(lggr logger.Logger, cfg Config) *cacheSet { func (cs *cacheSet) Start(context.Context) error { return cs.StartOnce("CacheSet", func() error { - cs.lggr.Debugw("CacheSet starting", "config", cs.cfg) + cs.lggr.Debugw("CacheSet starting", "config", cs.cfg, "cachingEnabled", cs.cfg.LatestReportTTL > 0) return nil }) } @@ -65,6 +65,10 @@ func (cs *cacheSet) Close() error { } func (cs *cacheSet) Get(ctx context.Context, client Client) (f Fetcher, err error) { + if cs.cfg.LatestReportTTL == 0 { + // caching disabled + return nil, nil + } ok := cs.IfStarted(func() { f, err = cs.get(ctx, client) }) @@ -104,8 +108,9 @@ func (cs *cacheSet) HealthReport() map[string]error { cs.Name(): cs.Ready(), } cs.RLock() - defer cs.RUnlock() - for _, c := range cs.caches { + caches := maps.Values(cs.caches) + cs.RUnlock() + for _, c := range caches { services.CopyHealth(report, c.HealthReport()) } return report diff --git a/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go b/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go index 4e19c7b56de..f12dc8a9bc7 100644 --- a/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go +++ b/core/services/relay/evm/mercury/wsrpc/cache/cache_set_test.go @@ -3,27 +3,36 @@ package cache import ( "testing" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" ) func Test_CacheSet(t *testing.T) { lggr := logger.TestLogger(t) - cs := newCacheSet(lggr, Config{}) + cs := newCacheSet(lggr, Config{LatestReportTTL: 1}) + disabledCs := newCacheSet(lggr, Config{LatestReportTTL: 0}) ctx := testutils.Context(t) - require.NoError(t, cs.Start(ctx)) - t.Cleanup(func() { - assert.NoError(t, cs.Close()) - }) + servicetest.Run(t, cs) t.Run("Get", func(t *testing.T) { c := &mockClient{} var err error var f Fetcher + t.Run("with caching disabled, returns nil, nil", func(t *testing.T) { + assert.Len(t, disabledCs.caches, 0) + + f, err = disabledCs.Get(ctx, c) + require.NoError(t, err) + + assert.Nil(t, f) + assert.Len(t, disabledCs.caches, 0) + }) + t.Run("with virgin cacheset, makes new entry and returns it", func(t *testing.T) { assert.Len(t, cs.caches, 0) diff --git a/core/services/relay/evm/mercury/wsrpc/client.go b/core/services/relay/evm/mercury/wsrpc/client.go index 5cdf1f44e96..c9533717757 100644 --- a/core/services/relay/evm/mercury/wsrpc/client.go +++ b/core/services/relay/evm/mercury/wsrpc/client.go @@ -24,9 +24,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) -// MaxConsecutiveTransmitFailures controls how many consecutive requests are +// MaxConsecutiveRequestFailures controls how many consecutive requests are // allowed to time out before we reset the connection -const MaxConsecutiveTransmitFailures = 5 +const MaxConsecutiveRequestFailures = 10 var ( timeoutCount = promauto.NewCounterVec(prometheus.CounterOpts{ @@ -55,7 +55,7 @@ var ( ) connectionResetCount = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "mercury_connection_reset_count", - Help: fmt.Sprintf("Running count of times connection to mercury server has been reset (connection reset happens automatically after %d consecutive transmit failures)", MaxConsecutiveTransmitFailures), + Help: fmt.Sprintf("Running count of times connection to mercury server has been reset (connection reset happens automatically after %d consecutive request failures)", MaxConsecutiveRequestFailures), }, []string{"serverURL"}, ) @@ -256,13 +256,26 @@ func (w *client) Transmit(ctx context.Context, req *pb.TransmitRequest) (resp *p return nil, errors.Wrap(err, "Transmit call failed") } resp, err = w.rawClient.Transmit(ctx, req) + w.handleTimeout(err) + if err != nil { + w.logger.Warnw("Transmit call failed due to networking error", "err", err, "resp", resp) + incRequestStatusMetric(statusFailed) + } else { + w.logger.Tracew("Transmit call succeeded", "resp", resp) + incRequestStatusMetric(statusSuccess) + setRequestLatencyMetric(float64(time.Since(start).Milliseconds())) + } + return +} + +func (w *client) handleTimeout(err error) { if errors.Is(err, context.DeadlineExceeded) { w.timeoutCountMetric.Inc() cnt := w.consecutiveTimeoutCnt.Add(1) - if cnt == MaxConsecutiveTransmitFailures { + if cnt == MaxConsecutiveRequestFailures { w.logger.Errorf("Timed out on %d consecutive transmits, resetting transport", cnt) - // NOTE: If we get 5+ request timeouts in a row, close and re-open - // the websocket connection. + // NOTE: If we get at least MaxConsecutiveRequestFailures request + // timeouts in a row, close and re-open the websocket connection. // // This *shouldn't* be necessary in theory (ideally, wsrpc would // handle it for us) but it acts as a "belts and braces" approach @@ -271,11 +284,11 @@ func (w *client) Transmit(ctx context.Context, req *pb.TransmitRequest) (resp *p select { case w.chResetTransport <- struct{}{}: default: - // This can happen if we had 5 consecutive timeouts, already - // sent a reset signal, then the connection started working - // again (resetting the count) then we got 5 additional - // failures before the runloop was able to close the bad - // connection. + // This can happen if we had MaxConsecutiveRequestFailures + // consecutive timeouts, already sent a reset signal, then the + // connection started working again (resetting the count) then + // we got MaxConsecutiveRequestFailures additional failures + // before the runloop was able to close the bad connection. // // It should be safe to just ignore in this case. // @@ -286,15 +299,6 @@ func (w *client) Transmit(ctx context.Context, req *pb.TransmitRequest) (resp *p } else { w.consecutiveTimeoutCnt.Store(0) } - if err != nil { - w.logger.Warnw("Transmit call failed due to networking error", "err", err, "resp", resp) - incRequestStatusMetric(statusFailed) - } else { - w.logger.Tracew("Transmit call succeeded", "resp", resp) - incRequestStatusMetric(statusSuccess) - setRequestLatencyMetric(float64(time.Since(start).Milliseconds())) - } - return } func (w *client) LatestReport(ctx context.Context, req *pb.LatestReportRequest) (resp *pb.LatestReportResponse, err error) { @@ -303,17 +307,22 @@ func (w *client) LatestReport(ctx context.Context, req *pb.LatestReportRequest) if err = w.waitForReady(ctx); err != nil { return nil, errors.Wrap(err, "LatestReport failed") } + var cached bool if w.cache == nil { resp, err = w.rawClient.LatestReport(ctx, req) + w.handleTimeout(err) } else { + cached = true resp, err = w.cache.LatestReport(ctx, req) } if err != nil { - lggr.Errorw("LatestReport failed", "err", err, "resp", resp) + lggr.Errorw("LatestReport failed", "err", err, "resp", resp, "cached", cached) } else if resp.Error != "" { - lggr.Errorw("LatestReport failed; mercury server returned error", "err", resp.Error, "resp", resp) + lggr.Errorw("LatestReport failed; mercury server returned error", "err", resp.Error, "resp", resp, "cached", cached) + } else if !cached { + lggr.Debugw("LatestReport succeeded", "resp", resp, "cached", cached) } else { - lggr.Debugw("LatestReport succeeded", "resp", resp) + lggr.Tracew("LatestReport succeeded", "resp", resp, "cached", cached) } return } diff --git a/core/services/relay/evm/mercury/wsrpc/client_test.go b/core/services/relay/evm/mercury/wsrpc/client_test.go index 9b0100a3cdd..b4a3dae733d 100644 --- a/core/services/relay/evm/mercury/wsrpc/client_test.go +++ b/core/services/relay/evm/mercury/wsrpc/client_test.go @@ -8,14 +8,23 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" - mocks "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/mocks" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" ) +// simulate start without dialling +func simulateStart(ctx context.Context, t *testing.T, c *client) { + require.NoError(t, c.StartOnce("Mock WSRPC Client", func() (err error) { + c.cache, err = c.cacheSet.Get(ctx, c) + return err + })) +} + var _ cache.CacheSet = &mockCacheSet{} type mockCacheSet struct{} @@ -53,7 +62,7 @@ func Test_Client_Transmit(t *testing.T) { noopCacheSet := newNoopCacheSet() - t.Run("sends on reset channel after MaxConsecutiveTransmitFailures timed out transmits", func(t *testing.T) { + t.Run("sends on reset channel after MaxConsecutiveRequestFailures timed out transmits", func(t *testing.T) { calls := 0 transmitErr := context.DeadlineExceeded wsrpcClient := &mocks.MockWSRPCClient{ @@ -69,11 +78,11 @@ func Test_Client_Transmit(t *testing.T) { c.conn = conn c.rawClient = wsrpcClient require.NoError(t, c.StartOnce("Mock WSRPC Client", func() error { return nil })) - for i := 1; i < MaxConsecutiveTransmitFailures; i++ { + for i := 1; i < MaxConsecutiveRequestFailures; i++ { _, err := c.Transmit(ctx, req) require.EqualError(t, err, "context deadline exceeded") } - assert.Equal(t, 4, calls) + assert.Equal(t, MaxConsecutiveRequestFailures-1, calls) select { case <-c.chResetTransport: t.Fatal("unexpected send on chResetTransport") @@ -81,7 +90,7 @@ func Test_Client_Transmit(t *testing.T) { } _, err := c.Transmit(ctx, req) require.EqualError(t, err, "context deadline exceeded") - assert.Equal(t, 5, calls) + assert.Equal(t, MaxConsecutiveRequestFailures, calls) select { case <-c.chResetTransport: default: @@ -93,14 +102,14 @@ func Test_Client_Transmit(t *testing.T) { // working transmit to reset counter _, err = c.Transmit(ctx, req) require.NoError(t, err) - assert.Equal(t, 6, calls) + assert.Equal(t, MaxConsecutiveRequestFailures+1, calls) assert.Equal(t, 0, int(c.consecutiveTimeoutCnt.Load())) }) t.Run("doesn't block in case channel is full", func(t *testing.T) { transmitErr = context.DeadlineExceeded c.chResetTransport = nil // simulate full channel - for i := 0; i < MaxConsecutiveTransmitFailures; i++ { + for i := 0; i < MaxConsecutiveRequestFailures; i++ { _, err := c.Transmit(ctx, req) require.EqualError(t, err, "context deadline exceeded") } @@ -111,105 +120,59 @@ func Test_Client_Transmit(t *testing.T) { func Test_Client_LatestReport(t *testing.T) { lggr := logger.TestLogger(t) ctx := testutils.Context(t) + cacheReads := 5 + + tests := []struct { + name string + ttl time.Duration + expectedCalls int + }{ + { + name: "with cache disabled", + ttl: 0, + expectedCalls: 5, + }, + { + name: "with cache enabled", + ttl: 1000 * time.Hour, //some large value that will never expire during a test + expectedCalls: 1, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := &pb.LatestReportRequest{} + + cacheSet := cache.NewCacheSet(lggr, cache.Config{LatestReportTTL: tt.ttl}) + + resp := &pb.LatestReportResponse{} + + var calls int + wsrpcClient := &mocks.MockWSRPCClient{ + LatestReportF: func(ctx context.Context, in *pb.LatestReportRequest) (*pb.LatestReportResponse, error) { + calls++ + assert.Equal(t, req, in) + return resp, nil + }, + } - t.Run("with nil cache", func(t *testing.T) { - req := &pb.LatestReportRequest{} - noopCacheSet := newNoopCacheSet() - resp := &pb.LatestReportResponse{} - - wsrpcClient := &mocks.MockWSRPCClient{ - LatestReportF: func(ctx context.Context, in *pb.LatestReportRequest) (*pb.LatestReportResponse, error) { - assert.Equal(t, req, in) - return resp, nil - }, - } - - conn := &mocks.MockConn{ - Ready: true, - } - c := newClient(lggr, csakey.KeyV2{}, nil, "", noopCacheSet) - c.conn = conn - c.rawClient = wsrpcClient - require.NoError(t, c.StartOnce("Mock WSRPC Client", func() error { return nil })) - - r, err := c.LatestReport(ctx, req) - - require.NoError(t, err) - assert.Equal(t, resp, r) - }) - - t.Run("with cache disabled", func(t *testing.T) { - req := &pb.LatestReportRequest{} - cacheSet := cache.NewCacheSet(lggr, cache.Config{LatestReportTTL: 0}) - resp := &pb.LatestReportResponse{} - - var calls int - wsrpcClient := &mocks.MockWSRPCClient{ - LatestReportF: func(ctx context.Context, in *pb.LatestReportRequest) (*pb.LatestReportResponse, error) { - calls++ - assert.Equal(t, req, in) - return resp, nil - }, - } - - conn := &mocks.MockConn{ - Ready: true, - } - c := newClient(lggr, csakey.KeyV2{}, nil, "", cacheSet) - c.conn = conn - c.rawClient = wsrpcClient - - // simulate start without dialling - require.NoError(t, c.StartOnce("Mock WSRPC Client", func() error { return nil })) - var err error - require.NoError(t, cacheSet.Start(ctx)) - c.cache, err = cacheSet.Get(ctx, c) - require.NoError(t, err) - - for i := 0; i < 5; i++ { - r, err := c.LatestReport(ctx, req) - - require.NoError(t, err) - assert.Equal(t, resp, r) - } - assert.Equal(t, 5, calls, "expected 5 calls to LatestReport but it was called %d times", calls) - }) - - t.Run("with caching", func(t *testing.T) { - req := &pb.LatestReportRequest{} - const neverExpireTTL = 1000 * time.Hour // some massive value that will never expire during a test - cacheSet := cache.NewCacheSet(lggr, cache.Config{LatestReportTTL: neverExpireTTL}) - resp := &pb.LatestReportResponse{} - - var calls int - wsrpcClient := &mocks.MockWSRPCClient{ - LatestReportF: func(ctx context.Context, in *pb.LatestReportRequest) (*pb.LatestReportResponse, error) { - calls++ - assert.Equal(t, req, in) - return resp, nil - }, - } - - conn := &mocks.MockConn{ - Ready: true, - } - c := newClient(lggr, csakey.KeyV2{}, nil, "", cacheSet) - c.conn = conn - c.rawClient = wsrpcClient + conn := &mocks.MockConn{ + Ready: true, + } + c := newClient(lggr, csakey.KeyV2{}, nil, "", cacheSet) + c.conn = conn + c.rawClient = wsrpcClient - // simulate start without dialling - require.NoError(t, c.StartOnce("Mock WSRPC Client", func() error { return nil })) - var err error - require.NoError(t, cacheSet.Start(ctx)) - c.cache, err = cacheSet.Get(ctx, c) - require.NoError(t, err) + servicetest.Run(t, cacheSet) + simulateStart(ctx, t, c) - for i := 0; i < 5; i++ { - r, err := c.LatestReport(ctx, req) + for i := 0; i < cacheReads; i++ { + r, err := c.LatestReport(ctx, req) - require.NoError(t, err) - assert.Equal(t, resp, r) - } - assert.Equal(t, 1, calls, "expected only 1 call to LatestReport but it was called %d times", calls) - }) + require.NoError(t, err) + assert.Equal(t, resp, r) + } + assert.Equal(t, tt.expectedCalls, calls, "expected %d calls to LatestReport but it was called %d times", tt.expectedCalls, calls) + }) + } } diff --git a/core/services/relay/evm/mercury/wsrpc/metrics.go b/core/services/relay/evm/mercury/wsrpc/metrics.go index f2000674f7f..8c12184cd85 100644 --- a/core/services/relay/evm/mercury/wsrpc/metrics.go +++ b/core/services/relay/evm/mercury/wsrpc/metrics.go @@ -28,7 +28,7 @@ var ( Namespace: "mercury", Name: "wsrpc_request_latency", Help: "Latency of requests made to the Mercury WSRPC server", - Buckets: []float64{10, 30, 100, 300, 1000, 3000, 10000}, + Buckets: []float64{10, 30, 100, 200, 250, 300, 350, 400, 500, 750, 1000, 3000, 10000}, }) ) diff --git a/core/services/relay/evm/mercury/wsrpc/pool.go b/core/services/relay/evm/mercury/wsrpc/pool.go index 76f9bc808b9..dd85381469b 100644 --- a/core/services/relay/evm/mercury/wsrpc/pool.go +++ b/core/services/relay/evm/mercury/wsrpc/pool.go @@ -6,6 +6,7 @@ import ( "sync" "github.com/smartcontractkit/wsrpc/credentials" + "golang.org/x/exp/maps" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services" @@ -224,7 +225,7 @@ func (p *pool) Ready() error { } func (p *pool) HealthReport() map[string]error { - return map[string]error{ - p.Name(): p.Ready(), - } + hp := map[string]error{p.Name(): p.Ready()} + maps.Copy(hp, p.cacheSet.HealthReport()) + return hp } diff --git a/core/services/relay/evm/mercury/wsrpc/pool_test.go b/core/services/relay/evm/mercury/wsrpc/pool_test.go index 3d418d39d87..bb5ceec0bb6 100644 --- a/core/services/relay/evm/mercury/wsrpc/pool_test.go +++ b/core/services/relay/evm/mercury/wsrpc/pool_test.go @@ -9,12 +9,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var _ Client = &mockClient{} diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go index 90253808171..d9858ac64c3 100644 --- a/core/services/relay/evm/mercury_provider.go +++ b/core/services/relay/evm/mercury_provider.go @@ -6,48 +6,55 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - relaymercury "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury" - relaymercuryv1 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v1" - relaymercuryv2 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v2" - relaymercuryv3 "github.com/smartcontractkit/chainlink-common/pkg/reportingplugins/mercury/v3" "github.com/smartcontractkit/chainlink-common/pkg/services" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" + mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" + v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" + v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" + v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" + "github.com/smartcontractkit/chainlink-data-streams/mercury" + + httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" + evmmercury "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" ) var _ commontypes.MercuryProvider = (*mercuryProvider)(nil) type mercuryProvider struct { - configWatcher *configWatcher - transmitter mercury.Transmitter - reportCodecV1 relaymercuryv1.ReportCodec - reportCodecV2 relaymercuryv2.ReportCodec - reportCodecV3 relaymercuryv3.ReportCodec - chainReader relaymercury.ChainReader - logger logger.Logger - - ms services.MultiStart + configWatcher *configWatcher + chainReader commontypes.ChainReader + codec commontypes.Codec + transmitter evmmercury.Transmitter + reportCodecV1 v1.ReportCodec + reportCodecV2 v2.ReportCodec + reportCodecV3 v3.ReportCodec + mercuryChainReader mercurytypes.ChainReader + logger logger.Logger + ms services.MultiStart } func NewMercuryProvider( configWatcher *configWatcher, - transmitter mercury.Transmitter, - reportCodecV1 relaymercuryv1.ReportCodec, - reportCodecV2 relaymercuryv2.ReportCodec, - reportCodecV3 relaymercuryv3.ReportCodec, - chainReader relaymercury.ChainReader, + chainReader commontypes.ChainReader, + codec commontypes.Codec, + mercuryChainReader mercurytypes.ChainReader, + transmitter evmmercury.Transmitter, + reportCodecV1 v1.ReportCodec, + reportCodecV2 v2.ReportCodec, + reportCodecV3 v3.ReportCodec, lggr logger.Logger, ) *mercuryProvider { return &mercuryProvider{ configWatcher, + chainReader, + codec, transmitter, reportCodecV1, reportCodecV2, reportCodecV3, - chainReader, + mercuryChainReader, lggr, services.MultiStart{}, } @@ -76,6 +83,14 @@ func (p *mercuryProvider) HealthReport() map[string]error { return report } +func (p *mercuryProvider) MercuryChainReader() mercurytypes.ChainReader { + return p.mercuryChainReader +} + +func (p *mercuryProvider) Codec() commontypes.Codec { + return p.codec +} + func (p *mercuryProvider) ContractConfigTracker() ocrtypes.ContractConfigTracker { return p.configWatcher.ContractConfigTracker() } @@ -84,19 +99,19 @@ func (p *mercuryProvider) OffchainConfigDigester() ocrtypes.OffchainConfigDigest return p.configWatcher.OffchainConfigDigester() } -func (p *mercuryProvider) OnchainConfigCodec() relaymercury.OnchainConfigCodec { - return relaymercury.StandardOnchainConfigCodec{} +func (p *mercuryProvider) OnchainConfigCodec() mercurytypes.OnchainConfigCodec { + return mercury.StandardOnchainConfigCodec{} } -func (p *mercuryProvider) ReportCodecV1() relaymercuryv1.ReportCodec { +func (p *mercuryProvider) ReportCodecV1() v1.ReportCodec { return p.reportCodecV1 } -func (p *mercuryProvider) ReportCodecV2() relaymercuryv2.ReportCodec { +func (p *mercuryProvider) ReportCodecV2() v2.ReportCodec { return p.reportCodecV2 } -func (p *mercuryProvider) ReportCodecV3() relaymercuryv3.ReportCodec { +func (p *mercuryProvider) ReportCodecV3() v3.ReportCodec { return p.reportCodecV3 } @@ -104,35 +119,39 @@ func (p *mercuryProvider) ContractTransmitter() ocrtypes.ContractTransmitter { return p.transmitter } -func (p *mercuryProvider) MercuryServerFetcher() relaymercury.MercuryServerFetcher { +func (p *mercuryProvider) MercuryServerFetcher() mercurytypes.ServerFetcher { return p.transmitter } -func (p *mercuryProvider) ChainReader() relaymercury.ChainReader { +func (p *mercuryProvider) ChainReader() commontypes.ChainReader { return p.chainReader } -var _ relaymercury.ChainReader = (*chainReader)(nil) +var _ mercurytypes.ChainReader = (*mercuryChainReader)(nil) -type chainReader struct { +type mercuryChainReader struct { tracker httypes.HeadTracker } -func NewChainReader(h httypes.HeadTracker) relaymercury.ChainReader { - return &chainReader{ +func NewChainReader(h httypes.HeadTracker) mercurytypes.ChainReader { + return &mercuryChainReader{h} +} + +func NewMercuryChainReader(h httypes.HeadTracker) mercurytypes.ChainReader { + return &mercuryChainReader{ tracker: h, } } -func (r *chainReader) LatestHeads(ctx context.Context, k int) ([]relaymercury.Head, error) { +func (r *mercuryChainReader) LatestHeads(ctx context.Context, k int) ([]mercurytypes.Head, error) { evmBlocks := r.tracker.LatestChain().AsSlice(k) if len(evmBlocks) == 0 { return nil, nil } - blocks := make([]relaymercury.Head, len(evmBlocks)) + blocks := make([]mercurytypes.Head, len(evmBlocks)) for x := 0; x < len(evmBlocks); x++ { - blocks[x] = relaymercury.Head{ + blocks[x] = mercurytypes.Head{ Number: uint64(evmBlocks[x].BlockNumber()), Hash: evmBlocks[x].Hash.Bytes(), Timestamp: uint64(evmBlocks[x].Timestamp.Unix()), diff --git a/core/services/relay/evm/method_binding.go b/core/services/relay/evm/method_binding.go new file mode 100644 index 00000000000..c5e10cce1c1 --- /dev/null +++ b/core/services/relay/evm/method_binding.go @@ -0,0 +1,66 @@ +package evm + +import ( + "context" + "fmt" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" +) + +type methodBinding struct { + address common.Address + contractName string + method string + client evmclient.Client + codec commontypes.Codec + bound bool +} + +var _ readBinding = &methodBinding{} + +func (m *methodBinding) SetCodec(codec commontypes.RemoteCodec) { + m.codec = codec +} + +func (m *methodBinding) Register() error { + return nil +} + +func (m *methodBinding) Unregister() error { + return nil +} + +func (m *methodBinding) GetLatestValue(ctx context.Context, params, returnValue any) error { + if !m.bound { + return fmt.Errorf("%w: method not bound", commontypes.ErrInvalidType) + } + + data, err := m.codec.Encode(ctx, params, wrapItemType(m.contractName, m.method, true)) + if err != nil { + return err + } + + callMsg := ethereum.CallMsg{ + To: &m.address, + From: m.address, + Data: data, + } + + bytes, err := m.client.CallContract(ctx, callMsg, nil) + if err != nil { + return fmt.Errorf("%w: %w", commontypes.ErrInternal, err) + } + + return m.codec.Decode(ctx, bytes, returnValue, wrapItemType(m.contractName, m.method, false)) +} + +func (m *methodBinding) Bind(binding commontypes.BoundContract) error { + m.address = common.HexToAddress(binding.Address) + m.bound = true + return nil +} diff --git a/core/services/relay/evm/mocks/loop_relay_adapter.go b/core/services/relay/evm/mocks/loop_relay_adapter.go index 0376c9f27a4..5b927f1b8ac 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -22,6 +22,10 @@ type LoopRelayAdapter struct { func (_m *LoopRelayAdapter) Chain() legacyevm.Chain { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Chain") + } + var r0 legacyevm.Chain if rf, ok := ret.Get(0).(func() legacyevm.Chain); ok { r0 = rf() @@ -38,6 +42,10 @@ func (_m *LoopRelayAdapter) Chain() legacyevm.Chain { func (_m *LoopRelayAdapter) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -52,6 +60,10 @@ func (_m *LoopRelayAdapter) Close() error { func (_m *LoopRelayAdapter) GetChainStatus(ctx context.Context) (types.ChainStatus, error) { ret := _m.Called(ctx) + if len(ret) == 0 { + panic("no return value specified for GetChainStatus") + } + var r0 types.ChainStatus var r1 error if rf, ok := ret.Get(0).(func(context.Context) (types.ChainStatus, error)); ok { @@ -76,6 +88,10 @@ func (_m *LoopRelayAdapter) GetChainStatus(ctx context.Context) (types.ChainStat func (_m *LoopRelayAdapter) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -92,6 +108,10 @@ func (_m *LoopRelayAdapter) HealthReport() map[string]error { func (_m *LoopRelayAdapter) ListNodeStatuses(ctx context.Context, pageSize int32, pageToken string) ([]types.NodeStatus, string, int, error) { ret := _m.Called(ctx, pageSize, pageToken) + if len(ret) == 0 { + panic("no return value specified for ListNodeStatuses") + } + var r0 []types.NodeStatus var r1 string var r2 int @@ -132,6 +152,10 @@ func (_m *LoopRelayAdapter) ListNodeStatuses(ctx context.Context, pageSize int32 func (_m *LoopRelayAdapter) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -146,6 +170,10 @@ func (_m *LoopRelayAdapter) Name() string { func (_m *LoopRelayAdapter) NewConfigProvider(_a0 context.Context, _a1 types.RelayArgs) (types.ConfigProvider, error) { ret := _m.Called(_a0, _a1) + if len(ret) == 0 { + panic("no return value specified for NewConfigProvider") + } + var r0 types.ConfigProvider var r1 error if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs) (types.ConfigProvider, error)); ok { @@ -172,6 +200,10 @@ func (_m *LoopRelayAdapter) NewConfigProvider(_a0 context.Context, _a1 types.Rel func (_m *LoopRelayAdapter) NewPluginProvider(_a0 context.Context, _a1 types.RelayArgs, _a2 types.PluginArgs) (types.PluginProvider, error) { ret := _m.Called(_a0, _a1, _a2) + if len(ret) == 0 { + panic("no return value specified for NewPluginProvider") + } + var r0 types.PluginProvider var r1 error if rf, ok := ret.Get(0).(func(context.Context, types.RelayArgs, types.PluginArgs) (types.PluginProvider, error)); ok { @@ -198,6 +230,10 @@ func (_m *LoopRelayAdapter) NewPluginProvider(_a0 context.Context, _a1 types.Rel func (_m *LoopRelayAdapter) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -212,6 +248,10 @@ func (_m *LoopRelayAdapter) Ready() error { func (_m *LoopRelayAdapter) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) @@ -226,6 +266,10 @@ func (_m *LoopRelayAdapter) Start(_a0 context.Context) error { func (_m *LoopRelayAdapter) Transact(ctx context.Context, from string, to string, amount *big.Int, balanceCheck bool) error { ret := _m.Called(ctx, from, to, amount, balanceCheck) + if len(ret) == 0 { + panic("no return value specified for Transact") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, string, string, *big.Int, bool) error); ok { r0 = rf(ctx, from, to, amount, balanceCheck) diff --git a/core/services/relay/evm/mocks/request_round_db.go b/core/services/relay/evm/mocks/request_round_db.go index 1727e8cc47d..eb27e8bd526 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type RequestRoundDB struct { func (_m *RequestRoundDB) LoadLatestRoundRequested() (ocr2aggregator.OCR2AggregatorRoundRequested, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LoadLatestRoundRequested") + } + var r0 ocr2aggregator.OCR2AggregatorRoundRequested var r1 error if rf, ok := ret.Get(0).(func() (ocr2aggregator.OCR2AggregatorRoundRequested, error)); ok { @@ -41,6 +45,10 @@ func (_m *RequestRoundDB) LoadLatestRoundRequested() (ocr2aggregator.OCR2Aggrega func (_m *RequestRoundDB) SaveLatestRoundRequested(tx pg.Queryer, rr ocr2aggregator.OCR2AggregatorRoundRequested) error { ret := _m.Called(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, ocr2aggregator.OCR2AggregatorRoundRequested) error); ok { r0 = rf(tx, rr) diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index 3b3bfeb652d..fd1fdb70480 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -6,6 +6,17 @@ import ( "fmt" "strings" + iregistry21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_keeper_registry_master_wrapper_2_1" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" + evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/upkeepstate" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + + "github.com/smartcontractkit/chainlink-common/pkg/types/automation" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/jmoiron/sqlx" @@ -22,14 +33,14 @@ import ( "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/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) var ( - _ OCR2KeeperRelayer = (*ocr2keeperRelayer)(nil) - _ OCR2KeeperProvider = (*ocr2keeperProvider)(nil) + _ OCR2KeeperRelayer = (*ocr2keeperRelayer)(nil) + _ OCR2KeeperProvider = (*ocr2keeperProvider)(nil) + ErrInitializationFailure = fmt.Errorf("failed to initialize registry") ) // OCR2KeeperProviderOpts is the custom options to create a keeper provider @@ -42,6 +53,15 @@ type OCR2KeeperProviderOpts struct { // OCR2KeeperProvider provides all components needed for a OCR2Keeper plugin. type OCR2KeeperProvider interface { commontypes.Plugin + Registry() automation.Registry + Encoder() automation.Encoder + TransmitEventProvider() automation.EventProvider + BlockSubscriber() automation.BlockSubscriber + PayloadBuilder() automation.PayloadBuilder + UpkeepStateStore() automation.UpkeepStateStore + LogEventProvider() automation.LogEventProvider + LogRecoverer() automation.LogRecoverer + UpkeepProvider() automation.ConditionalUpkeepProvider } // OCR2KeeperRelayer contains the relayer and instantiating functions for OCR2Keeper providers. @@ -51,21 +71,21 @@ type OCR2KeeperRelayer interface { // ocr2keeperRelayer is the relayer with added DKG and OCR2Keeper provider functions. type ocr2keeperRelayer struct { - db *sqlx.DB - chain legacyevm.Chain - pr pipeline.Runner - spec job.Job - lggr logger.Logger + db *sqlx.DB + chain legacyevm.Chain + lggr logger.Logger + ethKeystore keystore.Eth + dbCfg pg.QConfig } // NewOCR2KeeperRelayer is the constructor of ocr2keeperRelayer -func NewOCR2KeeperRelayer(db *sqlx.DB, chain legacyevm.Chain, pr pipeline.Runner, spec job.Job, lggr logger.Logger) OCR2KeeperRelayer { +func NewOCR2KeeperRelayer(db *sqlx.DB, chain legacyevm.Chain, lggr logger.Logger, ethKeystore keystore.Eth, dbCfg pg.QConfig) OCR2KeeperRelayer { return &ocr2keeperRelayer{ - db: db, - chain: chain, - pr: pr, - spec: spec, - lggr: lggr, + db: db, + chain: chain, + lggr: lggr, + ethKeystore: ethKeystore, + dbCfg: dbCfg, } } @@ -76,15 +96,58 @@ func (r *ocr2keeperRelayer) NewOCR2KeeperProvider(rargs commontypes.RelayArgs, p } gasLimit := cfgWatcher.chain.Config().EVM().OCR2().Automation().GasLimit() - contractTransmitter, err := newPipelineContractTransmitter(r.lggr, rargs, pargs.TransmitterID, &gasLimit, cfgWatcher, r.spec, r.pr) + contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, cfgWatcher, configTransmitterOpts{pluginGasLimit: &gasLimit}) + if err != nil { + return nil, err + } + + client := r.chain + + services := new(ocr2keeperProvider) + services.configWatcher = cfgWatcher + services.contractTransmitter = contractTransmitter + + addr := ethkey.MustEIP55Address(rargs.ContractID).Address() + + registryContract, err := iregistry21.NewIKeeperRegistryMaster(addr, client.Client()) + if err != nil { + return nil, fmt.Errorf("%w: failed to create caller for address and backend", ErrInitializationFailure) + } + // lookback blocks for transmit event is hard coded and should provide ample time for logs + // to be detected in most cases + var transmitLookbackBlocks int64 = 250 + transmitEventProvider, err := transmit.NewTransmitEventProvider(r.lggr, client.LogPoller(), addr, client.Client(), transmitLookbackBlocks) if err != nil { return nil, err } - return &ocr2keeperProvider{ - configWatcher: cfgWatcher, - contractTransmitter: contractTransmitter, - }, nil + services.transmitEventProvider = transmitEventProvider + + packer := encoding.NewAbiPacker() + services.encoder = encoding.NewReportEncoder(packer) + + finalityDepth := client.Config().EVM().FinalityDepth() + + orm := upkeepstate.NewORM(client.ID(), r.db, r.lggr, r.dbCfg) + scanner := upkeepstate.NewPerformedEventsScanner(r.lggr, client.LogPoller(), addr, finalityDepth) + services.upkeepStateStore = upkeepstate.NewUpkeepStateStore(orm, r.lggr, scanner) + + logProvider, logRecoverer := logprovider.New(r.lggr, client.LogPoller(), client.Client(), services.upkeepStateStore, finalityDepth) + services.logEventProvider = logProvider + services.logRecoverer = logRecoverer + blockSubscriber := evm.NewBlockSubscriber(client.HeadBroadcaster(), client.LogPoller(), finalityDepth, r.lggr) + services.blockSubscriber = blockSubscriber + + al := evm.NewActiveUpkeepList() + services.payloadBuilder = evm.NewPayloadBuilder(al, logRecoverer, r.lggr) + + services.registry = evm.NewEvmRegistry(r.lggr, addr, client, + registryContract, rargs.MercuryCredentials, al, logProvider, + packer, blockSubscriber, finalityDepth) + + services.conditionalUpkeepProvider = evm.NewUpkeepProvider(al, blockSubscriber, client.LogPoller()) + + return services, nil } type ocr3keeperProviderContractTransmitter struct { @@ -123,13 +186,30 @@ func (t *ocr3keeperProviderContractTransmitter) FromAccount() (ocrtypes.Account, type ocr2keeperProvider struct { *configWatcher - contractTransmitter ContractTransmitter + contractTransmitter ContractTransmitter + registry automation.Registry + encoder automation.Encoder + transmitEventProvider automation.EventProvider + blockSubscriber automation.BlockSubscriber + payloadBuilder automation.PayloadBuilder + upkeepStateStore automation.UpkeepStateStore + logEventProvider automation.LogEventProvider + logRecoverer automation.LogRecoverer + conditionalUpkeepProvider automation.ConditionalUpkeepProvider } func (c *ocr2keeperProvider) ContractTransmitter() ocrtypes.ContractTransmitter { return c.contractTransmitter } +func (c *ocr2keeperProvider) ChainReader() commontypes.ChainReader { + return nil +} + +func (c *ocr2keeperProvider) Codec() commontypes.Codec { + return nil +} + func newOCR2KeeperConfigProvider(lggr logger.Logger, chain legacyevm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { var relayConfig types.RelayConfig err := json.Unmarshal(rargs.RelayConfig, &relayConfig) @@ -174,3 +254,39 @@ func newOCR2KeeperConfigProvider(lggr logger.Logger, chain legacyevm.Chain, rarg rargs.New, ), nil } + +func (c *ocr2keeperProvider) Registry() automation.Registry { + return c.registry +} + +func (c *ocr2keeperProvider) Encoder() automation.Encoder { + return c.encoder +} + +func (c *ocr2keeperProvider) TransmitEventProvider() automation.EventProvider { + return c.transmitEventProvider +} + +func (c *ocr2keeperProvider) BlockSubscriber() automation.BlockSubscriber { + return c.blockSubscriber +} + +func (c *ocr2keeperProvider) PayloadBuilder() automation.PayloadBuilder { + return c.payloadBuilder +} + +func (c *ocr2keeperProvider) UpkeepStateStore() automation.UpkeepStateStore { + return c.upkeepStateStore +} + +func (c *ocr2keeperProvider) LogEventProvider() automation.LogEventProvider { + return c.logEventProvider +} + +func (c *ocr2keeperProvider) LogRecoverer() automation.LogRecoverer { + return c.logRecoverer +} + +func (c *ocr2keeperProvider) UpkeepProvider() automation.ConditionalUpkeepProvider { + return c.conditionalUpkeepProvider +} diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go index b7a2220588b..d300c71fbef 100644 --- a/core/services/relay/evm/ocr2vrf.go +++ b/core/services/relay/evm/ocr2vrf.go @@ -67,7 +67,7 @@ func (r *ocr2vrfRelayer) NewDKGProvider(rargs commontypes.RelayArgs, pargs commo if err != nil { return nil, err } - contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, configWatcher, r.ethKeystore) + contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}) if err != nil { return nil, err } @@ -90,7 +90,7 @@ func (r *ocr2vrfRelayer) NewOCR2VRFProvider(rargs commontypes.RelayArgs, pargs c if err != nil { return nil, err } - contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, configWatcher, r.ethKeystore) + contractTransmitter, err := newContractTransmitter(r.lggr, rargs, pargs.TransmitterID, r.ethKeystore, configWatcher, configTransmitterOpts{}) if err != nil { return nil, err } @@ -110,6 +110,14 @@ func (c *dkgProvider) ContractTransmitter() ocrtypes.ContractTransmitter { return c.contractTransmitter } +func (c *dkgProvider) ChainReader() commontypes.ChainReader { + return nil +} + +func (c *dkgProvider) Codec() commontypes.Codec { + return nil +} + type ocr2vrfProvider struct { *configWatcher contractTransmitter ContractTransmitter @@ -119,6 +127,14 @@ func (c *ocr2vrfProvider) ContractTransmitter() ocrtypes.ContractTransmitter { return c.contractTransmitter } +func (c *ocr2vrfProvider) ChainReader() commontypes.ChainReader { + return nil +} + +func (c *ocr2vrfProvider) Codec() commontypes.Codec { + return nil +} + func newOCR2VRFConfigProvider(lggr logger.Logger, chain legacyevm.Chain, rargs commontypes.RelayArgs) (*configWatcher, error) { var relayConfig types.RelayConfig err := json.Unmarshal(rargs.RelayConfig, &relayConfig) diff --git a/core/services/relay/evm/parsed_types.go b/core/services/relay/evm/parsed_types.go new file mode 100644 index 00000000000..168057e998d --- /dev/null +++ b/core/services/relay/evm/parsed_types.go @@ -0,0 +1,50 @@ +package evm + +import ( + "fmt" + "reflect" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +type parsedTypes struct { + encoderDefs map[string]types.CodecEntry + decoderDefs map[string]types.CodecEntry +} + +func (parsed *parsedTypes) toCodec() (commontypes.RemoteCodec, error) { + modByTypeName := map[string]codec.Modifier{} + if err := addEntries(parsed.encoderDefs, modByTypeName); err != nil { + return nil, err + } + if err := addEntries(parsed.decoderDefs, modByTypeName); err != nil { + return nil, err + } + + mod, err := codec.NewByItemTypeModifier(modByTypeName) + if err != nil { + return nil, err + } + underlying := &evmCodec{ + encoder: &encoder{Definitions: parsed.encoderDefs}, + decoder: &decoder{Definitions: parsed.decoderDefs}, + parsedTypes: parsed, + } + return codec.NewModifierCodec(underlying, mod, evmDecoderHooks...) +} + +// addEntries extracts the mods from codecEntry and adds them to modByTypeName use with codec.NewByItemTypeModifier +// Since each input/output can have its own modifications, we need to keep track of them by type name +func addEntries(defs map[string]types.CodecEntry, modByTypeName map[string]codec.Modifier) error { + for k, def := range defs { + modByTypeName[k] = def.Modifier() + _, err := def.Modifier().RetypeToOffChain(reflect.PointerTo(def.CheckedType()), k) + if err != nil { + return fmt.Errorf("%w: cannot retype %v: %w", commontypes.ErrInvalidConfig, k, err) + } + } + return nil +} diff --git a/core/services/relay/evm/relayer_extender_test.go b/core/services/relay/evm/relayer_extender_test.go index 3f4a3749ac8..af15461aee9 100644 --- a/core/services/relay/evm/relayer_extender_test.go +++ b/core/services/relay/evm/relayer_extender_test.go @@ -10,6 +10,7 @@ import ( evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + 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" @@ -17,7 +18,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestChainRelayExtenders(t *testing.T) { @@ -28,7 +28,7 @@ func TestChainRelayExtenders(t *testing.T) { one := uint32(1) c.EVM[0].MinIncomingConfirmations = &one t := true - c.EVM = append(c.EVM, &toml.EVMConfig{ChainID: utils.NewBig(newId), Enabled: &t, Chain: toml.Defaults(nil)}) + 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()) diff --git a/core/services/relay/evm/request_round_db.go b/core/services/relay/evm/request_round_db.go index 331d663918a..b3a5b01bc2c 100644 --- a/core/services/relay/evm/request_round_db.go +++ b/core/services/relay/evm/request_round_db.go @@ -61,6 +61,7 @@ LIMIT 1 if err != nil { return rr, errors.Wrap(err, "LoadLatestRoundRequested failed to query rows") } + defer rows.Close() for rows.Next() { var configDigest []byte diff --git a/core/services/relay/evm/types/abi_types.go b/core/services/relay/evm/types/abi_types.go new file mode 100644 index 00000000000..34b12d885b4 --- /dev/null +++ b/core/services/relay/evm/types/abi_types.go @@ -0,0 +1,66 @@ +package types + +import ( + "reflect" + + "github.com/ethereum/go-ethereum/common" +) + +//go:generate go run ./gen/main.go + +var typeMap = map[string]*ABIEncodingType{ + "bool": { + native: reflect.TypeOf(true), + checked: reflect.TypeOf(true), + }, + "int8": { + native: reflect.TypeOf(int8(0)), + checked: reflect.TypeOf(int8(0)), + }, + "int16": { + native: reflect.TypeOf(int16(0)), + checked: reflect.TypeOf(int16(0)), + }, + "int32": { + native: reflect.TypeOf(int32(0)), + checked: reflect.TypeOf(int32(0)), + }, + "int64": { + native: reflect.TypeOf(int64(0)), + checked: reflect.TypeOf(int64(0)), + }, + "uint8": { + native: reflect.TypeOf(uint8(0)), + checked: reflect.TypeOf(uint8(0)), + }, + "uint16": { + native: reflect.TypeOf(uint16(0)), + checked: reflect.TypeOf(uint16(0)), + }, + "uint32": { + native: reflect.TypeOf(uint32(0)), + checked: reflect.TypeOf(uint32(0)), + }, + "uint64": { + native: reflect.TypeOf(uint64(0)), + checked: reflect.TypeOf(uint64(0)), + }, + "string": { + native: reflect.TypeOf(""), + checked: reflect.TypeOf(""), + }, + "address": { + native: reflect.TypeOf(common.Address{}), + checked: reflect.TypeOf(common.Address{}), + }, +} + +type ABIEncodingType struct { + native reflect.Type + checked reflect.Type +} + +func GetAbiEncodingType(name string) (*ABIEncodingType, bool) { + abiType, ok := typeMap[name] + return abiType, ok +} diff --git a/core/services/relay/evm/types/byte_types_gen.go b/core/services/relay/evm/types/byte_types_gen.go new file mode 100644 index 00000000000..cf8d15ccabc --- /dev/null +++ b/core/services/relay/evm/types/byte_types_gen.go @@ -0,0 +1,300 @@ +package types + +import "reflect" + +type bytes1 [1]byte + +func init() { + typeMap["bytes1"] = &ABIEncodingType{ + native: reflect.TypeOf([1]byte{}), + checked: reflect.TypeOf(bytes1{}), + } +} + +type bytes2 [2]byte + +func init() { + typeMap["bytes2"] = &ABIEncodingType{ + native: reflect.TypeOf([2]byte{}), + checked: reflect.TypeOf(bytes2{}), + } +} + +type bytes3 [3]byte + +func init() { + typeMap["bytes3"] = &ABIEncodingType{ + native: reflect.TypeOf([3]byte{}), + checked: reflect.TypeOf(bytes3{}), + } +} + +type bytes4 [4]byte + +func init() { + typeMap["bytes4"] = &ABIEncodingType{ + native: reflect.TypeOf([4]byte{}), + checked: reflect.TypeOf(bytes4{}), + } +} + +type bytes5 [5]byte + +func init() { + typeMap["bytes5"] = &ABIEncodingType{ + native: reflect.TypeOf([5]byte{}), + checked: reflect.TypeOf(bytes5{}), + } +} + +type bytes6 [6]byte + +func init() { + typeMap["bytes6"] = &ABIEncodingType{ + native: reflect.TypeOf([6]byte{}), + checked: reflect.TypeOf(bytes6{}), + } +} + +type bytes7 [7]byte + +func init() { + typeMap["bytes7"] = &ABIEncodingType{ + native: reflect.TypeOf([7]byte{}), + checked: reflect.TypeOf(bytes7{}), + } +} + +type bytes8 [8]byte + +func init() { + typeMap["bytes8"] = &ABIEncodingType{ + native: reflect.TypeOf([8]byte{}), + checked: reflect.TypeOf(bytes8{}), + } +} + +type bytes9 [9]byte + +func init() { + typeMap["bytes9"] = &ABIEncodingType{ + native: reflect.TypeOf([9]byte{}), + checked: reflect.TypeOf(bytes9{}), + } +} + +type bytes10 [10]byte + +func init() { + typeMap["bytes10"] = &ABIEncodingType{ + native: reflect.TypeOf([10]byte{}), + checked: reflect.TypeOf(bytes10{}), + } +} + +type bytes11 [11]byte + +func init() { + typeMap["bytes11"] = &ABIEncodingType{ + native: reflect.TypeOf([11]byte{}), + checked: reflect.TypeOf(bytes11{}), + } +} + +type bytes12 [12]byte + +func init() { + typeMap["bytes12"] = &ABIEncodingType{ + native: reflect.TypeOf([12]byte{}), + checked: reflect.TypeOf(bytes12{}), + } +} + +type bytes13 [13]byte + +func init() { + typeMap["bytes13"] = &ABIEncodingType{ + native: reflect.TypeOf([13]byte{}), + checked: reflect.TypeOf(bytes13{}), + } +} + +type bytes14 [14]byte + +func init() { + typeMap["bytes14"] = &ABIEncodingType{ + native: reflect.TypeOf([14]byte{}), + checked: reflect.TypeOf(bytes14{}), + } +} + +type bytes15 [15]byte + +func init() { + typeMap["bytes15"] = &ABIEncodingType{ + native: reflect.TypeOf([15]byte{}), + checked: reflect.TypeOf(bytes15{}), + } +} + +type bytes16 [16]byte + +func init() { + typeMap["bytes16"] = &ABIEncodingType{ + native: reflect.TypeOf([16]byte{}), + checked: reflect.TypeOf(bytes16{}), + } +} + +type bytes17 [17]byte + +func init() { + typeMap["bytes17"] = &ABIEncodingType{ + native: reflect.TypeOf([17]byte{}), + checked: reflect.TypeOf(bytes17{}), + } +} + +type bytes18 [18]byte + +func init() { + typeMap["bytes18"] = &ABIEncodingType{ + native: reflect.TypeOf([18]byte{}), + checked: reflect.TypeOf(bytes18{}), + } +} + +type bytes19 [19]byte + +func init() { + typeMap["bytes19"] = &ABIEncodingType{ + native: reflect.TypeOf([19]byte{}), + checked: reflect.TypeOf(bytes19{}), + } +} + +type bytes20 [20]byte + +func init() { + typeMap["bytes20"] = &ABIEncodingType{ + native: reflect.TypeOf([20]byte{}), + checked: reflect.TypeOf(bytes20{}), + } +} + +type bytes21 [21]byte + +func init() { + typeMap["bytes21"] = &ABIEncodingType{ + native: reflect.TypeOf([21]byte{}), + checked: reflect.TypeOf(bytes21{}), + } +} + +type bytes22 [22]byte + +func init() { + typeMap["bytes22"] = &ABIEncodingType{ + native: reflect.TypeOf([22]byte{}), + checked: reflect.TypeOf(bytes22{}), + } +} + +type bytes23 [23]byte + +func init() { + typeMap["bytes23"] = &ABIEncodingType{ + native: reflect.TypeOf([23]byte{}), + checked: reflect.TypeOf(bytes23{}), + } +} + +type bytes24 [24]byte + +func init() { + typeMap["bytes24"] = &ABIEncodingType{ + native: reflect.TypeOf([24]byte{}), + checked: reflect.TypeOf(bytes24{}), + } +} + +type bytes25 [25]byte + +func init() { + typeMap["bytes25"] = &ABIEncodingType{ + native: reflect.TypeOf([25]byte{}), + checked: reflect.TypeOf(bytes25{}), + } +} + +type bytes26 [26]byte + +func init() { + typeMap["bytes26"] = &ABIEncodingType{ + native: reflect.TypeOf([26]byte{}), + checked: reflect.TypeOf(bytes26{}), + } +} + +type bytes27 [27]byte + +func init() { + typeMap["bytes27"] = &ABIEncodingType{ + native: reflect.TypeOf([27]byte{}), + checked: reflect.TypeOf(bytes27{}), + } +} + +type bytes28 [28]byte + +func init() { + typeMap["bytes28"] = &ABIEncodingType{ + native: reflect.TypeOf([28]byte{}), + checked: reflect.TypeOf(bytes28{}), + } +} + +type bytes29 [29]byte + +func init() { + typeMap["bytes29"] = &ABIEncodingType{ + native: reflect.TypeOf([29]byte{}), + checked: reflect.TypeOf(bytes29{}), + } +} + +type bytes30 [30]byte + +func init() { + typeMap["bytes30"] = &ABIEncodingType{ + native: reflect.TypeOf([30]byte{}), + checked: reflect.TypeOf(bytes30{}), + } +} + +type bytes31 [31]byte + +func init() { + typeMap["bytes31"] = &ABIEncodingType{ + native: reflect.TypeOf([31]byte{}), + checked: reflect.TypeOf(bytes31{}), + } +} + +type bytes32 [32]byte + +func init() { + typeMap["bytes32"] = &ABIEncodingType{ + native: reflect.TypeOf([32]byte{}), + checked: reflect.TypeOf(bytes32{}), + } +} + +type bytes0 [0]byte + +func init() { + typeMap["bytes0"] = &ABIEncodingType{ + native: reflect.TypeOf([0]byte{}), + checked: reflect.TypeOf(bytes0{}), + } +} diff --git a/core/services/relay/evm/types/codec_entry.go b/core/services/relay/evm/types/codec_entry.go new file mode 100644 index 00000000000..b87f7ced721 --- /dev/null +++ b/core/services/relay/evm/types/codec_entry.go @@ -0,0 +1,256 @@ +package types + +import ( + "fmt" + "reflect" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +// MaxTopicFields is three because the EVM has a max of four topics, but the first topic is always the event signature. +const MaxTopicFields = 3 + +type CodecEntry interface { + Init() error + Args() abi.Arguments + EncodingPrefix() []byte + GetMaxSize(n int) (int, error) + Modifier() codec.Modifier + + // CheckedType provides a type that can be used to decode into with type-safety around sizes of integers etc. + CheckedType() reflect.Type + + // ToNative converts a pointer to checked value into a pointer of a type to use with the go-ethereum ABI encoder + // Note that modification of the returned value will modify the original checked value and vice versa. + ToNative(checked reflect.Value) (reflect.Value, error) + + // IsNativePointer returns if the type is a pointer to the native type + IsNativePointer(item reflect.Type) bool +} + +func NewCodecEntry(args abi.Arguments, encodingPrefix []byte, mod codec.Modifier) CodecEntry { + if mod == nil { + mod = codec.MultiModifier{} + } + return &codecEntry{args: args, encodingPrefix: encodingPrefix, mod: mod} +} + +type codecEntry struct { + args abi.Arguments + encodingPrefix []byte + checkedType reflect.Type + nativeType reflect.Type + mod codec.Modifier +} + +func (entry *codecEntry) CheckedType() reflect.Type { + return entry.checkedType +} + +func (entry *codecEntry) NativeType() reflect.Type { + return entry.nativeType +} + +func (entry *codecEntry) ToNative(checked reflect.Value) (reflect.Value, error) { + if checked.Type() != reflect.PointerTo(entry.checkedType) { + return reflect.Value{}, fmt.Errorf("%w: checked type %v does not match expected type %v", commontypes.ErrInvalidType, reflect.TypeOf(checked), entry.checkedType) + } + + return reflect.NewAt(entry.nativeType, checked.UnsafePointer()), nil +} + +func (entry *codecEntry) IsNativePointer(item reflect.Type) bool { + return item == reflect.PointerTo(entry.nativeType) +} + +func (entry *codecEntry) Modifier() codec.Modifier { + return entry.mod +} + +func (entry *codecEntry) Args() abi.Arguments { + tmp := make(abi.Arguments, len(entry.args)) + copy(tmp, entry.args) + return tmp +} + +func (entry *codecEntry) EncodingPrefix() []byte { + tmp := make([]byte, len(entry.encodingPrefix)) + copy(tmp, entry.encodingPrefix) + return tmp +} + +func (entry *codecEntry) Init() error { + if entry.checkedType != nil { + return nil + } + + args := unwrapArgs(entry.args) + argLen := len(args) + native := make([]reflect.StructField, argLen) + checked := make([]reflect.StructField, argLen) + + // Single returns that aren't named will return that type + // whereas named parameters will return a struct with the fields + // Eg: function foo() returns (int256) ... will return a *big.Int for the native type + // function foo() returns (int256 i) ... will return a struct { I *big.Int } for the native type + // function foo() returns (int256 i1, int256 i2) ... will return a struct { I1 *big.Int, I2 *big.Int } for the native type + if len(args) == 1 && args[0].Name == "" { + nativeArg, checkedArg, err := getNativeAndCheckedTypesForArg(&args[0]) + if err != nil { + return err + } + entry.nativeType = nativeArg + entry.checkedType = checkedArg + return nil + } + + numIndices := 0 + seenNames := map[string]bool{} + for i, arg := range args { + if arg.Indexed { + if numIndices == MaxTopicFields { + return fmt.Errorf("%w: too many indexed arguments", commontypes.ErrInvalidConfig) + } + numIndices++ + } + + tmp := arg + nativeArg, checkedArg, err := getNativeAndCheckedTypesForArg(&tmp) + if err != nil { + return err + } + if len(arg.Name) == 0 { + return fmt.Errorf("%w: empty field names are not supported for multiple returns", commontypes.ErrInvalidType) + } + + name := strings.ToUpper(arg.Name[:1]) + arg.Name[1:] + if seenNames[name] { + return fmt.Errorf("%w: duplicate field name %s, after ToCamelCase", commontypes.ErrInvalidConfig, name) + } + seenNames[name] = true + native[i] = reflect.StructField{Name: name, Type: nativeArg} + checked[i] = reflect.StructField{Name: name, Type: checkedArg} + } + + entry.nativeType = structOfPointers(native) + entry.checkedType = structOfPointers(checked) + return nil +} + +func (entry *codecEntry) GetMaxSize(n int) (int, error) { + return GetMaxSize(n, entry.args) +} + +func unwrapArgs(args abi.Arguments) abi.Arguments { + // Unwrap an unnamed tuple so that callers don't need to wrap it + // Eg: If you have struct Foo { ... } and return an unnamed Foo, you should be able ot decode to a go Foo{} directly + if len(args) != 1 || args[0].Name != "" { + return args + } + + elms := args[0].Type.TupleElems + if len(elms) != 0 { + names := args[0].Type.TupleRawNames + args = make(abi.Arguments, len(elms)) + for i, elm := range elms { + args[i] = abi.Argument{ + Name: names[i], + Type: *elm, + } + } + } + return args +} + +func getNativeAndCheckedTypesForArg(arg *abi.Argument) (reflect.Type, reflect.Type, error) { + tmp := arg.Type + if arg.Indexed { + switch arg.Type.T { + case abi.StringTy: + return reflect.TypeOf(common.Hash{}), reflect.TypeOf(common.Hash{}), nil + case abi.ArrayTy: + u8, _ := GetAbiEncodingType("uint8") + if arg.Type.Elem.GetType() == u8.native { + return reflect.TypeOf(common.Hash{}), reflect.TypeOf(common.Hash{}), nil + } + fallthrough + case abi.SliceTy, abi.TupleTy, abi.FixedBytesTy, abi.FixedPointTy, abi.FunctionTy: + // https://github.com/ethereum/go-ethereum/blob/release/1.12/accounts/abi/topics.go#L78 + return nil, nil, fmt.Errorf("%w: unsupported indexed type: %v", commontypes.ErrInvalidConfig, arg.Type) + default: + } + } + + return getNativeAndCheckedTypes(&tmp) +} + +func getNativeAndCheckedTypes(curType *abi.Type) (reflect.Type, reflect.Type, error) { + converter := func(t reflect.Type) reflect.Type { return t } + for curType.Elem != nil { + prior := converter + switch curType.GetType().Kind() { + case reflect.Slice: + converter = func(t reflect.Type) reflect.Type { + return prior(reflect.SliceOf(t)) + } + curType = curType.Elem + case reflect.Array: + tmp := curType + converter = func(t reflect.Type) reflect.Type { + return prior(reflect.ArrayOf(tmp.Size, t)) + } + curType = curType.Elem + default: + return nil, nil, fmt.Errorf( + "%w: cannot create type for kind %v", commontypes.ErrInvalidType, curType.GetType().Kind()) + } + } + base, ok := GetAbiEncodingType(curType.String()) + if ok { + return converter(base.native), converter(base.checked), nil + } + + return createTupleType(curType, converter) +} + +func createTupleType(curType *abi.Type, converter func(reflect.Type) reflect.Type) (reflect.Type, reflect.Type, error) { + if len(curType.TupleElems) == 0 { + if curType.TupleType == nil { + return nil, nil, fmt.Errorf("%w: unsupported solitidy type: %v", commontypes.ErrInvalidType, curType.String()) + } + return curType.TupleType, curType.TupleType, nil + } + + // Our naive types always have the same layout as the checked ones. + // This differs intentionally from the type.GetType() in abi as fields on structs are pointers in ours to + // verify that fields are intentionally set. + nativeFields := make([]reflect.StructField, len(curType.TupleElems)) + checkedFields := make([]reflect.StructField, len(curType.TupleElems)) + for i, elm := range curType.TupleElems { + name := curType.TupleRawNames[i] + nativeFields[i].Name = name + checkedFields[i].Name = name + nativeArgType, checkedArgType, err := getNativeAndCheckedTypes(elm) + if err != nil { + return nil, nil, err + } + nativeFields[i].Type = nativeArgType + checkedFields[i].Type = checkedArgType + } + return converter(structOfPointers(nativeFields)), converter(structOfPointers(checkedFields)), nil +} + +func structOfPointers(fields []reflect.StructField) reflect.Type { + for i := range fields { + if fields[i].Type.Kind() != reflect.Pointer { + fields[i].Type = reflect.PointerTo(fields[i].Type) + } + } + return reflect.StructOf(fields) +} diff --git a/core/services/relay/evm/types/codec_entry_test.go b/core/services/relay/evm/types/codec_entry_test.go new file mode 100644 index 00000000000..1ea3a9ae576 --- /dev/null +++ b/core/services/relay/evm/types/codec_entry_test.go @@ -0,0 +1,289 @@ +package types + +import ( + "errors" + "math/big" + "reflect" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +func TestCodecEntry(t *testing.T) { + t.Run("basic types", func(t *testing.T) { + type1, err := abi.NewType("uint16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + type2, err := abi.NewType("string", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + type3, err := abi.NewType("uint24", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + type4, err := abi.NewType("int24", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + args := abi.Arguments{ + {Name: "Field1", Type: type1}, + {Name: "Field2", Type: type2}, + {Name: "Field3", Type: type3}, + {Name: "Field4", Type: type4}, + } + entry := NewCodecEntry(args, nil, nil) + require.NoError(t, entry.Init()) + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + f1 := uint16(2) + iChecked.FieldByName("Field1").Set(reflect.ValueOf(&f1)) + f2 := "any string" + iChecked.FieldByName("Field2").Set(reflect.ValueOf(&f2)) + + f3 := big.NewInt( /*2^24 - 1*/ 16777215) + setAndVerifyLimit(t, (*uint24)(f3), f3, iChecked.FieldByName("Field3")) + + f4 := big.NewInt( /*2^23 - 1*/ 8388607) + setAndVerifyLimit(t, (*int24)(f4), f4, iChecked.FieldByName("Field4")) + + rNative, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(rNative) + assert.Equal(t, iNative.Field(0).Interface(), iChecked.Field(0).Interface()) + assert.Equal(t, iNative.Field(1).Interface(), iChecked.Field(1).Interface()) + assert.Equal(t, iNative.Field(2).Interface(), f3) + assert.Equal(t, iNative.Field(3).Interface(), f4) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("tuples", func(t *testing.T) { + type1, err := abi.NewType("uint16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + tupleType, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{ + {Name: "Field3", Type: "uint24"}, + {Name: "Field4", Type: "int24"}, + }) + require.NoError(t, err) + args := abi.Arguments{ + {Name: "Field1", Type: type1}, + {Name: "Field2", Type: tupleType}, + } + entry := NewCodecEntry(args, nil, nil) + require.NoError(t, entry.Init()) + + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + f1 := uint16(2) + iChecked.FieldByName("Field1").Set(reflect.ValueOf(&f1)) + f2 := iChecked.FieldByName("Field2") + f2.Set(reflect.New(f2.Type().Elem())) + f2 = reflect.Indirect(f2) + f3 := big.NewInt( /*2^24 - 1*/ 16777215) + setAndVerifyLimit(t, (*uint24)(f3), f3, f2.FieldByName("Field3")) + f4 := big.NewInt( /*2^23 - 1*/ 8388607) + setAndVerifyLimit(t, (*int24)(f4), f4, f2.FieldByName("Field4")) + + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + require.Equal(t, iNative.Field(0).Interface(), iChecked.Field(0).Interface()) + nF2 := reflect.Indirect(iNative.Field(1)) + assert.Equal(t, nF2.Field(0).Interface(), f3) + assert.Equal(t, nF2.Field(1).Interface(), f4) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("unwrapped types", func(t *testing.T) { + // This exists to allow you to decode single returned values without naming the parameter + wrappedTuple, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{ + {Name: "Field1", Type: "int16"}, + }) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "", Type: wrappedTuple}}, nil, nil) + require.NoError(t, entry.Init()) + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + anyValue := int16(2) + iChecked.FieldByName("Field1").Set(reflect.ValueOf(&anyValue)) + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + assert.Equal(t, &anyValue, iNative.FieldByName("Field1").Interface()) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("slice types", func(t *testing.T) { + type1, err := abi.NewType("int16[]", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Field1", Type: type1}}, nil, nil) + + require.NoError(t, entry.Init()) + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + anySliceValue := &[]int16{2, 3} + iChecked.FieldByName("Field1").Set(reflect.ValueOf(anySliceValue)) + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + assert.Equal(t, anySliceValue, iNative.FieldByName("Field1").Interface()) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("array types", func(t *testing.T) { + type1, err := abi.NewType("int16[3]", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Field1", Type: type1}}, nil, nil) + require.NoError(t, entry.Init()) + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + anySliceValue := &[3]int16{2, 3, 30} + iChecked.FieldByName("Field1").Set(reflect.ValueOf(anySliceValue)) + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + assert.Equal(t, anySliceValue, iNative.FieldByName("Field1").Interface()) + }) + + t.Run("Not return values makes struct{}", func(t *testing.T) { + entry := NewCodecEntry(abi.Arguments{}, nil, nil) + require.NoError(t, entry.Init()) + assert.Equal(t, reflect.TypeOf(struct{}{}), entry.CheckedType()) + native, err := entry.ToNative(reflect.ValueOf(&struct{}{})) + require.NoError(t, err) + assert.Equal(t, &struct{}{}, native.Interface()) + }) + + t.Run("Address works", func(t *testing.T) { + address, err := abi.NewType("address", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "foo", Type: address}}, nil, nil) + require.NoError(t, entry.Init()) + + checked := reflect.New(entry.CheckedType()) + iChecked := reflect.Indirect(checked) + anyAddr := &common.Address{1, 2, 3} + iChecked.FieldByName("Foo").Set(reflect.ValueOf(anyAddr)) + + native, err := entry.ToNative(checked) + require.NoError(t, err) + iNative := reflect.Indirect(native) + assert.Equal(t, anyAddr, iNative.FieldByName("Foo").Interface()) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("Multiple unnamed parameters are not supported", func(t *testing.T) { + anyType, err := abi.NewType("int16[3]", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "", Type: anyType}, {Name: "", Type: anyType}}, nil, nil) + assert.True(t, errors.Is(entry.Init(), commontypes.ErrInvalidType)) + }) + + t.Run("Multiple abi arguments with the same name returns an error", func(t *testing.T) { + anyType, err := abi.NewType("int16[3]", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType}, {Name: "Name", Type: anyType}}, nil, nil) + assert.True(t, errors.Is(entry.Init(), commontypes.ErrInvalidConfig)) + }) + + t.Run("Indexed basic types leave their native and checked types as-is", func(t *testing.T) { + anyType, err := abi.NewType("int16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, nil, nil) + require.NoError(t, entry.Init()) + checkedField, ok := entry.CheckedType().FieldByName("Name") + require.True(t, ok) + assert.Equal(t, reflect.TypeOf((*int16)(nil)), checkedField.Type) + native, err := entry.ToNative(reflect.New(entry.CheckedType())) + require.NoError(t, err) + iNative := reflect.Indirect(native) + assertHaveSameStructureAndNames(t, iNative.Type(), entry.CheckedType()) + }) + + t.Run("Indexed non basic types change to hash", func(t *testing.T) { + anyType, err := abi.NewType("string", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, nil, nil) + require.NoError(t, entry.Init()) + nativeField, ok := entry.CheckedType().FieldByName("Name") + require.True(t, ok) + assert.Equal(t, reflect.TypeOf(&common.Hash{}), nativeField.Type) + native, err := entry.ToNative(reflect.New(entry.CheckedType())) + require.NoError(t, err) + assertHaveSameStructureAndNames(t, native.Type().Elem(), entry.CheckedType()) + }) + + t.Run("Too many indexed items returns an error", func(t *testing.T) { + anyType, err := abi.NewType("int16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry( + abi.Arguments{ + {Name: "Name1", Type: anyType, Indexed: true}, + {Name: "Name2", Type: anyType, Indexed: true}, + {Name: "Name3", Type: anyType, Indexed: true}, + {Name: "Name4", Type: anyType, Indexed: true}, + }, nil, nil) + require.True(t, errors.Is(entry.Init(), commontypes.ErrInvalidConfig)) + }) + + // TODO: when the TODO on + // https://github.com/ethereum/go-ethereum/blob/release/1.12/accounts/abi/topics.go#L78 + // is removed, remove this test. + t.Run("Using unsupported types by go-ethereum returns an error", func(t *testing.T) { + anyType, err := abi.NewType("int256[2]", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, nil, nil) + assert.True(t, errors.Is(entry.Init(), commontypes.ErrInvalidConfig)) + }) + + t.Run("Modifier returns provided modifier", func(t *testing.T) { + anyType, err := abi.NewType("int16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + mod := codec.NewRenamer(map[string]string{"Name": "RenamedName"}) + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, nil, mod) + assert.Equal(t, mod, entry.Modifier()) + }) + + t.Run("EncodingPrefix returns provided prefix", func(t *testing.T) { + anyType, err := abi.NewType("int16", "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + prefix := []byte{1, 2, 3} + entry := NewCodecEntry(abi.Arguments{{Name: "Name", Type: anyType, Indexed: true}}, prefix, nil) + assert.Equal(t, prefix, entry.EncodingPrefix()) + }) +} + +// sized and bi must be the same pointer. +func setAndVerifyLimit(t *testing.T, sbi SizedBigInt, bi *big.Int, field reflect.Value) { + require.Same(t, reflect.NewAt(reflect.TypeOf(big.Int{}), reflect.ValueOf(sbi).UnsafePointer()).Interface(), bi) + field.Set(reflect.ValueOf(sbi)) + assert.NoError(t, sbi.Verify()) + bi.Add(bi, big.NewInt(1)) + assert.IsType(t, commontypes.ErrInvalidType, sbi.Verify()) +} + +// verifying the same structure allows us to use unsafe pointers to cast between them. +// This is done for perf and simplicity in mapping the two structures. +// [reflect.NewAt]'s use is the same as (*native)(unsafe.Pointer(checked)) +// See the safe usecase 1 from [unsafe.Pointer], as this is a subset of that. +// This also verifies field names are the same. +func assertHaveSameStructureAndNames(t *testing.T, t1, t2 reflect.Type) { + require.Equal(t, t1.Kind(), t2.Kind()) + + switch t1.Kind() { + case reflect.Array: + require.Equal(t, t1.Len(), t2.Len()) + assertHaveSameStructureAndNames(t, t1.Elem(), t2.Elem()) + case reflect.Slice, reflect.Pointer: + assertHaveSameStructureAndNames(t, t1.Elem(), t2.Elem()) + case reflect.Struct: + numFields := t1.NumField() + require.Equal(t, numFields, t2.NumField()) + for i := 0; i < numFields; i++ { + require.Equal(t, t1.Field(i).Name, t2.Field(i).Name) + assertHaveSameStructureAndNames(t, t1.Field(i).Type, t2.Field(i).Type) + } + default: + require.Equal(t, t1, t2) + } +} diff --git a/core/services/relay/evm/types/gen/bytes.go.tmpl b/core/services/relay/evm/types/gen/bytes.go.tmpl new file mode 100644 index 00000000000..3c06529b0f3 --- /dev/null +++ b/core/services/relay/evm/types/gen/bytes.go.tmpl @@ -0,0 +1,14 @@ +package types + +import "reflect" + +{{ range . }} +type bytes{{.Size}} [{{.Size}}]byte +func init() { + typeMap["bytes{{.Size}}"] = &ABIEncodingType { + native: reflect.TypeOf([{{.Size}}]byte{}), + checked: reflect.TypeOf(bytes{{.Size}}{}), + } +} + +{{ end }} \ No newline at end of file diff --git a/core/services/relay/evm/types/gen/ints.go.tmpl b/core/services/relay/evm/types/gen/ints.go.tmpl new file mode 100644 index 00000000000..b5f0fa363ca --- /dev/null +++ b/core/services/relay/evm/types/gen/ints.go.tmpl @@ -0,0 +1,74 @@ +package types + +import ( + "math/big" + "reflect" + + "github.com/fxamacker/cbor/v2" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +type SizedBigInt interface { + Verify() error + private() +} + +var sizedBigIntType = reflect.TypeOf((*SizedBigInt)(nil)).Elem() +func SizedBigIntType() reflect.Type { + return sizedBigIntType +} + +{{ range . }} +type {{.Prefix}}int{{.Size}} big.Int +func (i *{{.Prefix}}int{{.Size}}) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *{{.Prefix}}int{{.Size}}) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *{{.Prefix}}int{{.Size}}) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *{{.Prefix}}int{{.Size}}) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *{{.Prefix}}int{{.Size}}) Verify() error { + bi := (*big.Int)(i) + {{ if .Signed }} + if !codec.FitsInNBitsSigned({{.Size}}, bi) { + return types.ErrInvalidType + } + {{ else }} + if bi.BitLen() > {{.Size}} || bi.Sign() < 0 { + return types.ErrInvalidType + } + {{ end }} + return nil +} + +func (i *{{.Prefix}}int{{.Size}}) private() {} + +func init() { + typeMap["{{.Prefix}}int{{.Size}}"] = &ABIEncodingType { + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*{{.Prefix}}int{{.Size}})(nil)), + } +} +{{ end }} \ No newline at end of file diff --git a/core/services/relay/evm/types/gen/main.go b/core/services/relay/evm/types/gen/main.go new file mode 100644 index 00000000000..84e7c008ee0 --- /dev/null +++ b/core/services/relay/evm/types/gen/main.go @@ -0,0 +1,73 @@ +package main + +import ( + "bytes" + _ "embed" + "go/format" + "os" + "text/template" +) + +func main() { + genInts() + genBytes() +} + +func genBytes() { + byteTypes := [33]ByteType{} + for i := 1; i < 33; i++ { + byteTypes[i-1].Size = i + } + mustRunTemplate("bytes", bytesTemplate, "byte_types_gen.go", byteTypes) +} + +func genInts() { + var intTypes []*IntType + + // 8, 16, 32, and 64 bits have their own type in go that is used by abi. + // The test use *big.Int + for i := 24; i <= 256; i += 8 { + if i == 32 || i == 64 { + continue + } + + signed := &IntType{Size: i, Signed: true} + unsigned := &IntType{Prefix: "u", Size: i} + intTypes = append(intTypes, signed, unsigned) + } + mustRunTemplate("ints", intsTemplate, "int_types_gen.go", intTypes) +} + +func mustRunTemplate(name, rawTemplate, outputFile string, input any) { + t := template.Must(template.New(name).Parse(rawTemplate)) + + br := bytes.Buffer{} + if err := t.Execute(&br, input); err != nil { + panic(err) + } + + res, err := format.Source(br.Bytes()) + if err != nil { + panic(err) + } + + if err = os.WriteFile(outputFile, res, 0600); err != nil { + panic(err) + } +} + +type IntType struct { + Prefix string + Size int + Signed bool +} + +type ByteType struct { + Size int +} + +//go:embed bytes.go.tmpl +var bytesTemplate string + +//go:embed ints.go.tmpl +var intsTemplate string diff --git a/core/services/relay/evm/types/int_types_gen.go b/core/services/relay/evm/types/int_types_gen.go new file mode 100644 index 00000000000..1ff82d5691d --- /dev/null +++ b/core/services/relay/evm/types/int_types_gen.go @@ -0,0 +1,2710 @@ +package types + +import ( + "math/big" + "reflect" + + "github.com/fxamacker/cbor/v2" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +type SizedBigInt interface { + Verify() error + private() +} + +var sizedBigIntType = reflect.TypeOf((*SizedBigInt)(nil)).Elem() + +func SizedBigIntType() reflect.Type { + return sizedBigIntType +} + +type int24 big.Int + +func (i *int24) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int24) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int24) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int24) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int24) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(24, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int24) private() {} + +func init() { + typeMap["int24"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int24)(nil)), + } +} + +type uint24 big.Int + +func (i *uint24) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint24) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint24) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint24) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint24) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 24 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint24) private() {} + +func init() { + typeMap["uint24"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint24)(nil)), + } +} + +type int40 big.Int + +func (i *int40) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int40) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int40) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int40) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int40) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(40, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int40) private() {} + +func init() { + typeMap["int40"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int40)(nil)), + } +} + +type uint40 big.Int + +func (i *uint40) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint40) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint40) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint40) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint40) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 40 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint40) private() {} + +func init() { + typeMap["uint40"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint40)(nil)), + } +} + +type int48 big.Int + +func (i *int48) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int48) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int48) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int48) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int48) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(48, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int48) private() {} + +func init() { + typeMap["int48"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int48)(nil)), + } +} + +type uint48 big.Int + +func (i *uint48) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint48) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint48) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint48) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint48) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 48 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint48) private() {} + +func init() { + typeMap["uint48"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint48)(nil)), + } +} + +type int56 big.Int + +func (i *int56) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int56) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int56) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int56) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int56) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(56, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int56) private() {} + +func init() { + typeMap["int56"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int56)(nil)), + } +} + +type uint56 big.Int + +func (i *uint56) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint56) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint56) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint56) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint56) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 56 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint56) private() {} + +func init() { + typeMap["uint56"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint56)(nil)), + } +} + +type int72 big.Int + +func (i *int72) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int72) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int72) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int72) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int72) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(72, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int72) private() {} + +func init() { + typeMap["int72"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int72)(nil)), + } +} + +type uint72 big.Int + +func (i *uint72) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint72) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint72) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint72) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint72) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 72 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint72) private() {} + +func init() { + typeMap["uint72"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint72)(nil)), + } +} + +type int80 big.Int + +func (i *int80) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int80) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int80) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int80) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int80) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(80, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int80) private() {} + +func init() { + typeMap["int80"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int80)(nil)), + } +} + +type uint80 big.Int + +func (i *uint80) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint80) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint80) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint80) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint80) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 80 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint80) private() {} + +func init() { + typeMap["uint80"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint80)(nil)), + } +} + +type int88 big.Int + +func (i *int88) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int88) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int88) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int88) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int88) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(88, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int88) private() {} + +func init() { + typeMap["int88"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int88)(nil)), + } +} + +type uint88 big.Int + +func (i *uint88) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint88) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint88) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint88) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint88) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 88 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint88) private() {} + +func init() { + typeMap["uint88"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint88)(nil)), + } +} + +type int96 big.Int + +func (i *int96) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int96) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int96) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int96) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int96) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(96, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int96) private() {} + +func init() { + typeMap["int96"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int96)(nil)), + } +} + +type uint96 big.Int + +func (i *uint96) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint96) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint96) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint96) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint96) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 96 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint96) private() {} + +func init() { + typeMap["uint96"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint96)(nil)), + } +} + +type int104 big.Int + +func (i *int104) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int104) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int104) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int104) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int104) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(104, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int104) private() {} + +func init() { + typeMap["int104"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int104)(nil)), + } +} + +type uint104 big.Int + +func (i *uint104) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint104) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint104) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint104) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint104) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 104 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint104) private() {} + +func init() { + typeMap["uint104"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint104)(nil)), + } +} + +type int112 big.Int + +func (i *int112) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int112) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int112) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int112) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int112) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(112, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int112) private() {} + +func init() { + typeMap["int112"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int112)(nil)), + } +} + +type uint112 big.Int + +func (i *uint112) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint112) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint112) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint112) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint112) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 112 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint112) private() {} + +func init() { + typeMap["uint112"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint112)(nil)), + } +} + +type int120 big.Int + +func (i *int120) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int120) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int120) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int120) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int120) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(120, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int120) private() {} + +func init() { + typeMap["int120"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int120)(nil)), + } +} + +type uint120 big.Int + +func (i *uint120) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint120) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint120) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint120) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint120) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 120 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint120) private() {} + +func init() { + typeMap["uint120"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint120)(nil)), + } +} + +type int128 big.Int + +func (i *int128) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int128) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int128) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int128) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int128) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(128, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int128) private() {} + +func init() { + typeMap["int128"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int128)(nil)), + } +} + +type uint128 big.Int + +func (i *uint128) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint128) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint128) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint128) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint128) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 128 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint128) private() {} + +func init() { + typeMap["uint128"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint128)(nil)), + } +} + +type int136 big.Int + +func (i *int136) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int136) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int136) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int136) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int136) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(136, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int136) private() {} + +func init() { + typeMap["int136"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int136)(nil)), + } +} + +type uint136 big.Int + +func (i *uint136) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint136) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint136) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint136) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint136) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 136 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint136) private() {} + +func init() { + typeMap["uint136"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint136)(nil)), + } +} + +type int144 big.Int + +func (i *int144) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int144) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int144) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int144) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int144) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(144, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int144) private() {} + +func init() { + typeMap["int144"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int144)(nil)), + } +} + +type uint144 big.Int + +func (i *uint144) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint144) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint144) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint144) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint144) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 144 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint144) private() {} + +func init() { + typeMap["uint144"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint144)(nil)), + } +} + +type int152 big.Int + +func (i *int152) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int152) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int152) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int152) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int152) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(152, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int152) private() {} + +func init() { + typeMap["int152"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int152)(nil)), + } +} + +type uint152 big.Int + +func (i *uint152) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint152) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint152) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint152) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint152) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 152 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint152) private() {} + +func init() { + typeMap["uint152"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint152)(nil)), + } +} + +type int160 big.Int + +func (i *int160) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int160) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int160) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int160) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int160) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(160, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int160) private() {} + +func init() { + typeMap["int160"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int160)(nil)), + } +} + +type uint160 big.Int + +func (i *uint160) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint160) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint160) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint160) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint160) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 160 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint160) private() {} + +func init() { + typeMap["uint160"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint160)(nil)), + } +} + +type int168 big.Int + +func (i *int168) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int168) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int168) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int168) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int168) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(168, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int168) private() {} + +func init() { + typeMap["int168"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int168)(nil)), + } +} + +type uint168 big.Int + +func (i *uint168) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint168) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint168) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint168) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint168) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 168 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint168) private() {} + +func init() { + typeMap["uint168"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint168)(nil)), + } +} + +type int176 big.Int + +func (i *int176) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int176) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int176) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int176) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int176) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(176, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int176) private() {} + +func init() { + typeMap["int176"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int176)(nil)), + } +} + +type uint176 big.Int + +func (i *uint176) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint176) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint176) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint176) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint176) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 176 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint176) private() {} + +func init() { + typeMap["uint176"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint176)(nil)), + } +} + +type int184 big.Int + +func (i *int184) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int184) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int184) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int184) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int184) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(184, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int184) private() {} + +func init() { + typeMap["int184"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int184)(nil)), + } +} + +type uint184 big.Int + +func (i *uint184) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint184) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint184) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint184) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint184) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 184 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint184) private() {} + +func init() { + typeMap["uint184"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint184)(nil)), + } +} + +type int192 big.Int + +func (i *int192) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int192) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int192) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int192) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int192) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(192, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int192) private() {} + +func init() { + typeMap["int192"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int192)(nil)), + } +} + +type uint192 big.Int + +func (i *uint192) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint192) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint192) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint192) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint192) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 192 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint192) private() {} + +func init() { + typeMap["uint192"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint192)(nil)), + } +} + +type int200 big.Int + +func (i *int200) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int200) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int200) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int200) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int200) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(200, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int200) private() {} + +func init() { + typeMap["int200"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int200)(nil)), + } +} + +type uint200 big.Int + +func (i *uint200) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint200) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint200) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint200) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint200) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 200 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint200) private() {} + +func init() { + typeMap["uint200"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint200)(nil)), + } +} + +type int208 big.Int + +func (i *int208) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int208) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int208) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int208) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int208) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(208, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int208) private() {} + +func init() { + typeMap["int208"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int208)(nil)), + } +} + +type uint208 big.Int + +func (i *uint208) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint208) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint208) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint208) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint208) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 208 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint208) private() {} + +func init() { + typeMap["uint208"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint208)(nil)), + } +} + +type int216 big.Int + +func (i *int216) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int216) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int216) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int216) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int216) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(216, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int216) private() {} + +func init() { + typeMap["int216"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int216)(nil)), + } +} + +type uint216 big.Int + +func (i *uint216) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint216) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint216) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint216) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint216) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 216 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint216) private() {} + +func init() { + typeMap["uint216"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint216)(nil)), + } +} + +type int224 big.Int + +func (i *int224) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int224) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int224) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int224) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int224) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(224, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int224) private() {} + +func init() { + typeMap["int224"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int224)(nil)), + } +} + +type uint224 big.Int + +func (i *uint224) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint224) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint224) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint224) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint224) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 224 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint224) private() {} + +func init() { + typeMap["uint224"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint224)(nil)), + } +} + +type int232 big.Int + +func (i *int232) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int232) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int232) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int232) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int232) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(232, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int232) private() {} + +func init() { + typeMap["int232"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int232)(nil)), + } +} + +type uint232 big.Int + +func (i *uint232) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint232) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint232) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint232) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint232) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 232 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint232) private() {} + +func init() { + typeMap["uint232"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint232)(nil)), + } +} + +type int240 big.Int + +func (i *int240) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int240) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int240) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int240) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int240) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(240, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int240) private() {} + +func init() { + typeMap["int240"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int240)(nil)), + } +} + +type uint240 big.Int + +func (i *uint240) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint240) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint240) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint240) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint240) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 240 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint240) private() {} + +func init() { + typeMap["uint240"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint240)(nil)), + } +} + +type int248 big.Int + +func (i *int248) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int248) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int248) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int248) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int248) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(248, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int248) private() {} + +func init() { + typeMap["int248"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int248)(nil)), + } +} + +type uint248 big.Int + +func (i *uint248) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint248) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint248) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint248) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint248) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 248 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint248) private() {} + +func init() { + typeMap["uint248"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint248)(nil)), + } +} + +type int256 big.Int + +func (i *int256) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *int256) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *int256) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *int256) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *int256) Verify() error { + bi := (*big.Int)(i) + + if !codec.FitsInNBitsSigned(256, bi) { + return types.ErrInvalidType + } + + return nil +} + +func (i *int256) private() {} + +func init() { + typeMap["int256"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*int256)(nil)), + } +} + +type uint256 big.Int + +func (i *uint256) UnmarshalCBOR(input []byte) error { + bi := (*big.Int)(i) + if err := cbor.Unmarshal(input, bi); err != nil { + return err + } + + return i.Verify() +} + +func (i *uint256) MarshalCBOR() ([]byte, error) { + return cbor.Marshal((*big.Int)(i)) +} + +func (i *uint256) UnmarshalText(input []byte) error { + bi := (*big.Int)(i) + if _, ok := bi.SetString(string(input), 10); !ok { + return types.ErrInvalidType + } + + return i.Verify() +} + +func (i *uint256) MarshalText() ([]byte, error) { + bi := (*big.Int)(i) + return []byte(bi.String()), nil +} + +func (i *uint256) Verify() error { + bi := (*big.Int)(i) + + if bi.BitLen() > 256 || bi.Sign() < 0 { + return types.ErrInvalidType + } + + return nil +} + +func (i *uint256) private() {} + +func init() { + typeMap["uint256"] = &ABIEncodingType{ + native: reflect.TypeOf((*big.Int)(nil)), + checked: reflect.TypeOf((*uint256)(nil)), + } +} diff --git a/core/services/relay/evm/types/int_types_test.go b/core/services/relay/evm/types/int_types_test.go new file mode 100644 index 00000000000..6930287c869 --- /dev/null +++ b/core/services/relay/evm/types/int_types_test.go @@ -0,0 +1,54 @@ +package types + +import ( + "errors" + "fmt" + "math/big" + "reflect" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +func TestIntTypes(t *testing.T) { + t.Parallel() + for i := 24; i <= 256; i += 8 { + if i == 64 || i == 32 { + continue + } + t.Run(fmt.Sprintf("int%v", i), func(t *testing.T) { + tpe, ok := GetAbiEncodingType(fmt.Sprintf("int%v", i)) + require.True(t, ok) + minVal := new(big.Int).Neg(new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(i-1)), nil)) + maxVal := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(i-1)), nil), big.NewInt(1)) + assertBigIntBounds(t, tpe, minVal, maxVal) + }) + + t.Run(fmt.Sprintf("uint%v", i), func(t *testing.T) { + tep, ok := GetAbiEncodingType(fmt.Sprintf("uint%v", i)) + require.True(t, ok) + minVal := big.NewInt(0) + maxVal := new(big.Int).Sub(new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(i)), nil), big.NewInt(1)) + assertBigIntBounds(t, tep, minVal, maxVal) + }) + } +} + +func assertBigIntBounds(t *testing.T, tpe *ABIEncodingType, min, max *big.Int) { + t.Helper() + assert.Equal(t, reflect.TypeOf(min), tpe.native) + assert.True(t, tpe.checked.ConvertibleTo(reflect.TypeOf(min))) + minMinusOne := new(big.Int).Sub(min, big.NewInt(1)) + maxPlusOne := new(big.Int).Add(max, big.NewInt(1)) + sbi := reflect.ValueOf(min).Convert(tpe.checked).Interface().(SizedBigInt) + assert.NoError(t, sbi.Verify()) + sbi = reflect.ValueOf(max).Convert(tpe.checked).Interface().(SizedBigInt) + assert.NoError(t, sbi.Verify()) + sbi = reflect.ValueOf(minMinusOne).Convert(tpe.checked).Interface().(SizedBigInt) + assert.True(t, errors.Is(types.ErrInvalidType, sbi.Verify())) + sbi = reflect.ValueOf(maxPlusOne).Convert(tpe.checked).Interface().(SizedBigInt) + assert.True(t, errors.Is(types.ErrInvalidType, sbi.Verify())) +} 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 6812ce5aba3..675cf317b14 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type LogPollerWrapper struct { func (_m *LogPollerWrapper) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *LogPollerWrapper) Close() error { func (_m *LogPollerWrapper) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -48,6 +56,10 @@ func (_m *LogPollerWrapper) HealthReport() map[string]error { func (_m *LogPollerWrapper) LatestEvents() ([]types.OracleRequest, []types.OracleResponse, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LatestEvents") + } + var r0 []types.OracleRequest var r1 []types.OracleResponse var r2 error @@ -83,6 +95,10 @@ func (_m *LogPollerWrapper) LatestEvents() ([]types.OracleRequest, []types.Oracl func (_m *LogPollerWrapper) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -97,6 +113,10 @@ func (_m *LogPollerWrapper) Name() string { func (_m *LogPollerWrapper) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -111,6 +131,10 @@ func (_m *LogPollerWrapper) Ready() error { func (_m *LogPollerWrapper) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/relay/evm/types/size_helper.go b/core/services/relay/evm/types/size_helper.go new file mode 100644 index 00000000000..921b8a28315 --- /dev/null +++ b/core/services/relay/evm/types/size_helper.go @@ -0,0 +1,69 @@ +package types + +import ( + "github.com/ethereum/go-ethereum/accounts/abi" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +func GetMaxSize(n int, args abi.Arguments) (int, error) { + size := 0 + for _, arg := range args { + tmp := arg.Type + argSize, _, err := getTypeSize(n, &tmp, true, false) + if err != nil { + return 0, err + } + size += argSize + } + + return size, nil +} + +func getTypeSize(n int, t *abi.Type, dynamicTypeAllowed bool, isNested bool) (int, bool, error) { + // See https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding + switch t.T { + case abi.ArrayTy: + elmSize, _, err := getTypeSize(n, t.Elem, false, true) + return t.Size * elmSize, false, err + case abi.SliceTy: + if !dynamicTypeAllowed { + return 0, false, commontypes.ErrInvalidType + } + elmSize, _, err := getTypeSize(n, t.Elem, false, true) + return 32 /*header*/ + 32 /*footer*/ + elmSize*n, true, err + case abi.BytesTy, abi.StringTy: + if !dynamicTypeAllowed { + return 0, false, commontypes.ErrInvalidType + } + totalSize := (n + 31) / 32 * 32 // strings and bytes are padded to 32 bytes + return 32 /*header*/ + 32 /*footer*/ + totalSize, true, nil + case abi.TupleTy: + return getTupleSize(n, t, isNested) + default: + // types are padded to 32 bytes + return 32, false, nil + } +} + +func getTupleSize(n int, t *abi.Type, isNested bool) (int, bool, error) { + // No header or footer, because if the tuple is dynamically sized we would need to know the inner slice sizes + // so it would return error for that element. + size := 0 + dynamic := false + for _, elm := range t.TupleElems { + argSize, dynamicArg, err := getTypeSize(n, elm, !isNested, true) + if err != nil { + return 0, false, err + } + dynamic = dynamic || dynamicArg + size += argSize + } + + if dynamic { + // offset for the element needs to be included there are dynamic elements + size += 32 + } + + return size, dynamic, nil +} diff --git a/core/services/relay/evm/types/size_helper_test.go b/core/services/relay/evm/types/size_helper_test.go new file mode 100644 index 00000000000..202269a4536 --- /dev/null +++ b/core/services/relay/evm/types/size_helper_test.go @@ -0,0 +1,263 @@ +package types_test + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +const anyNumElements = 10 + +func TestGetMaxSize(t *testing.T) { + t.Run("Basic types all encode to 32 bytes", func(t *testing.T) { + args := abi.Arguments{ + {Name: "I8", Type: mustType(t, "int8")}, + {Name: "I80", Type: mustType(t, "int80")}, + {Name: "I256", Type: mustType(t, "int256")}, + {Name: "B3", Type: mustType(t, "bytes3")}, + {Name: "B32", Type: mustType(t, "bytes32")}, + {Name: "TF", Type: mustType(t, "bool")}, + } + + runSizeTest(t, anyNumElements, args, int8(9), big.NewInt(3), big.NewInt(200), [3]byte{1, 3, 4}, make32Bytes(1), true) + }) + + t.Run("Slices of basic types all encode to 32 bytes each + header and footer", func(t *testing.T) { + args := abi.Arguments{ + {Name: "I8", Type: mustType(t, "int8[]")}, + {Name: "I80", Type: mustType(t, "int80[]")}, + {Name: "I256", Type: mustType(t, "int256[]")}, + {Name: "B3", Type: mustType(t, "bytes3[]")}, + {Name: "B32", Type: mustType(t, "bytes32[]")}, + {Name: "TF", Type: mustType(t, "bool[]")}, + } + + i8 := []int8{9, 2, 1, 3, 5, 6, 2, 1, 2, 3} + i80 := []*big.Int{big.NewInt(9), big.NewInt(2), big.NewInt(1), big.NewInt(3), big.NewInt(5), big.NewInt(6), big.NewInt(2), big.NewInt(1), big.NewInt(2), big.NewInt(3)} + i256 := []*big.Int{big.NewInt(119), big.NewInt(112), big.NewInt(1), big.NewInt(3), big.NewInt(5), big.NewInt(6), big.NewInt(2), big.NewInt(1), big.NewInt(2), big.NewInt(3)} + b3 := [][3]byte{{1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}, {1, 2, 3}} + b32 := [][32]byte{make32Bytes(1), make32Bytes(2), make32Bytes(3), make32Bytes(4), make32Bytes(5), make32Bytes(6), make32Bytes(7), make32Bytes(8), make32Bytes(9), make32Bytes(10)} + tf := []bool{true, false, true, false, true, false, true, false, true, false} + runSizeTest(t, anyNumElements, args, i8, i80, i256, b3, b32, tf) + }) + + t.Run("Arrays of basic types all encode to 32 bytes each", func(t *testing.T) { + args := abi.Arguments{ + {Name: "I8", Type: mustType(t, "int8[3]")}, + {Name: "I80", Type: mustType(t, "int80[3]")}, + {Name: "I256", Type: mustType(t, "int256[3]")}, + {Name: "B3", Type: mustType(t, "bytes3[3]")}, + {Name: "B32", Type: mustType(t, "bytes32[3]")}, + {Name: "TF", Type: mustType(t, "bool[3]")}, + } + + i8 := [3]int8{9, 2, 1} + i80 := [3]*big.Int{big.NewInt(9), big.NewInt(2), big.NewInt(1)} + i256 := [3]*big.Int{big.NewInt(119), big.NewInt(112), big.NewInt(1)} + b3 := [3][3]byte{{1, 2, 3}, {1, 2, 3}, {1, 2, 3}} + b32 := [3][32]byte{make32Bytes(1), make32Bytes(2), make32Bytes(3)} + tf := [3]bool{true, false, true} + runSizeTest(t, anyNumElements, args, i8, i80, i256, b3, b32, tf) + }) + + t.Run("Tuples are a sum of their elements", func(t *testing.T) { + tuple1 := []abi.ArgumentMarshaling{ + {Name: "I8", Type: "int8"}, + {Name: "I80", Type: "int80"}, + {Name: "I256", Type: "int256"}, + {Name: "B3", Type: "bytes3"}, + {Name: "B32", Type: "bytes32"}, + {Name: "TF", Type: "bool"}, + } + t1, err := abi.NewType("tuple", "", tuple1) + require.NoError(t, err) + + tuple2 := []abi.ArgumentMarshaling{ + {Name: "I80", Type: "int80"}, + {Name: "TF", Type: "bool"}, + } + t2, err := abi.NewType("tuple", "", tuple2) + require.NoError(t, err) + + args := abi.Arguments{ + {Name: "t1", Type: t1}, + {Name: "t2", Type: t2}, + } + arg1 := struct { + I8 int8 + I80 *big.Int + I256 *big.Int + B3 [3]byte + B32 [32]byte + TF bool + }{ + int8(9), big.NewInt(3), big.NewInt(200), [3]byte{1, 3, 4}, make32Bytes(1), true, + } + + arg2 := struct { + I80 *big.Int + TF bool + }{ + big.NewInt(3), true, + } + runSizeTest(t, anyNumElements, args, arg1, arg2) + }) + + t.Run("Slices of tuples are a sum of their elements with header and footer", func(t *testing.T) { + tuple1 := []abi.ArgumentMarshaling{ + {Name: "I80", Type: "int80"}, + {Name: "TF", Type: "bool"}, + } + t1, err := abi.NewType("tuple[]", "", tuple1) + require.NoError(t, err) + + args := abi.Arguments{ + {Name: "t1", Type: t1}, + } + arg1 := []struct { + I80 *big.Int + TF bool + }{ + {big.NewInt(1), true}, + {big.NewInt(2), true}, + {big.NewInt(3), true}, + {big.NewInt(4), false}, + {big.NewInt(5), true}, + {big.NewInt(6), true}, + {big.NewInt(7), true}, + {big.NewInt(8), false}, + {big.NewInt(9), true}, + {big.NewInt(10), true}, + } + runSizeTest(t, anyNumElements, args, arg1) + }) + + t.Run("Arrays of tuples are a sum of their elements", func(t *testing.T) { + tuple1 := []abi.ArgumentMarshaling{ + {Name: "I80", Type: "int80"}, + {Name: "TF", Type: "bool"}, + } + t1, err := abi.NewType("tuple[3]", "", tuple1) + require.NoError(t, err) + + args := abi.Arguments{ + {Name: "t1", Type: t1}, + } + arg1 := []struct { + I80 *big.Int + TF bool + }{ + {big.NewInt(1), true}, + {big.NewInt(2), true}, + {big.NewInt(3), true}, + } + runSizeTest(t, anyNumElements, args, arg1) + + }) + + t.Run("Bytes pack themselves", func(t *testing.T) { + args := abi.Arguments{{Name: "B", Type: mustType(t, "bytes")}} + t.Run("No padding needed", func(t *testing.T) { + padded := []byte("12345789022345678903234567890412345678905123456789061234") + runSizeTest(t, 64, args, padded) + }) + t.Run("Padding needed", func(t *testing.T) { + needsPadding := []byte("12345789022345678903234567890412345678905123456") + runSizeTest(t, 56, args, needsPadding) + }) + }) + + t.Run("Strings pack themselves", func(t *testing.T) { + args := abi.Arguments{{Name: "B", Type: mustType(t, "string")}} + t.Run("No padding needed", func(t *testing.T) { + padded := "12345789022345678903234567890412345678905123456789061234" + runSizeTest(t, 64, args, padded) + }) + t.Run("Padding needed", func(t *testing.T) { + needsPadding := "12345789022345678903234567890412345678905123456" + runSizeTest(t, 56, args, needsPadding) + }) + }) + + t.Run("Nested dynamic types return errors", func(t *testing.T) { + t.Run("Slice in slice", func(t *testing.T) { + args := abi.Arguments{{Name: "B", Type: mustType(t, "int32[][]")}} + _, err := types.GetMaxSize(anyNumElements, args) + assert.IsType(t, commontypes.ErrInvalidType, err) + }) + t.Run("Slice in array", func(t *testing.T) { + args := abi.Arguments{{Name: "B", Type: mustType(t, "int32[][2]")}} + _, err := types.GetMaxSize(anyNumElements, args) + assert.IsType(t, commontypes.ErrInvalidType, err) + }) + }) + + t.Run("Slices in a top level tuple works as-if they are the sized element", func(t *testing.T) { + tuple1 := []abi.ArgumentMarshaling{ + {Name: "I80", Type: "int80[]"}, + {Name: "TF", Type: "bool[]"}, + } + t1, err := abi.NewType("tuple", "", tuple1) + require.NoError(t, err) + args := abi.Arguments{{Name: "tuple", Type: t1}} + + arg1 := struct { + I80 []*big.Int + TF []bool + }{ + I80: []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3), big.NewInt(4), big.NewInt(5), big.NewInt(6), big.NewInt(7), big.NewInt(8), big.NewInt(9), big.NewInt(10)}, + TF: []bool{true, true, true, false, true, true, true, false, true, true}, + } + + runSizeTest(t, anyNumElements, args, arg1) + }) + + t.Run("Nested dynamic tuples return errors", func(t *testing.T) { + tuple1 := []abi.ArgumentMarshaling{ + {Name: "I8", Type: "int8"}, + {Name: "I80", Type: "int80"}, + {Name: "I256", Type: "int256"}, + {Name: "B3", Type: "bytes3"}, + {Name: "B32", Type: "bytes32"}, + {Name: "TF", Type: "bool[]"}, + } + + tuple2 := []abi.ArgumentMarshaling{ + {Name: "I80", Type: "int80"}, + {Name: "T1", Type: "tuple", Components: tuple1}, + } + t2, err := abi.NewType("tuple", "", tuple2) + require.NoError(t, err) + + args := abi.Arguments{{Name: "t2", Type: t2}} + _, err = types.GetMaxSize(anyNumElements, args) + assert.IsType(t, commontypes.ErrInvalidType, err) + }) +} + +func runSizeTest(t *testing.T, n int, args abi.Arguments, params ...any) { + + actual, err := types.GetMaxSize(n, args) + require.NoError(t, err) + + expected, err := args.Pack(params...) + require.NoError(t, err) + assert.Equal(t, len(expected), actual) +} + +func mustType(t *testing.T, name string) abi.Type { + aType, err := abi.NewType(name, "", []abi.ArgumentMarshaling{}) + require.NoError(t, err) + return aType +} + +func make32Bytes(firstByte byte) [32]byte { + return [32]byte{firstByte, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3} +} diff --git a/core/services/relay/evm/types/types.go b/core/services/relay/evm/types/types.go index d2edef8b118..0697605edab 100644 --- a/core/services/relay/evm/types/types.go +++ b/core/services/relay/evm/types/types.go @@ -1,6 +1,7 @@ package types import ( + "bytes" "context" "encoding/json" "errors" @@ -8,23 +9,108 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/lib/pq" - - "gopkg.in/guregu/null.v2" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "gopkg.in/guregu/null.v2" + "github.com/smartcontractkit/chainlink-common/pkg/codec" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" - commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" +) + +type ChainReaderConfig struct { + // Contracts key is contract name + Contracts map[string]ChainContractReader `json:"contracts" toml:"contracts"` +} + +type CodecConfig struct { + // Configs key is the type's name for the codec + Configs map[string]ChainCodecConfig `json:"configs" toml:"configs"` +} + +type ChainCodecConfig struct { + TypeABI string `json:"typeAbi" toml:"typeABI"` + ModifierConfigs codec.ModifiersConfig `toml:"modifierConfigs,omitempty"` +} + +type ChainContractReader struct { + ContractABI string `json:"contractABI" toml:"contractABI"` + // key is genericName from config + Configs map[string]*ChainReaderDefinition `json:"configs" toml:"configs"` +} + +type ChainReaderDefinition chainReaderDefinitionFields + +// chainReaderDefinitionFields has the fields for ChainReaderDefinition but no methods. +// This is necessary because package json recognizes the text encoding methods used for TOML, +// and would infinitely recurse on itself. +type chainReaderDefinitionFields struct { + CacheEnabled bool `json:"cacheEnabled,omitempty"` + // chain specific contract method name or event type. + ChainSpecificName string `json:"chainSpecificName"` + ReadType ReadType `json:"readType,omitempty"` + InputModifications codec.ModifiersConfig `json:"inputModifications,omitempty"` + OutputModifications codec.ModifiersConfig `json:"outputModifications,omitempty"` + + // EventInputFields allows you to choose which indexed fields are expected from the input + EventInputFields []string `json:"eventInputFields,omitempty"` +} + +func (d *ChainReaderDefinition) MarshalText() ([]byte, error) { + var b bytes.Buffer + e := json.NewEncoder(&b) + e.SetIndent("", " ") + if err := e.Encode((*chainReaderDefinitionFields)(d)); err != nil { + return nil, err + } + return b.Bytes(), nil +} + +func (d *ChainReaderDefinition) UnmarshalText(b []byte) error { + return json.Unmarshal(b, (*chainReaderDefinitionFields)(d)) +} + +type ReadType int + +const ( + Method ReadType = iota + Event ) +func (r ReadType) String() string { + switch r { + case Method: + return "method" + case Event: + return "event" + } + return fmt.Sprintf("ReadType(%d)", r) +} + +func (r ReadType) MarshalText() ([]byte, error) { + return []byte(r.String()), nil +} + +func (r *ReadType) UnmarshalText(text []byte) error { + switch string(text) { + case "method": + *r = Method + return nil + case "event": + *r = Event + return nil + } + return fmt.Errorf("unrecognized ReadType: %s", string(text)) +} + type RelayConfig struct { - ChainID *utils.Big `json:"chainID"` - FromBlock uint64 `json:"fromBlock"` - EffectiveTransmitterID null.String `json:"effectiveTransmitterID"` - ConfigContractAddress *common.Address `json:"configContractAddress"` + ChainID *big.Big `json:"chainID"` + FromBlock uint64 `json:"fromBlock"` + EffectiveTransmitterID null.String `json:"effectiveTransmitterID"` + ConfigContractAddress *common.Address `json:"configContractAddress"` + ChainReader *ChainReaderConfig `json:"chainReader"` + Codec *CodecConfig `json:"codec"` // Contract-specific SendingKeys pq.StringArray `json:"sendingKeys"` @@ -33,15 +119,15 @@ type RelayConfig struct { FeedID *common.Hash `json:"feedID"` } +var ErrBadRelayConfig = errors.New("bad relay config") + type RelayOpts struct { // TODO BCF-2508 -- should anyone ever get the raw config bytes that are embedded in args? if not, // make this private and wrap the arg fields with funcs on RelayOpts - commontypes.RelayArgs + types.RelayArgs c *RelayConfig } -var ErrBadRelayConfig = errors.New("bad relay config") - func NewRelayOpts(args types.RelayArgs) *RelayOpts { return &RelayOpts{ RelayArgs: args, @@ -71,9 +157,9 @@ type ConfigPoller interface { Replay(ctx context.Context, fromBlock int64) error } -// TODO(FUN-668): Migrate this fully into commontypes.FunctionsProvider +// TODO(FUN-668): Migrate this fully into types.FunctionsProvider type FunctionsProvider interface { - commontypes.FunctionsProvider + types.FunctionsProvider LogPollerWrapper() LogPollerWrapper } diff --git a/core/services/relay/evm/types/types_test.go b/core/services/relay/evm/types/types_test.go index dec368614ec..fb394ddf38b 100644 --- a/core/services/relay/evm/types/types_test.go +++ b/core/services/relay/evm/types/types_test.go @@ -8,11 +8,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) -// ChainID *utils.Big `json:"chainID"` +// ChainID *big.Big `json:"chainID"` // FromBlock uint64 `json:"fromBlock"` // // Contract-specific diff --git a/core/services/relay/grpc_provider_server_test.go b/core/services/relay/grpc_provider_server_test.go index 6aff32f5e32..72bbbca0f44 100644 --- a/core/services/relay/grpc_provider_server_test.go +++ b/core/services/relay/grpc_provider_server_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -17,7 +18,7 @@ func TestProviderServer(t *testing.T) { lggr := logger.TestLogger(t) _, err := NewProviderServer(mp, "unsupported-type", lggr) - require.Error(t, err) + require.ErrorContains(t, err, "unsupported-type") ps, err := NewProviderServer(staticMedianProvider{}, types.Median, lggr) require.NoError(t, err) diff --git a/core/services/relay/relay.go b/core/services/relay/relay.go index eb6d3faf4fd..826c3d17a44 100644 --- a/core/services/relay/relay.go +++ b/core/services/relay/relay.go @@ -12,19 +12,20 @@ import ( type Network = string type ChainID = string -var ( - EVM Network = "evm" - Cosmos Network = "cosmos" - Solana Network = "solana" - StarkNet Network = "starknet" - SupportedRelays = map[Network]struct{}{ - EVM: {}, - Cosmos: {}, - Solana: {}, - StarkNet: {}, - } +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 @@ -54,9 +55,9 @@ func (i *ID) UnmarshalString(s string) error { // ignore the `.` in the match by dropping last rune network := s[idxs[0] : idxs[1]-1] chainID := s[idxs[1]:] - newID := &ID{ChainID: ChainID(chainID)} + newID := &ID{ChainID: chainID} for n := range SupportedRelays { - if Network(network) == n { + if network == n { newID.Network = n break } @@ -88,7 +89,9 @@ func (r *ServerAdapter) NewPluginProvider(ctx context.Context, rargs types.Relay return r.NewFunctionsProvider(ctx, rargs, pargs) case types.Mercury: return r.NewMercuryProvider(ctx, rargs, pargs) - case types.DKG, types.OCR2VRF, types.OCR2Keeper, types.GenericPlugin: + case types.OCR2Keeper: + return r.NewAutomationProvider(ctx, rargs, pargs) + case types.DKG, types.OCR2VRF, types.GenericPlugin: return r.RelayerAdapter.NewPluginProvider(ctx, rargs, pargs) case types.CCIPCommit, types.CCIPExecution: return nil, fmt.Errorf("provider type not supported: %s", rargs.ProviderType) diff --git a/core/services/relay/relay_test.go b/core/services/relay/relay_test.go index 18a7b1b44ea..40a11518edd 100644 --- a/core/services/relay/relay_test.go +++ b/core/services/relay/relay_test.go @@ -10,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" ) @@ -96,6 +97,10 @@ type staticMercuryProvider struct { types.MercuryProvider } +type staticAutomationProvider struct { + types.AutomationProvider +} + type mockRelayer struct { types.Relayer } @@ -112,6 +117,10 @@ func (m *mockRelayer) NewMercuryProvider(rargs types.RelayArgs, pargs types.Plug return staticMercuryProvider{}, nil } +func (m *mockRelayer) NewAutomationProvider(rargs types.RelayArgs, pargs types.PluginArgs) (types.AutomationProvider, error) { + return staticAutomationProvider{}, nil +} + type mockRelayerExt struct { loop.RelayerExt } diff --git a/core/services/s4/address_range.go b/core/services/s4/address_range.go index 679bb3b846a..e7b60ecb479 100644 --- a/core/services/s4/address_range.go +++ b/core/services/s4/address_range.go @@ -5,23 +5,23 @@ import ( "errors" "math/big" - "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/ethereum/go-ethereum/common" + + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // AddressRange represents a range of Ethereum addresses. type AddressRange struct { // MinAddress (inclusive). - MinAddress *utils.Big + MinAddress *ubig.Big // MaxAddress (inclusive). - MaxAddress *utils.Big + MaxAddress *ubig.Big } var ( ErrInvalidIntervals = errors.New("invalid intervals value") - MinAddress = utils.NewBig(common.BytesToAddress(bytes.Repeat([]byte{0x00}, common.AddressLength)).Big()) - MaxAddress = utils.NewBig(common.BytesToAddress(bytes.Repeat([]byte{0xff}, common.AddressLength)).Big()) + MinAddress = ubig.New(common.BytesToAddress(bytes.Repeat([]byte{0x00}, common.AddressLength)).Big()) + MaxAddress = ubig.New(common.BytesToAddress(bytes.Repeat([]byte{0xff}, common.AddressLength)).Big()) ) // NewFullAddressRange creates AddressRange for all address space: 0x00..-0xFF.. @@ -33,7 +33,7 @@ func NewFullAddressRange() *AddressRange { } // NewSingleAddressRange creates AddressRange for a single address. -func NewSingleAddressRange(address *utils.Big) (*AddressRange, error) { +func NewSingleAddressRange(address *ubig.Big) (*AddressRange, error) { if address == nil || address.Cmp(MinAddress) < 0 || address.Cmp(MaxAddress) > 0 { return nil, errors.New("invalid address") } @@ -56,12 +56,12 @@ func NewInitialAddressRangeForIntervals(intervals uint) (*AddressRange, error) { } divisor := big.NewInt(int64(intervals)) - maxPlusOne := MaxAddress.Add(utils.NewBigI(1)) - interval := utils.NewBig(new(big.Int).Div(maxPlusOne.ToInt(), divisor)) + maxPlusOne := MaxAddress.Add(ubig.NewI(1)) + interval := ubig.New(new(big.Int).Div(maxPlusOne.ToInt(), divisor)) return &AddressRange{ MinAddress: MinAddress, - MaxAddress: MinAddress.Add(interval).Sub(utils.NewBigI(1)), + MaxAddress: MinAddress.Add(interval).Sub(ubig.NewI(1)), }, nil } @@ -80,7 +80,7 @@ func (r *AddressRange) Advance() { if r.MinAddress.Cmp(MaxAddress) >= 0 { r.MinAddress = MinAddress - r.MaxAddress = MinAddress.Add(interval).Sub(utils.NewBigI(1)) + r.MaxAddress = MinAddress.Add(interval).Sub(ubig.NewI(1)) } if r.MaxAddress.Cmp(MaxAddress) > 0 { @@ -89,7 +89,7 @@ func (r *AddressRange) Advance() { } // Contains returns true if the given address belongs to the range. -func (r *AddressRange) Contains(address *utils.Big) bool { +func (r *AddressRange) Contains(address *ubig.Big) bool { if r == nil { return false } @@ -97,9 +97,9 @@ func (r *AddressRange) Contains(address *utils.Big) bool { } // Interval returns the interval between max and min address plus one. -func (r *AddressRange) Interval() *utils.Big { +func (r *AddressRange) Interval() *ubig.Big { if r == nil { return nil } - return r.MaxAddress.Sub(r.MinAddress).Add(utils.NewBigI(1)) + return r.MaxAddress.Sub(r.MinAddress).Add(ubig.NewI(1)) } diff --git a/core/services/s4/address_range_test.go b/core/services/s4/address_range_test.go index bbd4d3baa54..2b12acd08eb 100644 --- a/core/services/s4/address_range_test.go +++ b/core/services/s4/address_range_test.go @@ -3,8 +3,8 @@ package s4_test import ( "testing" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/assert" ) @@ -26,7 +26,7 @@ func TestAddressRange_NewFullAddressRange(t *testing.T) { func TestAddressRange_NewSingleAddressRange(t *testing.T) { t.Parallel() - addr := utils.NewBigI(0x123) + addr := big.NewI(0x123) sar, err := s4.NewSingleAddressRange(addr) assert.NoError(t, err) assert.Equal(t, addr, sar.MinAddress) @@ -94,10 +94,10 @@ func TestAddressRange_Contains(t *testing.T) { assert.NoError(t, err) assert.True(t, r.Contains(r.MinAddress)) assert.True(t, r.Contains(r.MaxAddress)) - assert.False(t, r.Contains(r.MaxAddress.Add(utils.NewBigI(1)))) + assert.False(t, r.Contains(r.MaxAddress.Add(big.NewI(1)))) r.Advance() assert.True(t, r.Contains(r.MinAddress)) assert.True(t, r.Contains(r.MaxAddress)) - assert.False(t, r.Contains(r.MinAddress.Sub(utils.NewBigI(1)))) + assert.False(t, r.Contains(r.MinAddress.Sub(big.NewI(1)))) } diff --git a/core/services/s4/in_memory_orm.go b/core/services/s4/in_memory_orm.go index bb67d2d63a4..28b50ce430c 100644 --- a/core/services/s4/in_memory_orm.go +++ b/core/services/s4/in_memory_orm.go @@ -5,8 +5,8 @@ import ( "sync" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type key struct { @@ -32,7 +32,7 @@ func NewInMemoryORM() ORM { } } -func (o *inMemoryOrm) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) { +func (o *inMemoryOrm) Get(address *big.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) { o.mu.RLock() defer o.mu.RUnlock() @@ -103,7 +103,7 @@ func (o *inMemoryOrm) GetSnapshot(addressRange *AddressRange, qopts ...pg.QOpt) for _, mrow := range o.rows { if mrow.Row.Expiration > now { rows = append(rows, &SnapshotRow{ - Address: utils.NewBig(mrow.Row.Address.ToInt()), + Address: big.New(mrow.Row.Address.ToInt()), SlotId: mrow.Row.SlotId, Version: mrow.Row.Version, Expiration: mrow.Row.Expiration, diff --git a/core/services/s4/in_memory_orm_test.go b/core/services/s4/in_memory_orm_test.go index 68bff00634f..318db5f1a44 100644 --- a/core/services/s4/in_memory_orm_test.go +++ b/core/services/s4/in_memory_orm_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" @@ -21,7 +21,7 @@ func TestInMemoryORM(t *testing.T) { signature := testutils.Random32Byte() expiration := time.Now().Add(time.Minute).UnixMilli() row := &s4.Row{ - Address: utils.NewBig(address.Big()), + Address: big.New(address.Big()), SlotId: slotId, Payload: payload[:], Version: 3, @@ -33,7 +33,7 @@ func TestInMemoryORM(t *testing.T) { orm := s4.NewInMemoryORM() t.Run("row not found", func(t *testing.T) { - _, err := orm.Get(utils.NewBig(address.Big()), slotId) + _, err := orm.Get(big.New(address.Big()), slotId) assert.ErrorIs(t, err, s4.ErrNotFound) }) @@ -41,7 +41,7 @@ func TestInMemoryORM(t *testing.T) { err := orm.Update(row) assert.NoError(t, err) - e, err := orm.Get(utils.NewBig(address.Big()), slotId) + e, err := orm.Get(big.New(address.Big()), slotId) assert.NoError(t, err) assert.Equal(t, row, e) }) @@ -59,7 +59,7 @@ func TestInMemoryORM(t *testing.T) { err = orm.Update(row) assert.NoError(t, err) - e, err := orm.Get(utils.NewBig(address.Big()), slotId) + e, err := orm.Get(big.New(address.Big()), slotId) assert.NoError(t, err) assert.Equal(t, row, e) }) @@ -76,7 +76,7 @@ func TestInMemoryORM_DeleteExpired(t *testing.T) { thisAddress[0] = byte(i) row := &s4.Row{ - Address: utils.NewBig(thisAddress.Big()), + Address: big.New(thisAddress.Big()), SlotId: 1, Payload: []byte{}, Version: 1, @@ -109,7 +109,7 @@ func TestInMemoryORM_GetUnconfirmedRows(t *testing.T) { thisAddress[0] = byte(i) row := &s4.Row{ - Address: utils.NewBig(thisAddress.Big()), + Address: big.New(thisAddress.Big()), SlotId: 1, Payload: []byte{}, Version: 1, @@ -139,7 +139,7 @@ func TestInMemoryORM_GetSnapshot(t *testing.T) { thisAddress[0] = byte(i) row := &s4.Row{ - Address: utils.NewBig(thisAddress.Big()), + Address: big.New(thisAddress.Big()), SlotId: 1, Payload: []byte{}, Version: uint64(i), diff --git a/core/services/s4/mocks/orm.go b/core/services/s4/mocks/orm.go index f053af9ca7b..3b8cac8e76d 100644 --- a/core/services/s4/mocks/orm.go +++ b/core/services/s4/mocks/orm.go @@ -1,15 +1,16 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks import ( + big "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + mock "github.com/stretchr/testify/mock" + pg "github.com/smartcontractkit/chainlink/v2/core/services/pg" + s4 "github.com/smartcontractkit/chainlink/v2/core/services/s4" - mock "github.com/stretchr/testify/mock" time "time" - - utils "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ORM is an autogenerated mock type for the ORM type @@ -28,6 +29,10 @@ func (_m *ORM) DeleteExpired(limit uint, utcNow time.Time, qopts ...pg.QOpt) (in _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for DeleteExpired") + } + var r0 int64 var r1 error if rf, ok := ret.Get(0).(func(uint, time.Time, ...pg.QOpt) (int64, error)); ok { @@ -49,7 +54,7 @@ func (_m *ORM) DeleteExpired(limit uint, utcNow time.Time, qopts ...pg.QOpt) (in } // Get provides a mock function with given fields: address, slotId, qopts -func (_m *ORM) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*s4.Row, error) { +func (_m *ORM) Get(address *big.Big, slotId uint, qopts ...pg.QOpt) (*s4.Row, error) { _va := make([]interface{}, len(qopts)) for _i := range qopts { _va[_i] = qopts[_i] @@ -59,12 +64,16 @@ func (_m *ORM) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*s4.Row, _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 *s4.Row var r1 error - if rf, ok := ret.Get(0).(func(*utils.Big, uint, ...pg.QOpt) (*s4.Row, error)); ok { + if rf, ok := ret.Get(0).(func(*big.Big, uint, ...pg.QOpt) (*s4.Row, error)); ok { return rf(address, slotId, qopts...) } - if rf, ok := ret.Get(0).(func(*utils.Big, uint, ...pg.QOpt) *s4.Row); ok { + if rf, ok := ret.Get(0).(func(*big.Big, uint, ...pg.QOpt) *s4.Row); ok { r0 = rf(address, slotId, qopts...) } else { if ret.Get(0) != nil { @@ -72,7 +81,7 @@ func (_m *ORM) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*s4.Row, } } - if rf, ok := ret.Get(1).(func(*utils.Big, uint, ...pg.QOpt) error); ok { + if rf, ok := ret.Get(1).(func(*big.Big, uint, ...pg.QOpt) error); ok { r1 = rf(address, slotId, qopts...) } else { r1 = ret.Error(1) @@ -92,6 +101,10 @@ func (_m *ORM) GetSnapshot(addressRange *s4.AddressRange, qopts ...pg.QOpt) ([]* _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetSnapshot") + } + var r0 []*s4.SnapshotRow var r1 error if rf, ok := ret.Get(0).(func(*s4.AddressRange, ...pg.QOpt) ([]*s4.SnapshotRow, error)); ok { @@ -125,6 +138,10 @@ func (_m *ORM) GetUnconfirmedRows(limit uint, qopts ...pg.QOpt) ([]*s4.Row, erro _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for GetUnconfirmedRows") + } + var r0 []*s4.Row var r1 error if rf, ok := ret.Get(0).(func(uint, ...pg.QOpt) ([]*s4.Row, error)); ok { @@ -158,6 +175,10 @@ func (_m *ORM) Update(row *s4.Row, qopts ...pg.QOpt) error { _ca = append(_ca, _va...) ret := _m.Called(_ca...) + if len(ret) == 0 { + panic("no return value specified for Update") + } + var r0 error if rf, ok := ret.Get(0).(func(*s4.Row, ...pg.QOpt) error); ok { r0 = rf(row, qopts...) diff --git a/core/services/s4/mocks/storage.go b/core/services/s4/mocks/storage.go index f4174f171b8..06fc153a358 100644 --- a/core/services/s4/mocks/storage.go +++ b/core/services/s4/mocks/storage.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -21,6 +21,10 @@ type Storage struct { func (_m *Storage) Constraints() s4.Constraints { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Constraints") + } + var r0 s4.Constraints if rf, ok := ret.Get(0).(func() s4.Constraints); ok { r0 = rf() @@ -35,6 +39,10 @@ func (_m *Storage) Constraints() s4.Constraints { func (_m *Storage) Get(ctx context.Context, key *s4.Key) (*s4.Record, *s4.Metadata, error) { ret := _m.Called(ctx, key) + if len(ret) == 0 { + panic("no return value specified for Get") + } + var r0 *s4.Record var r1 *s4.Metadata var r2 error @@ -70,6 +78,10 @@ func (_m *Storage) Get(ctx context.Context, key *s4.Key) (*s4.Record, *s4.Metada func (_m *Storage) List(ctx context.Context, address common.Address) ([]*s4.SnapshotRow, error) { ret := _m.Called(ctx, address) + if len(ret) == 0 { + panic("no return value specified for List") + } + var r0 []*s4.SnapshotRow var r1 error if rf, ok := ret.Get(0).(func(context.Context, common.Address) ([]*s4.SnapshotRow, error)); ok { @@ -96,6 +108,10 @@ func (_m *Storage) List(ctx context.Context, address common.Address) ([]*s4.Snap func (_m *Storage) Put(ctx context.Context, key *s4.Key, record *s4.Record, signature []byte) error { ret := _m.Called(ctx, key, record, signature) + if len(ret) == 0 { + panic("no return value specified for Put") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context, *s4.Key, *s4.Record, []byte) error); ok { r0 = rf(ctx, key, record, signature) diff --git a/core/services/s4/orm.go b/core/services/s4/orm.go index 1e0227b1191..4d3cee9312a 100644 --- a/core/services/s4/orm.go +++ b/core/services/s4/orm.go @@ -3,13 +3,13 @@ package s4 import ( "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Row represents a data row persisted by ORM. type Row struct { - Address *utils.Big + Address *big.Big SlotId uint Payload []byte Version uint64 @@ -20,11 +20,12 @@ type Row struct { // SnapshotRow(s) are returned by GetSnapshot function. type SnapshotRow struct { - Address *utils.Big - SlotId uint - Version uint64 - Expiration int64 - Confirmed bool + Address *big.Big + SlotId uint + Version uint64 + Expiration int64 + Confirmed bool + PayloadSize uint64 } //go:generate mockery --quiet --name ORM --output ./mocks/ --case=underscore @@ -35,7 +36,7 @@ type ORM interface { // Get reads a row for the given address and slotId combination. // If such row does not exist, ErrNotFound is returned. // There is no filter on Expiration. - Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) + Get(address *big.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) // Update inserts or updates the row identified by (Address, SlotId) pair. // When updating, the new row must have greater or equal version, @@ -59,7 +60,7 @@ type ORM interface { func (r Row) Clone() *Row { clone := Row{ - Address: utils.NewBig(r.Address.ToInt()), + Address: big.New(r.Address.ToInt()), SlotId: r.SlotId, Payload: make([]byte, len(r.Payload)), Version: r.Version, diff --git a/core/services/s4/postgres_orm.go b/core/services/s4/postgres_orm.go index 1f91270fd08..1f92f2e1281 100644 --- a/core/services/s4/postgres_orm.go +++ b/core/services/s4/postgres_orm.go @@ -5,9 +5,9 @@ import ( "fmt" "time" + "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" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/jmoiron/sqlx" "github.com/pkg/errors" @@ -34,7 +34,7 @@ func NewPostgresORM(db *sqlx.DB, lggr logger.Logger, cfg pg.QConfig, tableName, } } -func (o orm) Get(address *utils.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) { +func (o orm) Get(address *big.Big, slotId uint, qopts ...pg.QOpt) (*Row, error) { row := &Row{} q := o.q.WithOpts(qopts...) @@ -90,7 +90,7 @@ func (o orm) GetSnapshot(addressRange *AddressRange, qopts ...pg.QOpt) ([]*Snaps q := o.q.WithOpts(qopts...) rows := make([]*SnapshotRow, 0) - stmt := fmt.Sprintf(`SELECT address, slot_id, version, expiration, confirmed FROM %s WHERE namespace = $1 AND address >= $2 AND address <= $3;`, o.tableName) + stmt := fmt.Sprintf(`SELECT address, slot_id, version, expiration, confirmed, octet_length(payload) AS payload_size FROM %s WHERE namespace = $1 AND address >= $2 AND address <= $3;`, o.tableName) if err := q.Select(&rows, stmt, o.namespace, addressRange.MinAddress, addressRange.MaxAddress); err != nil { if !errors.Is(err, sql.ErrNoRows) { return nil, err diff --git a/core/services/s4/postgres_orm_test.go b/core/services/s4/postgres_orm_test.go index c233fe2361a..d26f082ce5b 100644 --- a/core/services/s4/postgres_orm_test.go +++ b/core/services/s4/postgres_orm_test.go @@ -6,12 +6,12 @@ import ( "testing" "time" + "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/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/s4" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/stretchr/testify/assert" ) @@ -36,7 +36,7 @@ func generateTestRows(t *testing.T, n int) []*s4.Row { rows := make([]*s4.Row, n) for i := 0; i < n; i++ { row := &s4.Row{ - Address: utils.NewBig(testutils.NewAddress().Big()), + Address: big.New(testutils.NewAddress().Big()), SlotId: 1, Payload: cltest.MustRandomBytes(t, 32), Version: 1 + uint64(i), @@ -181,6 +181,7 @@ func TestPostgresORM_GetSnapshot(t *testing.T) { assert.Equal(t, snapshotRow.Version, sr.Version) assert.Equal(t, snapshotRow.Expiration, sr.Expiration) assert.Equal(t, snapshotRow.Confirmed, sr.Confirmed) + assert.Equal(t, snapshotRow.PayloadSize, uint64(len(sr.Payload))) } }) diff --git a/core/services/s4/storage.go b/core/services/s4/storage.go index 65aa2f4bab5..7c9a92d1f68 100644 --- a/core/services/s4/storage.go +++ b/core/services/s4/storage.go @@ -3,6 +3,7 @@ package s4 import ( "context" + "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" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -92,7 +93,7 @@ func (s *storage) Get(ctx context.Context, key *Key) (*Record, *Metadata, error) return nil, nil, ErrSlotIdTooBig } - bigAddress := utils.NewBig(key.Address.Big()) + bigAddress := big.New(key.Address.Big()) row, err := s.orm.Get(bigAddress, key.SlotId, pg.WithParentCtx(ctx)) if err != nil { return nil, nil, err @@ -118,7 +119,7 @@ func (s *storage) Get(ctx context.Context, key *Key) (*Record, *Metadata, error) } func (s *storage) List(ctx context.Context, address common.Address) ([]*SnapshotRow, error) { - bigAddress := utils.NewBig(address.Big()) + bigAddress := big.New(address.Big()) sar, err := NewSingleAddressRange(bigAddress) if err != nil { return nil, err @@ -148,7 +149,7 @@ func (s *storage) Put(ctx context.Context, key *Key, record *Record, signature [ } row := &Row{ - Address: utils.NewBig(key.Address.Big()), + Address: big.New(key.Address.Big()), SlotId: key.SlotId, Payload: make([]byte, len(record.Payload)), Version: key.Version, diff --git a/core/services/s4/storage_test.go b/core/services/s4/storage_test.go index 11a8f6544ce..199e3e6924b 100644 --- a/core/services/s4/storage_test.go +++ b/core/services/s4/storage_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/s4" @@ -51,7 +52,7 @@ func TestStorage_Errors(t *testing.T) { SlotId: 1, Version: 0, } - ormMock.On("Get", utils.NewBig(key.Address.Big()), uint(key.SlotId), mock.Anything).Return(nil, s4.ErrNotFound) + ormMock.On("Get", big.New(key.Address.Big()), key.SlotId, mock.Anything).Return(nil, s4.ErrNotFound) _, _, err := storage.Get(testutils.Context(t), key) assert.ErrorIs(t, err, s4.ErrNotFound) }) @@ -179,8 +180,8 @@ func TestStorage_PutAndGet(t *testing.T) { assert.NoError(t, err) ormMock.On("Update", mock.Anything, mock.Anything).Return(nil) - ormMock.On("Get", utils.NewBig(key.Address.Big()), uint(2), mock.Anything).Return(&s4.Row{ - Address: utils.NewBig(key.Address.Big()), + ormMock.On("Get", big.New(key.Address.Big()), uint(2), mock.Anything).Return(&s4.Row{ + Address: big.New(key.Address.Big()), SlotId: key.SlotId, Version: key.Version, Payload: record.Payload, @@ -217,7 +218,7 @@ func TestStorage_List(t *testing.T) { }, } - addressRange, err := s4.NewSingleAddressRange(utils.NewBig(address.Big())) + addressRange, err := s4.NewSingleAddressRange(big.New(address.Big())) assert.NoError(t, err) ormMock.On("GetSnapshot", addressRange, mock.Anything).Return(ormRows, nil) diff --git a/core/services/signatures/secp256k1/curve.go b/core/services/signatures/secp256k1/curve.go index 2ed52a87cec..70187e68738 100644 --- a/core/services/signatures/secp256k1/curve.go +++ b/core/services/signatures/secp256k1/curve.go @@ -12,7 +12,7 @@ package secp256k1 import ( "math/big" - secp256k1BTCD "github.com/btcsuite/btcd/btcec" + secp256k1BTCD "github.com/btcsuite/btcd/btcec/v2" "go.dedis.ch/kyber/v3" ) diff --git a/core/services/signatures/secp256k1/field.go b/core/services/signatures/secp256k1/field.go index 7cfa7af2e5c..bf9652e5dbd 100644 --- a/core/services/signatures/secp256k1/field.go +++ b/core/services/signatures/secp256k1/field.go @@ -49,7 +49,7 @@ func (f *fieldElt) modQ() *fieldElt { func fieldEltFromBigInt(v *big.Int) *fieldElt { return (*fieldElt)(v).modQ() } func fieldEltFromInt(v int64) *fieldElt { - return fieldEltFromBigInt(big.NewInt(int64(v))).modQ() + return fieldEltFromBigInt(big.NewInt(v)).modQ() } var fieldZero = fieldEltFromInt(0) @@ -137,13 +137,11 @@ func fieldSquare(y *fieldElt) *fieldElt { return fieldEltFromBigInt(newFieldZero().int().Exp(y.int(), two, q)) } +func i() *big.Int { return new(big.Int) } + // sqrtPower is s.t. n^sqrtPower≡sqrt(n) mod q, if n has a root at all. See // https://math.stackexchange.com/a/1816280, for instance -// -// What I'm calling sqrtPower is called q on the s256 struct. (See -// btcec.initS256), which is confusing because the "Q" in "QPlus1Div4" refers to -// the field characteristic -var sqrtPower = s256.QPlus1Div4() +var sqrtPower = i().Rsh(i().Add(q, big.NewInt(1)), 2) // (q +1)/4 // maybeSqrtInField returns a square root of v, if it has any, else nil func maybeSqrtInField(v *fieldElt) *fieldElt { diff --git a/core/services/signatures/secp256k1/public_key.go b/core/services/signatures/secp256k1/public_key.go index 1f7fd9c0ebd..c39565984ae 100644 --- a/core/services/signatures/secp256k1/public_key.go +++ b/core/services/signatures/secp256k1/public_key.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "go.dedis.ch/kyber/v3" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) // PublicKey is a secp256k1 point in compressed format diff --git a/core/services/signatures/secp256k1/scalar.go b/core/services/signatures/secp256k1/scalar.go index 9d89188c4c7..d12826a8270 100644 --- a/core/services/signatures/secp256k1/scalar.go +++ b/core/services/signatures/secp256k1/scalar.go @@ -19,7 +19,7 @@ import ( "io" "math/big" - secp256k1BTCD "github.com/btcsuite/btcd/btcec" + secp256k1BTCD "github.com/btcsuite/btcd/btcec/v2" "github.com/ethereum/go-ethereum/common" "go.dedis.ch/kyber/v3" diff --git a/core/services/srvctest/servicetest.go b/core/services/srvctest/servicetest.go deleted file mode 100644 index ee888a46fa6..00000000000 --- a/core/services/srvctest/servicetest.go +++ /dev/null @@ -1,18 +0,0 @@ -package srvctest - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services" -) - -// Start is test helper to automatically Start/Close a ServiceCtx along with a test. -func Start[S services.ServiceCtx](tb testing.TB, s S) S { - require.NoError(tb, s.Start(testutils.Context(tb))) - tb.Cleanup(func() { assert.NoError(tb, s.Close()) }) - return s -} diff --git a/core/services/streams/delegate.go b/core/services/streams/delegate.go new file mode 100644 index 00000000000..b62ceb9857b --- /dev/null +++ b/core/services/streams/delegate.go @@ -0,0 +1,110 @@ +package streams + +import ( + "context" + "fmt" + "strings" + + "github.com/google/uuid" + "github.com/pelletier/go-toml/v2" + "github.com/pkg/errors" + + "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" +) + +type DelegateConfig interface { + MaxSuccessfulRuns() uint64 + ResultWriteQueueDepth() uint64 +} + +type Delegate struct { + lggr logger.Logger + registry Registry + runner ocrcommon.Runner + cfg DelegateConfig +} + +var _ job.Delegate = (*Delegate)(nil) + +func NewDelegate(lggr logger.Logger, registry Registry, runner ocrcommon.Runner, cfg DelegateConfig) *Delegate { + return &Delegate{lggr, registry, runner, cfg} +} + +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(jb job.Job, q pg.Queryer) error { return nil } + +func (d *Delegate) ServicesForSpec(jb job.Job) (services []job.ServiceCtx, err error) { + if !jb.Name.Valid { + return nil, errors.New("job name is required to be present for stream specs") + } + id := jb.Name.String + lggr := d.lggr.Named(id).With("streamID", id) + + rrs := ocrcommon.NewResultRunSaver(d.runner, lggr, d.cfg.MaxSuccessfulRuns(), d.cfg.ResultWriteQueueDepth()) + services = append(services, rrs, &StreamService{ + d.registry, + id, + jb.PipelineSpec, + lggr, + rrs, + }) + return services, nil +} + +type ResultRunSaver interface { + Save(run *pipeline.Run) +} + +type StreamService struct { + registry Registry + id StreamID + spec *pipeline.Spec + lggr logger.Logger + rrs ResultRunSaver +} + +func (s *StreamService) Start(_ context.Context) error { + if s.spec == nil { + return fmt.Errorf("pipeline spec unexpectedly missing for stream %q", s.id) + } + s.lggr.Debugf("Starting stream %q", s.id) + return s.registry.Register(s.id, *s.spec, s.rrs) +} + +func (s *StreamService) Close() error { + s.lggr.Debugf("Stopping stream %q", s.id) + s.registry.Unregister(s.id) + return nil +} + +func ValidatedStreamSpec(tomlString string) (job.Job, error) { + var jb = job.Job{ExternalJobID: uuid.New()} + + r := strings.NewReader(tomlString) + d := toml.NewDecoder(r) + d.DisallowUnknownFields() + err := d.Decode(&jb) + if err != nil { + return jb, errors.Wrap(err, "toml unmarshal error on job") + } + + if jb.Type != job.Stream { + return jb, errors.Errorf("unsupported type: %q", jb.Type) + } + + if !jb.Name.Valid { + return jb, errors.New("jobs of type 'stream' require a non-blank name as stream ID") + } + + return jb, nil +} diff --git a/core/services/streams/delegate_test.go b/core/services/streams/delegate_test.go new file mode 100644 index 00000000000..77b10260375 --- /dev/null +++ b/core/services/streams/delegate_test.go @@ -0,0 +1,161 @@ +package streams + +import ( + "testing" + + "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/pipeline" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/guregu/null.v4" +) + +type mockRegistry struct{} + +func (m *mockRegistry) Get(streamID StreamID) (strm Stream, exists bool) { return } +func (m *mockRegistry) Register(streamID StreamID, spec pipeline.Spec, rrs ResultRunSaver) error { + return nil +} +func (m *mockRegistry) Unregister(streamID StreamID) {} + +type mockDelegateConfig struct{} + +func (m *mockDelegateConfig) MaxSuccessfulRuns() uint64 { return 0 } +func (m *mockDelegateConfig) ResultWriteQueueDepth() uint64 { return 0 } + +func Test_Delegate(t *testing.T) { + lggr := logger.TestLogger(t) + registry := &mockRegistry{} + runner := &mockRunner{} + cfg := &mockDelegateConfig{} + d := NewDelegate(lggr, registry, runner, cfg) + + t.Run("ServicesForSpec", func(t *testing.T) { + jb := job.Job{PipelineSpec: &pipeline.Spec{ID: 1}} + t.Run("errors if job is missing name", func(t *testing.T) { + _, err := d.ServicesForSpec(jb) + assert.EqualError(t, err, "job name is required to be present for stream specs") + }) + jb.Name = null.StringFrom("jobname") + t.Run("returns services", func(t *testing.T) { + srvs, err := d.ServicesForSpec(jb) + require.NoError(t, err) + + assert.Len(t, srvs, 2) + assert.IsType(t, &ocrcommon.RunResultSaver{}, srvs[0]) + + strmSrv := srvs[1].(*StreamService) + assert.Equal(t, registry, strmSrv.registry) + assert.Equal(t, StreamID("jobname"), strmSrv.id) + assert.Equal(t, jb.PipelineSpec, strmSrv.spec) + assert.NotNil(t, strmSrv.lggr) + assert.Equal(t, srvs[0], strmSrv.rrs) + }) + }) +} + +func Test_ValidatedStreamSpec(t *testing.T) { + var tt = []struct { + name string + toml string + assertion func(t *testing.T, os job.Job, err error) + }{ + { + name: "minimal stream spec", + toml: ` +type = "stream" +name = "voter-turnout" +schemaVersion = 1 +observationSource = """ +ds1 [type=bridge name=voter_turnout]; +ds1_parse [type=jsonparse path="one,two"]; +ds1_multiply [type=multiply times=1.23]; +ds1 -> ds1_parse -> ds1_multiply -> answer1; +answer1 [type=median index=0]; +""" +`, + assertion: func(t *testing.T, jb job.Job, err error) { + require.NoError(t, err) + assert.Equal(t, job.Type("stream"), jb.Type) + assert.Equal(t, uint32(1), jb.SchemaVersion) + assert.True(t, jb.Name.Valid) + assert.Equal(t, "voter-turnout", jb.Name.String) + }, + }, + { + name: "unparseable toml", + toml: `not toml`, + assertion: func(t *testing.T, jb job.Job, err error) { + assert.EqualError(t, err, "toml unmarshal error on job: toml: expected character =") + }, + }, + { + name: "invalid field type", + toml: ` +type = "stream" +name = "voter-turnout" +schemaVersion = "should be integer" +`, + assertion: func(t *testing.T, jb job.Job, err error) { + assert.EqualError(t, err, "toml unmarshal error on job: toml: cannot decode TOML string into struct field job.Job.SchemaVersion of type uint32") + }, + }, + { + name: "invalid fields", + toml: ` +type = "stream" +name = "voter-turnout" +notAValidField = "some value" +schemaVersion = 1 +`, + assertion: func(t *testing.T, jb job.Job, err error) { + assert.EqualError(t, err, "toml unmarshal error on job: strict mode: fields in the document are missing in the target struct") + }, + }, + { + name: "wrong type", + toml: ` +type = "not a valid type" +name = "voter-turnout" +schemaVersion = 1 +observationSource = """ +ds1 [type=bridge name=voter_turnout]; +ds1_parse [type=jsonparse path="one,two"]; +ds1_multiply [type=multiply times=1.23]; +ds1 -> ds1_parse -> ds1_multiply -> answer1; +answer1 [type=median index=0]; +""" +`, + assertion: func(t *testing.T, jb job.Job, err error) { + assert.EqualError(t, err, "unsupported type: \"not a valid type\"") + }, + }, + { + name: "error if missing name", + toml: ` +type = "stream" +schemaVersion = 1 +observationSource = """ +ds1 [type=bridge name=voter_turnout]; +ds1_parse [type=jsonparse path="one,two"]; +ds1_multiply [type=multiply times=1.23]; +ds1 -> ds1_parse -> ds1_multiply -> answer1; +answer1 [type=median index=0]; +""" +`, + assertion: func(t *testing.T, jb job.Job, err error) { + assert.EqualError(t, err, "jobs of type 'stream' require a non-blank name as stream ID") + }, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + s, err := ValidatedStreamSpec(tc.toml) + tc.assertion(t, s, err) + }) + } +} diff --git a/core/services/streams/stream.go b/core/services/streams/stream.go new file mode 100644 index 00000000000..51535a0cb86 --- /dev/null +++ b/core/services/streams/stream.go @@ -0,0 +1,133 @@ +package streams + +import ( + "context" + "fmt" + "math/big" + "sync" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type Runner interface { + ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error) + InitializePipeline(spec pipeline.Spec) (*pipeline.Pipeline, error) +} + +type RunResultSaver interface { + Save(run *pipeline.Run) +} + +type Stream interface { + Run(ctx context.Context) (*pipeline.Run, pipeline.TaskRunResults, error) +} + +type stream struct { + sync.RWMutex + id StreamID + lggr logger.Logger + spec *pipeline.Spec + runner Runner + rrs RunResultSaver +} + +func NewStream(lggr logger.Logger, id StreamID, spec pipeline.Spec, runner Runner, rrs RunResultSaver) Stream { + return newStream(lggr, id, spec, runner, rrs) +} + +func newStream(lggr logger.Logger, id StreamID, spec pipeline.Spec, runner Runner, rrs RunResultSaver) *stream { + return &stream{sync.RWMutex{}, id, lggr.Named("Stream").With("streamID", id), &spec, runner, rrs} +} + +func (s *stream) Run(ctx context.Context) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error) { + run, trrs, err = s.executeRun(ctx) + + if err != nil { + return nil, nil, fmt.Errorf("Run failed: %w", err) + } + if s.rrs != nil { + s.rrs.Save(run) + } + + return +} + +// The context passed in here has a timeout of (ObservationTimeout + ObservationGracePeriod). +// Upon context cancellation, its expected that we return any usable values within ObservationGracePeriod. +func (s *stream) executeRun(ctx context.Context) (*pipeline.Run, pipeline.TaskRunResults, error) { + // the hot path here is to avoid parsing and use the pre-parsed, cached, pipeline + s.RLock() + initialize := s.spec.Pipeline == nil + s.RUnlock() + if initialize { + pipeline, err := s.spec.ParsePipeline() + if err != nil { + return nil, nil, fmt.Errorf("Run failed due to unparseable pipeline: %w", err) + } + + s.Lock() + if s.spec.Pipeline == nil { + s.spec.Pipeline = pipeline + // initialize it for the given runner + if _, err := s.runner.InitializePipeline(*s.spec); err != nil { + return nil, nil, fmt.Errorf("Run failed due to error while initializing pipeline: %w", err) + } + } + s.Unlock() + } + + vars := pipeline.NewVarsFrom(map[string]interface{}{ + "pipelineSpec": map[string]interface{}{ + "id": s.spec.ID, + }, + "stream": map[string]interface{}{ + "id": s.id, + }, + }) + + run, trrs, err := s.runner.ExecuteRun(ctx, *s.spec, vars, s.lggr) + if err != nil { + return nil, nil, fmt.Errorf("error executing run for spec ID %v: %w", s.spec.ID, err) + } + + return run, trrs, err +} + +// ExtractBigInt returns a result of a pipeline run that returns one single +// decimal result, as a *big.Int. +// This acts as a reference/example method, other methods can be implemented to +// extract any desired type that matches a particular pipeline run output. +// Returns error on parse errors: if results are wrong type +func ExtractBigInt(trrs pipeline.TaskRunResults) (*big.Int, error) { + var finaltrrs []pipeline.TaskRunResult + // pipeline.TaskRunResults comes ordered asc by index, this is guaranteed + // by the pipeline executor + for _, trr := range trrs { + if trr.IsTerminal() { + finaltrrs = append(finaltrrs, trr) + } + } + + if len(finaltrrs) != 1 { + return nil, fmt.Errorf("invalid number of results, expected: 1, got: %d", len(finaltrrs)) + } + res := finaltrrs[0].Result + if res.Error != nil { + return nil, res.Error + } + val, err := toBigInt(res.Value) + if err != nil { + return nil, fmt.Errorf("failed to parse BenchmarkPrice: %w", err) + } + return val, nil +} + +func toBigInt(val interface{}) (*big.Int, error) { + dec, err := utils.ToDecimal(val) + if err != nil { + return nil, err + } + return dec.BigInt(), nil +} diff --git a/core/services/streams/stream_registry.go b/core/services/streams/stream_registry.go new file mode 100644 index 00000000000..c79c6c4e043 --- /dev/null +++ b/core/services/streams/stream_registry.go @@ -0,0 +1,60 @@ +package streams + +import ( + "fmt" + "sync" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" +) + +type StreamID = string + +type Registry interface { + Get(streamID StreamID) (strm Stream, exists bool) + Register(streamID StreamID, spec pipeline.Spec, rrs ResultRunSaver) error + Unregister(streamID StreamID) +} + +type streamRegistry struct { + sync.RWMutex + lggr logger.Logger + runner Runner + streams map[StreamID]Stream +} + +func NewRegistry(lggr logger.Logger, runner Runner) Registry { + return newRegistry(lggr, runner) +} + +func newRegistry(lggr logger.Logger, runner Runner) *streamRegistry { + return &streamRegistry{ + sync.RWMutex{}, + lggr.Named("Registry"), + runner, + make(map[StreamID]Stream), + } +} + +func (s *streamRegistry) Get(streamID StreamID) (strm Stream, exists bool) { + s.RLock() + defer s.RUnlock() + strm, exists = s.streams[streamID] + return +} + +func (s *streamRegistry) Register(streamID StreamID, spec pipeline.Spec, rrs ResultRunSaver) error { + s.Lock() + defer s.Unlock() + if _, exists := s.streams[streamID]; exists { + return fmt.Errorf("stream already registered for id: %q", streamID) + } + s.streams[streamID] = NewStream(s.lggr, streamID, spec, s.runner, rrs) + return nil +} + +func (s *streamRegistry) Unregister(streamID StreamID) { + s.Lock() + defer s.Unlock() + delete(s.streams, streamID) +} diff --git a/core/services/streams/stream_registry_test.go b/core/services/streams/stream_registry_test.go new file mode 100644 index 00000000000..2c7c2bd6ecc --- /dev/null +++ b/core/services/streams/stream_registry_test.go @@ -0,0 +1,107 @@ +package streams + +import ( + "context" + "testing" + + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type mockStream struct { + run *pipeline.Run + trrs pipeline.TaskRunResults + err error +} + +func (m *mockStream) Run(ctx context.Context) (*pipeline.Run, pipeline.TaskRunResults, error) { + return m.run, m.trrs, m.err +} + +func Test_Registry(t *testing.T) { + lggr := logger.TestLogger(t) + runner := &mockRunner{} + + t.Run("Get", func(t *testing.T) { + sr := newRegistry(lggr, runner) + + sr.streams["foo"] = &mockStream{run: &pipeline.Run{ID: 1}} + sr.streams["bar"] = &mockStream{run: &pipeline.Run{ID: 2}} + sr.streams["baz"] = &mockStream{run: &pipeline.Run{ID: 3}} + + v, exists := sr.Get("foo") + assert.True(t, exists) + assert.Equal(t, sr.streams["foo"], v) + + v, exists = sr.Get("bar") + assert.True(t, exists) + assert.Equal(t, sr.streams["bar"], v) + + v, exists = sr.Get("baz") + assert.True(t, exists) + assert.Equal(t, sr.streams["baz"], v) + + v, exists = sr.Get("qux") + assert.Nil(t, v) + assert.False(t, exists) + }) + t.Run("Register", func(t *testing.T) { + sr := newRegistry(lggr, runner) + + t.Run("registers new stream", func(t *testing.T) { + assert.Len(t, sr.streams, 0) + err := sr.Register("foo", pipeline.Spec{ID: 32, DotDagSource: "source"}, nil) + require.NoError(t, err) + assert.Len(t, sr.streams, 1) + + v, exists := sr.Get("foo") + require.True(t, exists) + strm := v.(*stream) + assert.Equal(t, StreamID("foo"), strm.id) + assert.Equal(t, int32(32), strm.spec.ID) + }) + + t.Run("errors when attempt to re-register a stream with an existing ID", func(t *testing.T) { + assert.Len(t, sr.streams, 1) + err := sr.Register("foo", pipeline.Spec{ID: 33, DotDagSource: "source"}, nil) + require.Error(t, err) + assert.Len(t, sr.streams, 1) + assert.EqualError(t, err, "stream already registered for id: \"foo\"") + + v, exists := sr.Get("foo") + require.True(t, exists) + strm := v.(*stream) + assert.Equal(t, StreamID("foo"), strm.id) + assert.Equal(t, int32(32), strm.spec.ID) + }) + }) + t.Run("Unregister", func(t *testing.T) { + sr := newRegistry(lggr, runner) + + sr.streams["foo"] = &mockStream{run: &pipeline.Run{ID: 1}} + sr.streams["bar"] = &mockStream{run: &pipeline.Run{ID: 2}} + sr.streams["baz"] = &mockStream{run: &pipeline.Run{ID: 3}} + + t.Run("unregisters a stream", func(t *testing.T) { + assert.Len(t, sr.streams, 3) + + sr.Unregister("foo") + + assert.Len(t, sr.streams, 2) + _, exists := sr.streams["foo"] + assert.False(t, exists) + }) + t.Run("no effect when unregistering a non-existent stream", func(t *testing.T) { + assert.Len(t, sr.streams, 2) + + sr.Unregister("foo") + + assert.Len(t, sr.streams, 2) + _, exists := sr.streams["foo"] + assert.False(t, exists) + }) + }) +} diff --git a/core/services/streams/stream_test.go b/core/services/streams/stream_test.go new file mode 100644 index 00000000000..3a556411bc6 --- /dev/null +++ b/core/services/streams/stream_test.go @@ -0,0 +1,133 @@ +package streams + +import ( + "context" + "math/big" + "testing" + "time" + + "github.com/google/uuid" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "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" +) + +var UUID = uuid.New() + +type mockRunner struct { + p *pipeline.Pipeline + run *pipeline.Run + trrs pipeline.TaskRunResults + err error +} + +func (m *mockRunner) ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error) { + return m.run, m.trrs, m.err +} +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 { + return m.err +} + +type MockTask struct { + result pipeline.Result +} + +func (m *MockTask) Type() pipeline.TaskType { return "MockTask" } +func (m *MockTask) ID() int { return 0 } +func (m *MockTask) DotID() string { return "" } +func (m *MockTask) Run(ctx context.Context, lggr logger.Logger, vars pipeline.Vars, inputs []pipeline.Result) (pipeline.Result, pipeline.RunInfo) { + return m.result, pipeline.RunInfo{} +} +func (m *MockTask) Base() *pipeline.BaseTask { return nil } +func (m *MockTask) Outputs() []pipeline.Task { return nil } +func (m *MockTask) Inputs() []pipeline.TaskDependency { return nil } +func (m *MockTask) OutputIndex() int32 { return 0 } +func (m *MockTask) TaskTimeout() (time.Duration, bool) { return 0, false } +func (m *MockTask) TaskRetries() uint32 { return 0 } +func (m *MockTask) TaskMinBackoff() time.Duration { return 0 } +func (m *MockTask) TaskMaxBackoff() time.Duration { return 0 } + +func Test_Stream(t *testing.T) { + lggr := logger.TestLogger(t) + runner := &mockRunner{} + spec := pipeline.Spec{} + id := StreamID("stream-id-foo") + ctx := testutils.Context(t) + + t.Run("Run", func(t *testing.T) { + strm := newStream(lggr, id, spec, runner, nil) + + t.Run("errors with empty pipeline", func(t *testing.T) { + _, _, err := strm.Run(ctx) + assert.EqualError(t, err, "Run failed: Run failed due to unparseable pipeline: empty pipeline") + }) + + spec.DotDagSource = ` +succeed [type=memo value=42] +succeed; +` + + strm = newStream(lggr, id, spec, runner, nil) + + t.Run("executes the pipeline (success)", func(t *testing.T) { + runner.run = &pipeline.Run{ID: 42} + runner.trrs = []pipeline.TaskRunResult{pipeline.TaskRunResult{ID: UUID}} + runner.err = nil + + run, trrs, err := strm.Run(ctx) + assert.NoError(t, err) + + assert.Equal(t, int64(42), run.ID) + require.Len(t, trrs, 1) + assert.Equal(t, UUID, trrs[0].ID) + }) + t.Run("executes the pipeline (failure)", func(t *testing.T) { + runner.err = errors.New("something exploded") + + _, _, err := strm.Run(ctx) + require.Error(t, err) + + assert.EqualError(t, err, "Run failed: error executing run for spec ID 0: something exploded") + }) + }) +} + +func Test_ExtractBigInt(t *testing.T) { + t.Run("wrong number of inputs", func(t *testing.T) { + trrs := []pipeline.TaskRunResult{} + + _, err := ExtractBigInt(trrs) + assert.EqualError(t, err, "invalid number of results, expected: 1, got: 0") + }) + t.Run("wrong type", func(t *testing.T) { + trrs := []pipeline.TaskRunResult{ + { + Result: pipeline.Result{Value: []byte{1, 2, 3}}, + Task: &MockTask{}, + }, + } + + _, err := ExtractBigInt(trrs) + assert.EqualError(t, err, "failed to parse BenchmarkPrice: type []uint8 cannot be converted to decimal.Decimal ([1 2 3])") + }) + t.Run("correct inputs", func(t *testing.T) { + trrs := []pipeline.TaskRunResult{ + { + Result: pipeline.Result{Value: "122.345"}, + Task: &MockTask{}, + }, + } + + val, err := ExtractBigInt(trrs) + require.NoError(t, err) + assert.Equal(t, big.NewInt(122), val) + }) +} diff --git a/core/services/synchronization/mocks/telemetry_service.go b/core/services/synchronization/mocks/telemetry_service.go index bd822666b97..375b46ad7bb 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -18,6 +18,10 @@ type TelemetryService struct { func (_m *TelemetryService) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -32,6 +36,10 @@ func (_m *TelemetryService) Close() error { func (_m *TelemetryService) HealthReport() map[string]error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for HealthReport") + } + var r0 map[string]error if rf, ok := ret.Get(0).(func() map[string]error); ok { r0 = rf() @@ -48,6 +56,10 @@ func (_m *TelemetryService) HealthReport() map[string]error { func (_m *TelemetryService) Name() string { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Name") + } + var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() @@ -62,6 +74,10 @@ func (_m *TelemetryService) Name() string { func (_m *TelemetryService) Ready() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Ready") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -81,6 +97,10 @@ func (_m *TelemetryService) Send(ctx context.Context, telemetry []byte, contract func (_m *TelemetryService) Start(_a0 context.Context) error { ret := _m.Called(_a0) + if len(ret) == 0 { + panic("no return value specified for Start") + } + var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(_a0) diff --git a/core/services/synchronization/telemetry_ingress_batch_client_test.go b/core/services/synchronization/telemetry_ingress_batch_client_test.go index 6dd9d401a80..c4f6417131d 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client_test.go +++ b/core/services/synchronization/telemetry_ingress_batch_client_test.go @@ -9,8 +9,8 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -37,7 +37,7 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { serverPubKeyHex := "33333333333" sendInterval := time.Millisecond * 5 telemIngressClient := synchronization.NewTestTelemetryIngressBatchClient(t, url, serverPubKeyHex, csaKeystore, false, telemClient, sendInterval, false) - require.NoError(t, telemIngressClient.Start(testutils.Context(t))) + servicetest.Run(t, telemIngressClient) // Create telemetry payloads for different contracts telemPayload1 := synchronization.TelemPayload{ @@ -100,7 +100,4 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { g.Eventually(func() []uint32 { return []uint32{contractCounter1.Load(), contractCounter2.Load(), contractCounter3.Load()} }).Should(gomega.Equal([]uint32{3, 2, 1})) - - // Client should shut down - telemIngressClient.Close() } diff --git a/core/services/synchronization/telemetry_ingress_client_test.go b/core/services/synchronization/telemetry_ingress_client_test.go index 5a0cc23ecd0..55be107b977 100644 --- a/core/services/synchronization/telemetry_ingress_client_test.go +++ b/core/services/synchronization/telemetry_ingress_client_test.go @@ -9,8 +9,8 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -35,8 +35,7 @@ func TestTelemetryIngressClient_Send_HappyPath(t *testing.T) { url := &url.URL{} serverPubKeyHex := "33333333333" telemIngressClient := synchronization.NewTestTelemetryIngressClient(t, url, serverPubKeyHex, csaKeystore, false, telemClient) - require.NoError(t, telemIngressClient.Start(testutils.Context(t))) - defer func() { assert.NoError(t, telemIngressClient.Close()) }() + servicetest.Run(t, telemIngressClient) // Create the telemetry payload telemetry := []byte("101010") diff --git a/core/services/telemetry/manager.go b/core/services/telemetry/manager.go index c457aca5bf8..228a997eeca 100644 --- a/core/services/telemetry/manager.go +++ b/core/services/telemetry/manager.go @@ -18,13 +18,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" ) -//// Client encapsulates all the functionality needed to -//// send telemetry to the ingress server using wsrpc -//type Client interface { -// services.ServiceCtx -// Send(context.Context, synchronization.TelemPayload) -//} - type Manager struct { services.StateMachine bufferSize uint @@ -38,32 +31,6 @@ type Manager struct { uniConn bool useBatchSend bool MonitoringEndpointGenerator MonitoringEndpointGenerator - - //legacyMode means that we are sending all telemetry to a single endpoint. - //In order for this to be set as true, we need to have no endpoints defined with TelemetryIngress.URL and TelemetryIngress.ServerPubKey set. - //This mode will be supported until we completely switch to TelemetryIngress.Endpoints in config.toml - legacyMode bool -} - -type legacyEndpointConfig struct { - Url *url.URL - PubKey string -} - -func (l *legacyEndpointConfig) Network() string { - return "-" -} - -func (l *legacyEndpointConfig) ChainID() string { - return "-" -} - -func (l *legacyEndpointConfig) ServerPubKey() string { - return l.PubKey -} - -func (l *legacyEndpointConfig) URL() *url.URL { - return l.Url } type telemetryEndpoint struct { @@ -87,30 +54,12 @@ func NewManager(cfg config.TelemetryIngress, csaKeyStore keystore.CSA, lggr logg sendTimeout: cfg.SendTimeout(), uniConn: cfg.UniConn(), useBatchSend: cfg.UseBatchSend(), - legacyMode: false, } for _, e := range cfg.Endpoints() { if err := m.addEndpoint(e); err != nil { m.lggr.Error(err) } } - - if len(cfg.Endpoints()) == 0 && cfg.URL() != nil && cfg.ServerPubKey() != "" { - m.lggr.Error(`TelemetryIngress.URL and TelemetryIngress.ServerPubKey will be removed in a future version, please switch to TelemetryIngress.Endpoints: - [[TelemetryIngress.Endpoints]] - Network = '...' # e.g. EVM. Solana, Starknet, Cosmos - ChainID = '...' # e.g. 1, 5, devnet, mainnet-beta - URL = '...' - ServerPubKey = '...'`) - m.legacyMode = true - if err := m.addEndpoint(&legacyEndpointConfig{ - Url: cfg.URL(), - PubKey: cfg.ServerPubKey(), - }); err != nil { - m.lggr.Error(err) - } - } - return m } @@ -165,11 +114,11 @@ func (m *Manager) GenMonitoringEndpoint(network string, chainID string, contract } func (m *Manager) addEndpoint(e config.TelemetryIngressEndpoint) error { - if e.Network() == "" && !m.legacyMode { + if e.Network() == "" { return errors.New("cannot add telemetry endpoint, network cannot be empty") } - if e.ChainID() == "" && !m.legacyMode { + if e.ChainID() == "" { return errors.New("cannot add telemetry endpoint, chainID cannot be empty") } @@ -205,11 +154,6 @@ func (m *Manager) addEndpoint(e config.TelemetryIngressEndpoint) error { } func (m *Manager) getEndpoint(network string, chainID string) (*telemetryEndpoint, bool) { - //in legacy mode we send telemetry to a single endpoint - if m.legacyMode && len(m.endpoints) == 1 { - return m.endpoints[0], true - } - for _, e := range m.endpoints { if e.Network == strings.ToUpper(network) && e.ChainID == strings.ToUpper(chainID) { return e, true diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index 8564be8466f..2d3409ba569 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -9,7 +9,6 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" @@ -22,7 +21,6 @@ import ( mocks3 "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" mocks2 "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) func setupMockConfig(t *testing.T, useBatchSend bool) *mocks.TelemetryIngress { @@ -201,7 +199,6 @@ func TestNewManager(t *testing.T) { func TestCorrectEndpointRouting(t *testing.T) { tic := setupMockConfig(t, true) tic.On("Endpoints").Return(nil) - tic.On("URL").Return(nil) lggr, obsLogs := logger.TestLoggerObserved(t, zapcore.InfoLevel) ks := mocks3.NewCSA(t) @@ -287,53 +284,3 @@ func TestCorrectEndpointRouting(t *testing.T) { } } - -func TestLegacyMode(t *testing.T) { - tic := setupMockConfig(t, true) - tic.On("Endpoints").Return(nil) - url, err := models.ParseURL("test.test") - require.NoError(t, err) - tic.On("URL").Return(url.URL()) - tic.On("ServerPubKey").Return("some-pub-key") - - lggr, obsLogs := logger.TestLoggerObserved(t, zapcore.InfoLevel) - ks := mocks3.NewCSA(t) - - tm := NewManager(tic, ks, lggr) - require.Equal(t, true, tm.legacyMode) - require.Len(t, tm.endpoints, 1) - - var clientSent []synchronization.TelemPayload - clientMock := mocks2.NewTelemetryService(t) - clientMock.On("Send", mock.Anything, mock.AnythingOfType("[]uint8"), mock.AnythingOfType("string"), mock.AnythingOfType("TelemetryType")).Return().Run(func(args mock.Arguments) { - clientSent = append(clientSent, synchronization.TelemPayload{ - Telemetry: args[1].([]byte), - ContractID: args[2].(string), - TelemType: args[3].(synchronization.TelemetryType), - }) - }) - tm.endpoints[0].client = clientMock - - e := tm.GenMonitoringEndpoint("unknown-network", "unknown-chainID", "some-contractID", "some-type") - require.Equal(t, "*telemetry.IngressAgentBatch", reflect.TypeOf(e).String()) - - e.SendLog([]byte("endpoint-1-message-1")) - e.SendLog([]byte("endpoint-1-message-2")) - e.SendLog([]byte("endpoint-1-message-3")) - require.Len(t, clientSent, 3) - - e2 := tm.GenMonitoringEndpoint("another-unknown-network", "another-unknown-chainID", "another-contractID", "another-type") - require.Equal(t, "*telemetry.IngressAgentBatch", reflect.TypeOf(e).String()) - - e2.SendLog([]byte("endpoint-2-message-1")) - e2.SendLog([]byte("endpoint-2-message-2")) - e2.SendLog([]byte("endpoint-2-message-3")) - require.Len(t, clientSent, 6) - assert.Equal(t, []byte("endpoint-1-message-1"), clientSent[0].Telemetry) - assert.Equal(t, []byte("endpoint-1-message-2"), clientSent[1].Telemetry) - assert.Equal(t, []byte("endpoint-1-message-3"), clientSent[2].Telemetry) - assert.Equal(t, []byte("endpoint-2-message-1"), clientSent[3].Telemetry) - assert.Equal(t, []byte("endpoint-2-message-2"), clientSent[4].Telemetry) - assert.Equal(t, []byte("endpoint-2-message-3"), clientSent[5].Telemetry) - assert.Equal(t, 1, obsLogs.Len()) // Deprecation warning for TelemetryIngress.URL and TelemetryIngress.ServerPubKey -} diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index a13df71d9a3..ecabbc09c71 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -12,6 +12,7 @@ import ( "github.com/jmoiron/sqlx" + "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" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -29,7 +30,6 @@ import ( v1 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v1" v2 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type Delegate struct { @@ -39,7 +39,7 @@ type Delegate struct { ks keystore.Master legacyChains legacyevm.LegacyChainContainer lggr logger.Logger - mailMon *utils.MailboxMonitor + mailMon *mailbox.Monitor } func NewDelegate( @@ -50,7 +50,7 @@ func NewDelegate( legacyChains legacyevm.LegacyChainContainer, lggr logger.Logger, cfg pg.QConfig, - mailMon *utils.MailboxMonitor) *Delegate { + mailMon *mailbox.Monitor) *Delegate { return &Delegate{ q: pg.NewQ(db, lggr, cfg), ks: ks, @@ -76,7 +76,7 @@ func (d *Delegate) ServicesForSpec(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) } - pl, err := jb.PipelineSpec.Pipeline() + pl, err := jb.PipelineSpec.ParsePipeline() if err != nil { return nil, err } @@ -142,6 +142,9 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { if vrfOwner != nil { return nil, errors.New("VRF Owner is not supported for VRF V2 Plus") } + if jb.VRFSpec.CustomRevertsPipelineEnabled { + return nil, errors.New("Custom Reverted Txns Pipeline is not supported for VRF V2 Plus") + } // Get the LINKNATIVEFEED address with retries // This is needed because the RPC endpoint may be down so we need to @@ -250,7 +253,7 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { MailMon: d.mailMon, // Note the mailbox size effectively sets a limit on how many logs we can replay // in the event of a VRF outage. - ReqLogs: utils.NewHighCapacityMailbox[log.Broadcast](), + ReqLogs: mailbox.NewHighCapacity[log.Broadcast](), ChStop: make(chan struct{}), WaitOnStop: make(chan struct{}), NewHead: make(chan struct{}, 1), diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 3c297026004..8ad88d7b73b 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -6,7 +6,16 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -17,6 +26,7 @@ import ( log_mocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log/mocks" "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/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -32,7 +42,6 @@ import ( "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" - "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/services/vrf" vrf_mocks "github.com/smartcontractkit/chainlink/v2/core/services/vrf/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/solidity_cross_tests" @@ -40,13 +49,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" ) type vrfUniverse struct { @@ -123,14 +125,14 @@ func generateCallbackReturnValues(t *testing.T, fulfilled bool) []byte { // Empty callback b, err2 := args.Pack(solidity_vrf_coordinator_interface.Callbacks{ RandomnessFee: big.NewInt(10), - SeedAndBlockNum: utils.EmptyHash, + SeedAndBlockNum: evmutils.EmptyHash, }) require.NoError(t, err2) return b } b, err := args.Pack(solidity_vrf_coordinator_interface.Callbacks{ RandomnessFee: big.NewInt(10), - SeedAndBlockNum: utils.NewHash(), + SeedAndBlockNum: evmutils.NewHash(), }) require.NoError(t, err) return b @@ -149,7 +151,7 @@ func setup(t *testing.T) (vrfUniverse, *v1.Listener, job.Job) { cfg := configtest.NewTestGeneralConfig(t) vuni := buildVrfUni(t, db, cfg) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) vd := vrf.NewDelegate( db, @@ -176,8 +178,7 @@ func setup(t *testing.T) (vrfUniverse, *v1.Listener, job.Job) { go func() { listener.RunHeadListener(func() {}) }() - t.Cleanup(func() { listener.Stop(t) }) - require.NoError(t, listener.Start(testutils.Context(t))) + servicetest.Run(t, listener) return vuni, listener, jb } @@ -185,7 +186,7 @@ func TestDelegate_ReorgAttackProtection(t *testing.T) { vuni, listener, jb := setup(t) // Same request has already been fulfilled twice - reqID := utils.NewHash() + reqID := evmutils.NewHash() var reqIDBytes [32]byte copy(reqIDBytes[:], reqID.Bytes()) listener.SetRespCount(reqIDBytes, 2) @@ -198,17 +199,17 @@ func TestDelegate_ReorgAttackProtection(t *testing.T) { added <- struct{}{} }) preSeed := common.BigToHash(big.NewInt(42)).Bytes() - txHash := utils.NewHash() + 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.ec.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(generateCallbackReturnValues(t, false), nil).Maybe() listener.HandleLog(log.NewLogBroadcast(types.Log{ // Data has all the NON-indexed parameters Data: bytes.Join([][]byte{pk.MustHash().Bytes(), // key hash - preSeed, // preSeed - utils.NewHash().Bytes(), // sender - utils.NewHash().Bytes(), // fee - reqID.Bytes()}, []byte{}, // requestID + preSeed, // preSeed + evmutils.NewHash().Bytes(), // sender + evmutils.NewHash().Bytes(), // fee + reqID.Bytes()}, []byte{}, // requestID ), // JobID is indexed, thats why it lives in the Topics. Topics: []common.Hash{ @@ -230,9 +231,9 @@ func TestDelegate_ReorgAttackProtection(t *testing.T) { func TestDelegate_ValidLog(t *testing.T) { vuni, listener, jb := setup(t) - txHash := utils.NewHash() - reqID1 := utils.NewHash() - reqID2 := utils.NewHash() + txHash := evmutils.NewHash() + reqID1 := evmutils.NewHash() + reqID2 := evmutils.NewHash() keyID := vuni.vrfkey.PublicKey.String() pk, err := secp256k1.NewPublicKeyFromHex(keyID) require.NoError(t, err) @@ -241,7 +242,7 @@ func TestDelegate_ValidLog(t *testing.T) { added <- struct{}{} }) preSeed := common.BigToHash(big.NewInt(42)).Bytes() - bh := utils.NewHash() + bh := evmutils.NewHash() var tt = []struct { reqID [32]byte log types.Log @@ -253,8 +254,8 @@ func TestDelegate_ValidLog(t *testing.T) { Data: bytes.Join([][]byte{ pk.MustHash().Bytes(), // key hash common.BigToHash(big.NewInt(42)).Bytes(), // seed - utils.NewHash().Bytes(), // sender - utils.NewHash().Bytes(), // fee + evmutils.NewHash().Bytes(), // sender + evmutils.NewHash().Bytes(), // fee reqID1.Bytes()}, // requestID []byte{}), // JobID is indexed, thats why it lives in the Topics. @@ -275,8 +276,8 @@ func TestDelegate_ValidLog(t *testing.T) { Data: bytes.Join([][]byte{ pk.MustHash().Bytes(), // key hash common.BigToHash(big.NewInt(42)).Bytes(), // seed - utils.NewHash().Bytes(), // sender - utils.NewHash().Bytes(), // fee + evmutils.NewHash().Bytes(), // sender + evmutils.NewHash().Bytes(), // fee reqID2.Bytes()}, // requestID []byte{}), Topics: []common.Hash{ @@ -324,7 +325,7 @@ func TestDelegate_ValidLog(t *testing.T) { // Should have 4 tasks all completed assert.Len(t, runs[0].PipelineTaskRuns, 4) - p, err := vuni.ks.VRF().GenerateProof(keyID, utils.MustHash(string(bytes.Join([][]byte{preSeed, bh.Bytes()}, []byte{}))).Big()) + 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) { @@ -367,11 +368,11 @@ func TestDelegate_InvalidLog(t *testing.T) { listener.HandleLog(log.NewLogBroadcast(types.Log{ // Data has all the NON-indexed parameters Data: append(append(append(append( - utils.NewHash().Bytes(), // key hash + evmutils.NewHash().Bytes(), // key hash common.BigToHash(big.NewInt(42)).Bytes()...), // seed - utils.NewHash().Bytes()...), // sender - utils.NewHash().Bytes()...), // fee - utils.NewHash().Bytes()...), // requestID + evmutils.NewHash().Bytes()...), // sender + evmutils.NewHash().Bytes()...), // fee + evmutils.NewHash().Bytes()...), // requestID // JobID is indexed, that's why it lives in the Topics. Topics: []common.Hash{ solidity_cross_tests.VRFRandomnessRequestLogTopic(), @@ -404,11 +405,13 @@ func TestDelegate_InvalidLog(t *testing.T) { } } - // Ensure we have NOT queued up an eth transaction - var ethTxes []txmgr.DbEthTx - err = vuni.prm.GetQ().Select(ðTxes, `SELECT * FROM evm.txes;`) + db := pgtest.NewSqlxDB(t) + cfg := pgtest.NewQConfig(false) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + + txes, err := txStore.GetAllTxes(testutils.Context(t)) require.NoError(t, err) - require.Len(t, ethTxes, 0) + require.Len(t, txes, 0) } func TestFulfilledCheck(t *testing.T) { @@ -433,18 +436,18 @@ func TestFulfilledCheck(t *testing.T) { Data: bytes.Join([][]byte{ vuni.vrfkey.PublicKey.MustHash().Bytes(), // key hash common.BigToHash(big.NewInt(42)).Bytes(), // seed - utils.NewHash().Bytes(), // sender - utils.NewHash().Bytes(), // fee - utils.NewHash().Bytes()}, // requestID + evmutils.NewHash().Bytes(), // sender + evmutils.NewHash().Bytes(), // fee + evmutils.NewHash().Bytes()}, // requestID []byte{}), // JobID is indexed, that's why it lives in the Topics. Topics: []common.Hash{ solidity_cross_tests.VRFRandomnessRequestLogTopic(), jb.ExternalIDEncodeBytesToTopic(), // jobID STRING }, - //TxHash: utils.NewHash().Bytes(), + //TxHash: evmutils.NewHash().Bytes(), BlockNumber: 10, - //BlockHash: utils.NewHash().Bytes(), + //BlockHash: evmutils.NewHash().Bytes(), }, vuni.cid, nil)) // Should queue the request, even though its already fulfilled @@ -674,7 +677,7 @@ func Test_VRFV2PlusServiceFailsWhenVRFOwnerProvided(t *testing.T) { cfg := configtest.NewTestGeneralConfig(t) vuni := buildVrfUni(t, db, cfg) - mailMon := srvctest.Start(t, utils.NewMailboxMonitor(t.Name())) + mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) vd := vrf.NewDelegate( db, @@ -690,7 +693,7 @@ func Test_VRFV2PlusServiceFailsWhenVRFOwnerProvided(t *testing.T) { vs := testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ VRFVersion: vrfcommon.V2Plus, PublicKey: vuni.vrfkey.PublicKey.String(), - FromAddresses: []string{string(vuni.submitter.Hex())}, + FromAddresses: []string{vuni.submitter.Hex()}, GasLanePrice: chain.Config().EVM().GasEstimator().PriceMax(), }) toml := "vrfOwnerAddress=\"0xF62fEFb54a0af9D32CDF0Db21C52710844c7eddb\"\n" + vs.Toml() diff --git a/core/services/vrf/extraargs/types.go b/core/services/vrf/extraargs/types.go index 4dcc87e5d04..eecd0bfa334 100644 --- a/core/services/vrf/extraargs/types.go +++ b/core/services/vrf/extraargs/types.go @@ -5,7 +5,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) const functionSignatureLength = 4 diff --git a/core/services/vrf/mocks/aggregator_v3_interface.go b/core/services/vrf/mocks/aggregator_v3_interface.go index 956e315f297..46ca11aa200 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -23,6 +23,10 @@ type AggregatorV3Interface struct { func (_m *AggregatorV3Interface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -39,6 +43,10 @@ func (_m *AggregatorV3Interface) Address() common.Address { func (_m *AggregatorV3Interface) Decimals(opts *bind.CallOpts) (uint8, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Decimals") + } + var r0 uint8 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint8, error)); ok { @@ -63,6 +71,10 @@ func (_m *AggregatorV3Interface) Decimals(opts *bind.CallOpts) (uint8, error) { func (_m *AggregatorV3Interface) Description(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Description") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -87,6 +99,10 @@ func (_m *AggregatorV3Interface) Description(opts *bind.CallOpts) (string, error func (_m *AggregatorV3Interface) GetRoundData(opts *bind.CallOpts, _roundId *big.Int) (aggregator_v3_interface.GetRoundData, error) { ret := _m.Called(opts, _roundId) + if len(ret) == 0 { + panic("no return value specified for GetRoundData") + } + var r0 aggregator_v3_interface.GetRoundData var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) (aggregator_v3_interface.GetRoundData, error)); ok { @@ -111,6 +127,10 @@ func (_m *AggregatorV3Interface) GetRoundData(opts *bind.CallOpts, _roundId *big func (_m *AggregatorV3Interface) LatestRoundData(opts *bind.CallOpts) (aggregator_v3_interface.LatestRoundData, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LatestRoundData") + } + var r0 aggregator_v3_interface.LatestRoundData var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (aggregator_v3_interface.LatestRoundData, error)); ok { @@ -135,6 +155,10 @@ func (_m *AggregatorV3Interface) LatestRoundData(opts *bind.CallOpts) (aggregato func (_m *AggregatorV3Interface) Version(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Version") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { diff --git a/core/services/vrf/mocks/config.go b/core/services/vrf/mocks/config.go index 72d5960f2c9..b46a28ec037 100644 --- a/core/services/vrf/mocks/config.go +++ b/core/services/vrf/mocks/config.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -13,6 +13,10 @@ type Config struct { func (_m *Config) FinalityDepth() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for FinalityDepth") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -27,6 +31,10 @@ func (_m *Config) FinalityDepth() uint32 { func (_m *Config) MinIncomingConfirmations() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for MinIncomingConfirmations") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() diff --git a/core/services/vrf/mocks/fee_config.go b/core/services/vrf/mocks/fee_config.go index 067ce7e4455..2f33415b338 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type FeeConfig struct { func (_m *FeeConfig) LimitDefault() uint32 { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitDefault") + } + var r0 uint32 if rf, ok := ret.Get(0).(func() uint32); ok { r0 = rf() @@ -34,6 +38,10 @@ func (_m *FeeConfig) LimitDefault() uint32 { func (_m *FeeConfig) LimitJobType() config.LimitJobType { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for LimitJobType") + } + var r0 config.LimitJobType if rf, ok := ret.Get(0).(func() config.LimitJobType); ok { r0 = rf() @@ -50,6 +58,10 @@ func (_m *FeeConfig) LimitJobType() config.LimitJobType { func (_m *FeeConfig) PriceMaxKey(addr common.Address) *assets.Wei { ret := _m.Called(addr) + if len(ret) == 0 { + panic("no return value specified for PriceMaxKey") + } + var r0 *assets.Wei if rf, ok := ret.Get(0).(func(common.Address) *assets.Wei); ok { r0 = rf(addr) diff --git a/core/services/vrf/mocks/vrf_coordinator_v2.go b/core/services/vrf/mocks/vrf_coordinator_v2.go index c39995b38e9..529bc789257 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -28,6 +28,10 @@ type VRFCoordinatorV2Interface struct { func (_m *VRFCoordinatorV2Interface) AcceptOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for AcceptOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -54,6 +58,10 @@ func (_m *VRFCoordinatorV2Interface) AcceptOwnership(opts *bind.TransactOpts) (* func (_m *VRFCoordinatorV2Interface) AcceptSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for AcceptSubscriptionOwnerTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64) (*types.Transaction, error)); ok { @@ -80,6 +88,10 @@ func (_m *VRFCoordinatorV2Interface) AcceptSubscriptionOwnerTransfer(opts *bind. func (_m *VRFCoordinatorV2Interface) AddConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, consumer) + if len(ret) == 0 { + panic("no return value specified for AddConsumer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, common.Address) (*types.Transaction, error)); ok { @@ -106,6 +118,10 @@ func (_m *VRFCoordinatorV2Interface) AddConsumer(opts *bind.TransactOpts, subId func (_m *VRFCoordinatorV2Interface) Address() common.Address { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Address") + } + var r0 common.Address if rf, ok := ret.Get(0).(func() common.Address); ok { r0 = rf() @@ -122,6 +138,10 @@ func (_m *VRFCoordinatorV2Interface) Address() common.Address { func (_m *VRFCoordinatorV2Interface) BLOCKHASHSTORE(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for BLOCKHASHSTORE") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -148,6 +168,10 @@ func (_m *VRFCoordinatorV2Interface) BLOCKHASHSTORE(opts *bind.CallOpts) (common func (_m *VRFCoordinatorV2Interface) CancelSubscription(opts *bind.TransactOpts, subId uint64, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, to) + if len(ret) == 0 { + panic("no return value specified for CancelSubscription") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, common.Address) (*types.Transaction, error)); ok { @@ -174,6 +198,10 @@ func (_m *VRFCoordinatorV2Interface) CancelSubscription(opts *bind.TransactOpts, func (_m *VRFCoordinatorV2Interface) CreateSubscription(opts *bind.TransactOpts) (*types.Transaction, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for CreateSubscription") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts) (*types.Transaction, error)); ok { @@ -200,6 +228,10 @@ func (_m *VRFCoordinatorV2Interface) CreateSubscription(opts *bind.TransactOpts) func (_m *VRFCoordinatorV2Interface) DeregisterProvingKey(opts *bind.TransactOpts, publicProvingKey [2]*big.Int) (*types.Transaction, error) { ret := _m.Called(opts, publicProvingKey) + if len(ret) == 0 { + panic("no return value specified for DeregisterProvingKey") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [2]*big.Int) (*types.Transaction, error)); ok { @@ -226,6 +258,10 @@ func (_m *VRFCoordinatorV2Interface) DeregisterProvingKey(opts *bind.TransactOpt func (_m *VRFCoordinatorV2Interface) FilterConfigSet(opts *bind.FilterOpts) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSetIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterConfigSet") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ConfigSetIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSetIterator, error)); ok { @@ -252,6 +288,10 @@ func (_m *VRFCoordinatorV2Interface) FilterConfigSet(opts *bind.FilterOpts) (*vr func (_m *VRFCoordinatorV2Interface) FilterFundsRecovered(opts *bind.FilterOpts) (*vrf_coordinator_v2.VRFCoordinatorV2FundsRecoveredIterator, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for FilterFundsRecovered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2FundsRecoveredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts) (*vrf_coordinator_v2.VRFCoordinatorV2FundsRecoveredIterator, error)); ok { @@ -278,6 +318,10 @@ func (_m *VRFCoordinatorV2Interface) FilterFundsRecovered(opts *bind.FilterOpts) func (_m *VRFCoordinatorV2Interface) FilterOwnershipTransferRequested(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequestedIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequestedIterator, error)); ok { @@ -304,6 +348,10 @@ func (_m *VRFCoordinatorV2Interface) FilterOwnershipTransferRequested(opts *bind func (_m *VRFCoordinatorV2Interface) FilterOwnershipTransferred(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferredIterator, error) { ret := _m.Called(opts, from, to) + if len(ret) == 0 { + panic("no return value specified for FilterOwnershipTransferred") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address, []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferredIterator, error)); ok { @@ -330,6 +378,10 @@ func (_m *VRFCoordinatorV2Interface) FilterOwnershipTransferred(opts *bind.Filte func (_m *VRFCoordinatorV2Interface) FilterProvingKeyDeregistered(opts *bind.FilterOpts, oracle []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregisteredIterator, error) { ret := _m.Called(opts, oracle) + if len(ret) == 0 { + panic("no return value specified for FilterProvingKeyDeregistered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregisteredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregisteredIterator, error)); ok { @@ -356,6 +408,10 @@ func (_m *VRFCoordinatorV2Interface) FilterProvingKeyDeregistered(opts *bind.Fil func (_m *VRFCoordinatorV2Interface) FilterProvingKeyRegistered(opts *bind.FilterOpts, oracle []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegisteredIterator, error) { ret := _m.Called(opts, oracle) + if len(ret) == 0 { + panic("no return value specified for FilterProvingKeyRegistered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegisteredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegisteredIterator, error)); ok { @@ -382,6 +438,10 @@ func (_m *VRFCoordinatorV2Interface) FilterProvingKeyRegistered(opts *bind.Filte func (_m *VRFCoordinatorV2Interface) FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestId []*big.Int) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilledIterator, error) { ret := _m.Called(opts, requestId) + if len(ret) == 0 { + panic("no return value specified for FilterRandomWordsFulfilled") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []*big.Int) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilledIterator, error)); ok { @@ -408,6 +468,10 @@ func (_m *VRFCoordinatorV2Interface) FilterRandomWordsFulfilled(opts *bind.Filte func (_m *VRFCoordinatorV2Interface) FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subId []uint64, sender []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequestedIterator, error) { ret := _m.Called(opts, keyHash, subId, sender) + if len(ret) == 0 { + panic("no return value specified for FilterRandomWordsRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, [][32]byte, []uint64, []common.Address) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequestedIterator, error)); ok { @@ -434,6 +498,10 @@ func (_m *VRFCoordinatorV2Interface) FilterRandomWordsRequested(opts *bind.Filte func (_m *VRFCoordinatorV2Interface) FilterSubscriptionCanceled(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceledIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionCanceled") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceledIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceledIterator, error)); ok { @@ -460,6 +528,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionCanceled(opts *bind.Filte func (_m *VRFCoordinatorV2Interface) FilterSubscriptionConsumerAdded(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAddedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionConsumerAdded") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAddedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAddedIterator, error)); ok { @@ -486,6 +558,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionConsumerAdded(opts *bind. func (_m *VRFCoordinatorV2Interface) FilterSubscriptionConsumerRemoved(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemovedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionConsumerRemoved") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemovedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemovedIterator, error)); ok { @@ -512,6 +588,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionConsumerRemoved(opts *bin func (_m *VRFCoordinatorV2Interface) FilterSubscriptionCreated(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreatedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionCreated") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreatedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreatedIterator, error)); ok { @@ -538,6 +618,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionCreated(opts *bind.Filter func (_m *VRFCoordinatorV2Interface) FilterSubscriptionFunded(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFundedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionFunded") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFundedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFundedIterator, error)); ok { @@ -564,6 +648,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionFunded(opts *bind.FilterO func (_m *VRFCoordinatorV2Interface) FilterSubscriptionOwnerTransferRequested(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequestedIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionOwnerTransferRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequestedIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequestedIterator, error)); ok { @@ -590,6 +678,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionOwnerTransferRequested(op func (_m *VRFCoordinatorV2Interface) FilterSubscriptionOwnerTransferred(opts *bind.FilterOpts, subId []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferredIterator, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for FilterSubscriptionOwnerTransferred") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferredIterator var r1 error if rf, ok := ret.Get(0).(func(*bind.FilterOpts, []uint64) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferredIterator, error)); ok { @@ -616,6 +708,10 @@ func (_m *VRFCoordinatorV2Interface) FilterSubscriptionOwnerTransferred(opts *bi func (_m *VRFCoordinatorV2Interface) FulfillRandomWords(opts *bind.TransactOpts, proof vrf_coordinator_v2.VRFProof, rc vrf_coordinator_v2.VRFCoordinatorV2RequestCommitment) (*types.Transaction, error) { ret := _m.Called(opts, proof, rc) + if len(ret) == 0 { + panic("no return value specified for FulfillRandomWords") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, vrf_coordinator_v2.VRFProof, vrf_coordinator_v2.VRFCoordinatorV2RequestCommitment) (*types.Transaction, error)); ok { @@ -642,6 +738,10 @@ func (_m *VRFCoordinatorV2Interface) FulfillRandomWords(opts *bind.TransactOpts, func (_m *VRFCoordinatorV2Interface) GetCommitment(opts *bind.CallOpts, requestId *big.Int) ([32]byte, error) { ret := _m.Called(opts, requestId) + if len(ret) == 0 { + panic("no return value specified for GetCommitment") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, *big.Int) ([32]byte, error)); ok { @@ -668,6 +768,10 @@ func (_m *VRFCoordinatorV2Interface) GetCommitment(opts *bind.CallOpts, requestI func (_m *VRFCoordinatorV2Interface) GetConfig(opts *bind.CallOpts) (vrf_coordinator_v2.GetConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetConfig") + } + var r0 vrf_coordinator_v2.GetConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_coordinator_v2.GetConfig, error)); ok { @@ -692,6 +796,10 @@ func (_m *VRFCoordinatorV2Interface) GetConfig(opts *bind.CallOpts) (vrf_coordin func (_m *VRFCoordinatorV2Interface) GetCurrentSubId(opts *bind.CallOpts) (uint64, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetCurrentSubId") + } + var r0 uint64 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint64, error)); ok { @@ -716,6 +824,10 @@ func (_m *VRFCoordinatorV2Interface) GetCurrentSubId(opts *bind.CallOpts) (uint6 func (_m *VRFCoordinatorV2Interface) GetFallbackWeiPerUnitLink(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetFallbackWeiPerUnitLink") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -742,6 +854,10 @@ func (_m *VRFCoordinatorV2Interface) GetFallbackWeiPerUnitLink(opts *bind.CallOp func (_m *VRFCoordinatorV2Interface) GetFeeConfig(opts *bind.CallOpts) (vrf_coordinator_v2.GetFeeConfig, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetFeeConfig") + } + var r0 vrf_coordinator_v2.GetFeeConfig var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (vrf_coordinator_v2.GetFeeConfig, error)); ok { @@ -766,6 +882,10 @@ func (_m *VRFCoordinatorV2Interface) GetFeeConfig(opts *bind.CallOpts) (vrf_coor func (_m *VRFCoordinatorV2Interface) GetFeeTier(opts *bind.CallOpts, reqCount uint64) (uint32, error) { ret := _m.Called(opts, reqCount) + if len(ret) == 0 { + panic("no return value specified for GetFeeTier") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (uint32, error)); ok { @@ -790,6 +910,10 @@ func (_m *VRFCoordinatorV2Interface) GetFeeTier(opts *bind.CallOpts, reqCount ui func (_m *VRFCoordinatorV2Interface) GetRequestConfig(opts *bind.CallOpts) (uint16, uint32, [][32]byte, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetRequestConfig") + } + var r0 uint16 var r1 uint32 var r2 [][32]byte @@ -830,6 +954,10 @@ func (_m *VRFCoordinatorV2Interface) GetRequestConfig(opts *bind.CallOpts) (uint func (_m *VRFCoordinatorV2Interface) GetSubscription(opts *bind.CallOpts, subId uint64) (vrf_coordinator_v2.GetSubscription, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for GetSubscription") + } + var r0 vrf_coordinator_v2.GetSubscription var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (vrf_coordinator_v2.GetSubscription, error)); ok { @@ -854,6 +982,10 @@ func (_m *VRFCoordinatorV2Interface) GetSubscription(opts *bind.CallOpts, subId func (_m *VRFCoordinatorV2Interface) GetTotalBalance(opts *bind.CallOpts) (*big.Int, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for GetTotalBalance") + } + var r0 *big.Int var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (*big.Int, error)); ok { @@ -880,6 +1012,10 @@ func (_m *VRFCoordinatorV2Interface) GetTotalBalance(opts *bind.CallOpts) (*big. func (_m *VRFCoordinatorV2Interface) HashOfKey(opts *bind.CallOpts, publicKey [2]*big.Int) ([32]byte, error) { ret := _m.Called(opts, publicKey) + if len(ret) == 0 { + panic("no return value specified for HashOfKey") + } + var r0 [32]byte var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, [2]*big.Int) ([32]byte, error)); ok { @@ -906,6 +1042,10 @@ func (_m *VRFCoordinatorV2Interface) HashOfKey(opts *bind.CallOpts, publicKey [2 func (_m *VRFCoordinatorV2Interface) LINK(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LINK") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -932,6 +1072,10 @@ func (_m *VRFCoordinatorV2Interface) LINK(opts *bind.CallOpts) (common.Address, func (_m *VRFCoordinatorV2Interface) LINKETHFEED(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for LINKETHFEED") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -958,6 +1102,10 @@ func (_m *VRFCoordinatorV2Interface) LINKETHFEED(opts *bind.CallOpts) (common.Ad func (_m *VRFCoordinatorV2Interface) MAXCONSUMERS(opts *bind.CallOpts) (uint16, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MAXCONSUMERS") + } + var r0 uint16 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint16, error)); ok { @@ -982,6 +1130,10 @@ func (_m *VRFCoordinatorV2Interface) MAXCONSUMERS(opts *bind.CallOpts) (uint16, func (_m *VRFCoordinatorV2Interface) MAXNUMWORDS(opts *bind.CallOpts) (uint32, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MAXNUMWORDS") + } + var r0 uint32 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint32, error)); ok { @@ -1006,6 +1158,10 @@ func (_m *VRFCoordinatorV2Interface) MAXNUMWORDS(opts *bind.CallOpts) (uint32, e func (_m *VRFCoordinatorV2Interface) MAXREQUESTCONFIRMATIONS(opts *bind.CallOpts) (uint16, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for MAXREQUESTCONFIRMATIONS") + } + var r0 uint16 var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (uint16, error)); ok { @@ -1030,6 +1186,10 @@ func (_m *VRFCoordinatorV2Interface) MAXREQUESTCONFIRMATIONS(opts *bind.CallOpts func (_m *VRFCoordinatorV2Interface) OnTokenTransfer(opts *bind.TransactOpts, arg0 common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { ret := _m.Called(opts, arg0, amount, data) + if len(ret) == 0 { + panic("no return value specified for OnTokenTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int, []byte) (*types.Transaction, error)); ok { @@ -1056,6 +1216,10 @@ func (_m *VRFCoordinatorV2Interface) OnTokenTransfer(opts *bind.TransactOpts, ar func (_m *VRFCoordinatorV2Interface) OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { ret := _m.Called(opts, recipient, amount) + if len(ret) == 0 { + panic("no return value specified for OracleWithdraw") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error)); ok { @@ -1082,6 +1246,10 @@ func (_m *VRFCoordinatorV2Interface) OracleWithdraw(opts *bind.TransactOpts, rec func (_m *VRFCoordinatorV2Interface) Owner(opts *bind.CallOpts) (common.Address, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for Owner") + } + var r0 common.Address var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (common.Address, error)); ok { @@ -1108,6 +1276,10 @@ func (_m *VRFCoordinatorV2Interface) Owner(opts *bind.CallOpts) (common.Address, func (_m *VRFCoordinatorV2Interface) OwnerCancelSubscription(opts *bind.TransactOpts, subId uint64) (*types.Transaction, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for OwnerCancelSubscription") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64) (*types.Transaction, error)); ok { @@ -1134,6 +1306,10 @@ func (_m *VRFCoordinatorV2Interface) OwnerCancelSubscription(opts *bind.Transact func (_m *VRFCoordinatorV2Interface) ParseConfigSet(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseConfigSet") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, error)); ok { @@ -1160,6 +1336,10 @@ func (_m *VRFCoordinatorV2Interface) ParseConfigSet(log types.Log) (*vrf_coordin func (_m *VRFCoordinatorV2Interface) ParseFundsRecovered(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2FundsRecovered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseFundsRecovered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2FundsRecovered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2FundsRecovered, error)); ok { @@ -1186,6 +1366,10 @@ func (_m *VRFCoordinatorV2Interface) ParseFundsRecovered(log types.Log) (*vrf_co func (_m *VRFCoordinatorV2Interface) ParseLog(log types.Log) (generated.AbigenLog, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseLog") + } + var r0 generated.AbigenLog var r1 error if rf, ok := ret.Get(0).(func(types.Log) (generated.AbigenLog, error)); ok { @@ -1212,6 +1396,10 @@ func (_m *VRFCoordinatorV2Interface) ParseLog(log types.Log) (generated.AbigenLo func (_m *VRFCoordinatorV2Interface) ParseOwnershipTransferRequested(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequested, error)); ok { @@ -1238,6 +1426,10 @@ func (_m *VRFCoordinatorV2Interface) ParseOwnershipTransferRequested(log types.L func (_m *VRFCoordinatorV2Interface) ParseOwnershipTransferred(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseOwnershipTransferred") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferred, error)); ok { @@ -1264,6 +1456,10 @@ func (_m *VRFCoordinatorV2Interface) ParseOwnershipTransferred(log types.Log) (* func (_m *VRFCoordinatorV2Interface) ParseProvingKeyDeregistered(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregistered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseProvingKeyDeregistered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregistered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregistered, error)); ok { @@ -1290,6 +1486,10 @@ func (_m *VRFCoordinatorV2Interface) ParseProvingKeyDeregistered(log types.Log) func (_m *VRFCoordinatorV2Interface) ParseProvingKeyRegistered(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegistered, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseProvingKeyRegistered") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegistered var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegistered, error)); ok { @@ -1316,6 +1516,10 @@ func (_m *VRFCoordinatorV2Interface) ParseProvingKeyRegistered(log types.Log) (* func (_m *VRFCoordinatorV2Interface) ParseRandomWordsFulfilled(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomWordsFulfilled") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error)); ok { @@ -1342,6 +1546,10 @@ func (_m *VRFCoordinatorV2Interface) ParseRandomWordsFulfilled(log types.Log) (* func (_m *VRFCoordinatorV2Interface) ParseRandomWordsRequested(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseRandomWordsRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, error)); ok { @@ -1368,6 +1576,10 @@ func (_m *VRFCoordinatorV2Interface) ParseRandomWordsRequested(log types.Log) (* func (_m *VRFCoordinatorV2Interface) ParseSubscriptionCanceled(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionCanceled") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error)); ok { @@ -1394,6 +1606,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionCanceled(log types.Log) (* func (_m *VRFCoordinatorV2Interface) ParseSubscriptionConsumerAdded(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionConsumerAdded") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, error)); ok { @@ -1420,6 +1636,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionConsumerAdded(log types.Lo func (_m *VRFCoordinatorV2Interface) ParseSubscriptionConsumerRemoved(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionConsumerRemoved") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, error)); ok { @@ -1446,6 +1666,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionConsumerRemoved(log types. func (_m *VRFCoordinatorV2Interface) ParseSubscriptionCreated(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionCreated") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, error)); ok { @@ -1472,6 +1696,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionCreated(log types.Log) (*v func (_m *VRFCoordinatorV2Interface) ParseSubscriptionFunded(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionFunded") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, error)); ok { @@ -1498,6 +1726,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionFunded(log types.Log) (*vr func (_m *VRFCoordinatorV2Interface) ParseSubscriptionOwnerTransferRequested(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequested, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionOwnerTransferRequested") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequested var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequested, error)); ok { @@ -1524,6 +1756,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionOwnerTransferRequested(log func (_m *VRFCoordinatorV2Interface) ParseSubscriptionOwnerTransferred(log types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferred, error) { ret := _m.Called(log) + if len(ret) == 0 { + panic("no return value specified for ParseSubscriptionOwnerTransferred") + } + var r0 *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferred var r1 error if rf, ok := ret.Get(0).(func(types.Log) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferred, error)); ok { @@ -1550,6 +1786,10 @@ func (_m *VRFCoordinatorV2Interface) ParseSubscriptionOwnerTransferred(log types func (_m *VRFCoordinatorV2Interface) PendingRequestExists(opts *bind.CallOpts, subId uint64) (bool, error) { ret := _m.Called(opts, subId) + if len(ret) == 0 { + panic("no return value specified for PendingRequestExists") + } + var r0 bool var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts, uint64) (bool, error)); ok { @@ -1574,6 +1814,10 @@ func (_m *VRFCoordinatorV2Interface) PendingRequestExists(opts *bind.CallOpts, s func (_m *VRFCoordinatorV2Interface) RecoverFunds(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for RecoverFunds") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1600,6 +1844,10 @@ func (_m *VRFCoordinatorV2Interface) RecoverFunds(opts *bind.TransactOpts, to co func (_m *VRFCoordinatorV2Interface) RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { ret := _m.Called(opts, oracle, publicProvingKey) + if len(ret) == 0 { + panic("no return value specified for RegisterProvingKey") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address, [2]*big.Int) (*types.Transaction, error)); ok { @@ -1626,6 +1874,10 @@ func (_m *VRFCoordinatorV2Interface) RegisterProvingKey(opts *bind.TransactOpts, func (_m *VRFCoordinatorV2Interface) RemoveConsumer(opts *bind.TransactOpts, subId uint64, consumer common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, consumer) + if len(ret) == 0 { + panic("no return value specified for RemoveConsumer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, common.Address) (*types.Transaction, error)); ok { @@ -1652,6 +1904,10 @@ func (_m *VRFCoordinatorV2Interface) RemoveConsumer(opts *bind.TransactOpts, sub func (_m *VRFCoordinatorV2Interface) RequestRandomWords(opts *bind.TransactOpts, keyHash [32]byte, subId uint64, requestConfirmations uint16, callbackGasLimit uint32, numWords uint32) (*types.Transaction, error) { ret := _m.Called(opts, keyHash, subId, requestConfirmations, callbackGasLimit, numWords) + if len(ret) == 0 { + panic("no return value specified for RequestRandomWords") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [32]byte, uint64, uint16, uint32, uint32) (*types.Transaction, error)); ok { @@ -1678,6 +1934,10 @@ func (_m *VRFCoordinatorV2Interface) RequestRandomWords(opts *bind.TransactOpts, func (_m *VRFCoordinatorV2Interface) RequestSubscriptionOwnerTransfer(opts *bind.TransactOpts, subId uint64, newOwner common.Address) (*types.Transaction, error) { ret := _m.Called(opts, subId, newOwner) + if len(ret) == 0 { + panic("no return value specified for RequestSubscriptionOwnerTransfer") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint64, common.Address) (*types.Transaction, error)); ok { @@ -1704,6 +1964,10 @@ func (_m *VRFCoordinatorV2Interface) RequestSubscriptionOwnerTransfer(opts *bind func (_m *VRFCoordinatorV2Interface) SetConfig(opts *bind.TransactOpts, minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig vrf_coordinator_v2.VRFCoordinatorV2FeeConfig) (*types.Transaction, error) { ret := _m.Called(opts, minimumRequestConfirmations, maxGasLimit, stalenessSeconds, gasAfterPaymentCalculation, fallbackWeiPerUnitLink, feeConfig) + if len(ret) == 0 { + panic("no return value specified for SetConfig") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, uint16, uint32, uint32, uint32, *big.Int, vrf_coordinator_v2.VRFCoordinatorV2FeeConfig) (*types.Transaction, error)); ok { @@ -1730,6 +1994,10 @@ func (_m *VRFCoordinatorV2Interface) SetConfig(opts *bind.TransactOpts, minimumR func (_m *VRFCoordinatorV2Interface) TransferOwnership(opts *bind.TransactOpts, to common.Address) (*types.Transaction, error) { ret := _m.Called(opts, to) + if len(ret) == 0 { + panic("no return value specified for TransferOwnership") + } + var r0 *types.Transaction var r1 error if rf, ok := ret.Get(0).(func(*bind.TransactOpts, common.Address) (*types.Transaction, error)); ok { @@ -1756,6 +2024,10 @@ func (_m *VRFCoordinatorV2Interface) TransferOwnership(opts *bind.TransactOpts, func (_m *VRFCoordinatorV2Interface) TypeAndVersion(opts *bind.CallOpts) (string, error) { ret := _m.Called(opts) + if len(ret) == 0 { + panic("no return value specified for TypeAndVersion") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(*bind.CallOpts) (string, error)); ok { @@ -1780,6 +2052,10 @@ func (_m *VRFCoordinatorV2Interface) TypeAndVersion(opts *bind.CallOpts) (string func (_m *VRFCoordinatorV2Interface) WatchConfigSet(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchConfigSet") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) (event.Subscription, error)); ok { @@ -1806,6 +2082,10 @@ func (_m *VRFCoordinatorV2Interface) WatchConfigSet(opts *bind.WatchOpts, sink c func (_m *VRFCoordinatorV2Interface) WatchFundsRecovered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2FundsRecovered) (event.Subscription, error) { ret := _m.Called(opts, sink) + if len(ret) == 0 { + panic("no return value specified for WatchFundsRecovered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2FundsRecovered) (event.Subscription, error)); ok { @@ -1832,6 +2112,10 @@ func (_m *VRFCoordinatorV2Interface) WatchFundsRecovered(opts *bind.WatchOpts, s func (_m *VRFCoordinatorV2Interface) WatchOwnershipTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequested, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferRequested, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1858,6 +2142,10 @@ func (_m *VRFCoordinatorV2Interface) WatchOwnershipTransferRequested(opts *bind. func (_m *VRFCoordinatorV2Interface) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferred, from []common.Address, to []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, from, to) + if len(ret) == 0 { + panic("no return value specified for WatchOwnershipTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2OwnershipTransferred, []common.Address, []common.Address) (event.Subscription, error)); ok { @@ -1884,6 +2172,10 @@ func (_m *VRFCoordinatorV2Interface) WatchOwnershipTransferred(opts *bind.WatchO func (_m *VRFCoordinatorV2Interface) WatchProvingKeyDeregistered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregistered, oracle []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, oracle) + if len(ret) == 0 { + panic("no return value specified for WatchProvingKeyDeregistered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyDeregistered, []common.Address) (event.Subscription, error)); ok { @@ -1910,6 +2202,10 @@ func (_m *VRFCoordinatorV2Interface) WatchProvingKeyDeregistered(opts *bind.Watc func (_m *VRFCoordinatorV2Interface) WatchProvingKeyRegistered(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegistered, oracle []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, oracle) + if len(ret) == 0 { + panic("no return value specified for WatchProvingKeyRegistered") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2ProvingKeyRegistered, []common.Address) (event.Subscription, error)); ok { @@ -1936,6 +2232,10 @@ func (_m *VRFCoordinatorV2Interface) WatchProvingKeyRegistered(opts *bind.WatchO func (_m *VRFCoordinatorV2Interface) WatchRandomWordsFulfilled(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, requestId []*big.Int) (event.Subscription, error) { ret := _m.Called(opts, sink, requestId) + if len(ret) == 0 { + panic("no return value specified for WatchRandomWordsFulfilled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, []*big.Int) (event.Subscription, error)); ok { @@ -1962,6 +2262,10 @@ func (_m *VRFCoordinatorV2Interface) WatchRandomWordsFulfilled(opts *bind.WatchO func (_m *VRFCoordinatorV2Interface) WatchRandomWordsRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, keyHash [][32]byte, subId []uint64, sender []common.Address) (event.Subscription, error) { ret := _m.Called(opts, sink, keyHash, subId, sender) + if len(ret) == 0 { + panic("no return value specified for WatchRandomWordsRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested, [][32]byte, []uint64, []common.Address) (event.Subscription, error)); ok { @@ -1988,6 +2292,10 @@ func (_m *VRFCoordinatorV2Interface) WatchRandomWordsRequested(opts *bind.WatchO func (_m *VRFCoordinatorV2Interface) WatchSubscriptionCanceled(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionCanceled") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, []uint64) (event.Subscription, error)); ok { @@ -2014,6 +2322,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionCanceled(opts *bind.WatchO func (_m *VRFCoordinatorV2Interface) WatchSubscriptionConsumerAdded(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionConsumerAdded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, []uint64) (event.Subscription, error)); ok { @@ -2040,6 +2352,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionConsumerAdded(opts *bind.W func (_m *VRFCoordinatorV2Interface) WatchSubscriptionConsumerRemoved(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionConsumerRemoved") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, []uint64) (event.Subscription, error)); ok { @@ -2066,6 +2382,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionConsumerRemoved(opts *bind func (_m *VRFCoordinatorV2Interface) WatchSubscriptionCreated(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionCreated") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, []uint64) (event.Subscription, error)); ok { @@ -2092,6 +2412,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionCreated(opts *bind.WatchOp func (_m *VRFCoordinatorV2Interface) WatchSubscriptionFunded(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionFunded") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, []uint64) (event.Subscription, error)); ok { @@ -2118,6 +2442,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionFunded(opts *bind.WatchOpt func (_m *VRFCoordinatorV2Interface) WatchSubscriptionOwnerTransferRequested(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequested, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionOwnerTransferRequested") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferRequested, []uint64) (event.Subscription, error)); ok { @@ -2144,6 +2472,10 @@ func (_m *VRFCoordinatorV2Interface) WatchSubscriptionOwnerTransferRequested(opt func (_m *VRFCoordinatorV2Interface) WatchSubscriptionOwnerTransferred(opts *bind.WatchOpts, sink chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferred, subId []uint64) (event.Subscription, error) { ret := _m.Called(opts, sink, subId) + if len(ret) == 0 { + panic("no return value specified for WatchSubscriptionOwnerTransferred") + } + var r0 event.Subscription var r1 error if rf, ok := ret.Get(0).(func(*bind.WatchOpts, chan<- *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionOwnerTransferred, []uint64) (event.Subscription, error)); ok { diff --git a/core/services/vrf/proof/proof_response.go b/core/services/vrf/proof/proof_response.go index 4cb58d921a4..f4e332616ca 100644 --- a/core/services/vrf/proof/proof_response.go +++ b/core/services/vrf/proof/proof_response.go @@ -13,9 +13,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ProofResponse is the data which is sent back to the VRFCoordinator, so that diff --git a/core/services/vrf/proof/seed.go b/core/services/vrf/proof/seed.go index 176a5e013ec..75dc441d881 100644 --- a/core/services/vrf/proof/seed.go +++ b/core/services/vrf/proof/seed.go @@ -7,7 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) // Seed represents a VRF seed as a serialized uint256 diff --git a/core/services/vrf/proof/solidity_proof.go b/core/services/vrf/proof/solidity_proof.go index c5823289cf1..48f2f9fd984 100644 --- a/core/services/vrf/proof/solidity_proof.go +++ b/core/services/vrf/proof/solidity_proof.go @@ -11,9 +11,9 @@ import ( "github.com/pkg/errors" "go.dedis.ch/kyber/v3" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - "github.com/smartcontractkit/chainlink/v2/core/utils" bm "github.com/smartcontractkit/chainlink/v2/core/utils/big_math" ) diff --git a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go index 35556c6b45f..24639af2f0d 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go +++ b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface.go @@ -8,8 +8,8 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // RawRandomnessRequestLog is used to parse a RandomnessRequest log into types @@ -35,7 +35,7 @@ func toGethLog(log types.Log) types.Log { return types.Log{ Address: log.Address, Topics: log.Topics, - Data: []byte(log.Data), + Data: log.Data, BlockNumber: log.BlockNumber, TxHash: log.TxHash, TxIndex: log.TxIndex, diff --git a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go index 2601f800e9e..47c47af7c9b 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go +++ b/core/services/vrf/solidity_cross_tests/vrf_coordinator_interface_test.go @@ -31,7 +31,7 @@ var ( Data: append(append(append(append( keyHash.Bytes(), common.BigToHash(seed).Bytes()...), - sender.Hash().Bytes()...), + common.BytesToHash(sender.Bytes()).Bytes()...), common.BigToHash(fee).Bytes()...), requestID.Bytes()...), Topics: []common.Hash{{}, jobID}, diff --git a/core/services/vrf/solidity_cross_tests/vrf_coordinator_solidity_crosscheck_test.go b/core/services/vrf/solidity_cross_tests/vrf_coordinator_solidity_crosscheck_test.go index 8dfbdae0148..946365e31a4 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_coordinator_solidity_crosscheck_test.go +++ b/core/services/vrf/solidity_cross_tests/vrf_coordinator_solidity_crosscheck_test.go @@ -13,9 +13,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/solidity_cross_tests" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" ) @@ -170,7 +170,7 @@ func TestRandomnessRequestLog(t *testing.T) { golangSeed := utils.MustHash(string(append(append(append( keyHash[:], common.BigToHash(hardcodedSeed).Bytes()...), - tc.consumerAddress.Hash().Bytes()...), + common.BytesToHash(tc.consumerAddress.Bytes()).Bytes()...), common.BigToHash(nonce).Bytes()...))) assert.Equal(t, golangSeed, common.BigToHash((log.Seed)), "VRFCoordinator logged different actual input seed than expected by golang code!") assert.Equal(t, jobID, log.JobID, "VRFCoordinator logged different JobID from randomness request!") diff --git a/core/services/vrf/solidity_cross_tests/vrf_solidity_crosscheck_test.go b/core/services/vrf/solidity_cross_tests/vrf_solidity_crosscheck_test.go index 06875edd74e..2476ee04ce2 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_solidity_crosscheck_test.go +++ b/core/services/vrf/solidity_cross_tests/vrf_solidity_crosscheck_test.go @@ -19,11 +19,11 @@ import ( "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Cross-checks of golang implementation details vs corresponding solidity diff --git a/core/services/vrf/solidity_cross_tests/vrf_v08_solidity_crosscheck_test.go b/core/services/vrf/solidity_cross_tests/vrf_v08_solidity_crosscheck_test.go index d1b21b58647..0552f93fea1 100644 --- a/core/services/vrf/solidity_cross_tests/vrf_v08_solidity_crosscheck_test.go +++ b/core/services/vrf/solidity_cross_tests/vrf_v08_solidity_crosscheck_test.go @@ -15,11 +15,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // Note these tests are identical to the ones in vrf_solidity_crosscheck_test.go, diff --git a/core/services/vrf/v1/integration_test.go b/core/services/vrf/v1/integration_test.go index a7dca56776f..b10ca160858 100644 --- a/core/services/vrf/v1/integration_test.go +++ b/core/services/vrf/v1/integration_test.go @@ -15,7 +15,9 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/guregu/null.v4" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "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/gethwrappers/generated/solidity_vrf_coordinator_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" @@ -27,9 +29,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestIntegration_VRF_JPV2(t *testing.T) { @@ -47,7 +47,7 @@ func TestIntegration_VRF_JPV2(t *testing.T) { t.Run(test.name, func(t *testing.T) { config, _ := heavyweight.FullTestDBV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = &test.eip1559 - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) key1 := cltest.MustGenerateRandomKey(t) key2 := cltest.MustGenerateRandomKey(t) @@ -133,8 +133,8 @@ func TestIntegration_VRF_WithBHS(t *testing.T) { c.EVM[0].BlockBackfillDepth = ptr[uint32](500) c.Feature.LogPoller = ptr(true) c.EVM[0].FinalityDepth = ptr[uint32](2) - c.EVM[0].LogPollInterval = models.MustNewDuration(time.Second) - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(time.Second) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) }) key := cltest.MustGenerateRandomKey(t) cu := vrftesthelpers.NewVRFCoordinatorUniverse(t, key) diff --git a/core/services/vrf/v1/listener_v1.go b/core/services/vrf/v1/listener_v1.go index 494847797fa..f4e813d7d61 100644 --- a/core/services/vrf/v1/listener_v1.go +++ b/core/services/vrf/v1/listener_v1.go @@ -17,6 +17,9 @@ import ( "github.com/theodesp/go-heaps/pairing" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -28,7 +31,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) var ( @@ -56,8 +58,8 @@ type Listener struct { Job job.Job Q pg.Q GethKs vrfcommon.GethKeyStore - MailMon *utils.MailboxMonitor - ReqLogs *utils.Mailbox[log.Broadcast] + MailMon *mailbox.Monitor + ReqLogs *mailbox.Mailbox[log.Broadcast] ChStop services.StopChan WaitOnStop chan struct{} NewHead chan struct{} diff --git a/core/services/vrf/v1/listener_v1_test.go b/core/services/vrf/v1/listener_v1_test.go index 4ab5d7ab368..c05358686df 100644 --- a/core/services/vrf/v1/listener_v1_test.go +++ b/core/services/vrf/v1/listener_v1_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/theodesp/go-heaps/pairing" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestConfirmedLogExtraction(t *testing.T) { diff --git a/core/services/vrf/v1/listener_v1_test_helpers.go b/core/services/vrf/v1/listener_v1_test_helpers.go index e9adde35b58..f9532bf83e6 100644 --- a/core/services/vrf/v1/listener_v1_test_helpers.go +++ b/core/services/vrf/v1/listener_v1_test_helpers.go @@ -3,6 +3,8 @@ package v1 import ( "testing" "time" + + "github.com/stretchr/testify/assert" ) func (lsn *Listener) SetReqAdded(fn func()) { @@ -10,7 +12,7 @@ func (lsn *Listener) SetReqAdded(fn func()) { } func (lsn *Listener) Stop(t *testing.T) { - lsn.ChStop <- struct{}{} + assert.NoError(t, lsn.Close()) select { case <-lsn.WaitOnStop: case <-time.After(time.Second): diff --git a/core/services/vrf/v2/bhs_feeder_test.go b/core/services/vrf/v2/bhs_feeder_test.go index 31a4ff815a9..a02eea75757 100644 --- a/core/services/vrf/v2/bhs_feeder_test.go +++ b/core/services/vrf/v2/bhs_feeder_test.go @@ -4,6 +4,9 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -11,9 +14,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - - "github.com/stretchr/testify/require" ) func TestStartHeartbeats(t *testing.T) { @@ -56,7 +56,7 @@ func TestStartHeartbeats(t *testing.T) { c.Feature.LogPoller = ptr(true) c.EVM[0].FinalityDepth = ptr[uint32](2) c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(gasLimit)) - c.EVM[0].LogPollInterval = models.MustNewDuration(time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(time.Second) }) heartbeatPeriod := 5 * time.Second diff --git a/core/services/vrf/v2/coordinator_v2x_interface.go b/core/services/vrf/v2/coordinator_v2x_interface.go index e20500cca89..e88053ebc2c 100644 --- a/core/services/vrf/v2/coordinator_v2x_interface.go +++ b/core/services/vrf/v2/coordinator_v2x_interface.go @@ -36,9 +36,11 @@ type CoordinatorV2_X interface { GetConfig(opts *bind.CallOpts) (Config, error) ParseLog(log types.Log) (generated.AbigenLog, error) OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) + Withdraw(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) + WithdrawNative(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) LogsWithTopics(keyHash common.Hash) map[common.Hash][][]log.Topic Version() vrfcommon.Version - RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) + RegisterProvingKey(opts *bind.TransactOpts, oracle *common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) FilterSubscriptionCreated(opts *bind.FilterOpts, subID []*big.Int) (SubscriptionCreatedIterator, error) FilterRandomWordsRequested(opts *bind.FilterOpts, keyHash [][32]byte, subID []*big.Int, sender []common.Address) (RandomWordsRequestedIterator, error) FilterRandomWordsFulfilled(opts *bind.FilterOpts, requestID []*big.Int, subID []*big.Int) (RandomWordsFulfilledIterator, error) @@ -130,6 +132,14 @@ func (c *coordinatorV2) OracleWithdraw(opts *bind.TransactOpts, recipient common return c.coordinator.OracleWithdraw(opts, recipient, amount) } +func (c *coordinatorV2) Withdraw(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) { + return nil, errors.New("withdraw not implemented for v2") +} + +func (c *coordinatorV2) WithdrawNative(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) { + return nil, errors.New("withdrawNative not implemented for v2") +} + func (c *coordinatorV2) LogsWithTopics(keyHash common.Hash) map[common.Hash][][]log.Topic { return map[common.Hash][][]log.Topic{ vrf_coordinator_v2.VRFCoordinatorV2RandomWordsRequested{}.Topic(): { @@ -144,8 +154,8 @@ func (c *coordinatorV2) Version() vrfcommon.Version { return c.vrfVersion } -func (c *coordinatorV2) RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return c.coordinator.RegisterProvingKey(opts, oracle, publicProvingKey) +func (c *coordinatorV2) RegisterProvingKey(opts *bind.TransactOpts, oracle *common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + return c.coordinator.RegisterProvingKey(opts, *oracle, publicProvingKey) } func (c *coordinatorV2) FilterSubscriptionCreated(opts *bind.FilterOpts, subID []*big.Int) (SubscriptionCreatedIterator, error) { @@ -281,7 +291,15 @@ func (c *coordinatorV2_5) ParseLog(log types.Log) (generated.AbigenLog, error) { } func (c *coordinatorV2_5) OracleWithdraw(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { - return c.coordinator.OracleWithdraw(opts, recipient, amount) + return nil, errors.New("oracle withdraw not implemented for v2.5") +} + +func (c *coordinatorV2_5) Withdraw(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) { + return c.coordinator.Withdraw(opts, recipient) +} + +func (c *coordinatorV2_5) WithdrawNative(opts *bind.TransactOpts, recipient common.Address) (*types.Transaction, error) { + return c.coordinator.WithdrawNative(opts, recipient) } func (c *coordinatorV2_5) LogsWithTopics(keyHash common.Hash) map[common.Hash][][]log.Topic { @@ -298,8 +316,11 @@ func (c *coordinatorV2_5) Version() vrfcommon.Version { return c.vrfVersion } -func (c *coordinatorV2_5) RegisterProvingKey(opts *bind.TransactOpts, oracle common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { - return c.coordinator.RegisterProvingKey(opts, oracle, publicProvingKey) +func (c *coordinatorV2_5) RegisterProvingKey(opts *bind.TransactOpts, oracle *common.Address, publicProvingKey [2]*big.Int) (*types.Transaction, error) { + if oracle != nil { + return nil, errors.New("oracle address not supported for registering proving key in v2.5") + } + return c.coordinator.RegisterProvingKey(opts, publicProvingKey) } func (c *coordinatorV2_5) FilterSubscriptionCreated(opts *bind.FilterOpts, subID []*big.Int) (SubscriptionCreatedIterator, error) { diff --git a/core/services/vrf/v2/integration_helpers_test.go b/core/services/vrf/v2/integration_helpers_test.go index 03d96cadf20..47d0089ade6 100644 --- a/core/services/vrf/v2/integration_helpers_test.go +++ b/core/services/vrf/v2/integration_helpers_test.go @@ -16,11 +16,14 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" v2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + 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/gethwrappers/generated/vrf_consumer_v2_upgradeable_example" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_external_sub_owner_example" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_transparent_upgradeable_proxy" @@ -30,11 +33,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" v22 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -73,7 +74,7 @@ func testSingleConsumerHappyPath( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1, key2) @@ -207,7 +208,7 @@ func testMultipleConsumersNeedBHS( simulatedOverrides(t, assets.GWei(10), keySpecificOverrides...)(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].FinalityDepth = ptr[uint32](2) }) keys = append(keys, ownerKey, vrfKey) @@ -355,7 +356,7 @@ func testMultipleConsumersNeedTrustedBHS( c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(5_000_000)) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].FinalityDepth = ptr[uint32](2) }) keys = append(keys, ownerKey, vrfKey) @@ -540,9 +541,9 @@ func testSingleConsumerHappyPathBatchFulfillment( })(c, s) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) @@ -646,7 +647,7 @@ func testSingleConsumerNeedsTopUp( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key) @@ -752,7 +753,7 @@ func testBlockHeaderFeeder( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].FinalityDepth = ptr[uint32](2) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, vrfKey, bhfKey) @@ -869,7 +870,7 @@ func setupAndFundSubscriptionAndConsumer( uni.backend.Commit() if vrfVersion == vrfcommon.V2Plus { - b, err2 := utils.ABIEncode(`[{"type":"uint256"}]`, subID) + b, err2 := evmutils.ABIEncode(`[{"type":"uint256"}]`, subID) require.NoError(t, err2) _, err2 = uni.linkContract.TransferAndCall( uni.sergey, coordinatorAddress, fundingAmount, b) @@ -877,7 +878,7 @@ func setupAndFundSubscriptionAndConsumer( uni.backend.Commit() return } - b, err := utils.ABIEncode(`[{"type":"uint64"}]`, subID.Uint64()) + b, err := evmutils.ABIEncode(`[{"type":"uint64"}]`, subID.Uint64()) require.NoError(t, err) _, err = uni.linkContract.TransferAndCall( uni.sergey, coordinatorAddress, fundingAmount, b) @@ -911,7 +912,7 @@ func testSingleConsumerForcedFulfillment( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1, key2) @@ -1074,7 +1075,7 @@ func testSingleConsumerEIP150( c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(3.5e6)) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) consumer := uni.vrfConsumers[0] @@ -1144,7 +1145,7 @@ func testSingleConsumerEIP150Revert( c.EVM[0].GasEstimator.LimitDefault = ptr(uint32(gasLimit)) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) consumer := uni.vrfConsumers[0] @@ -1209,7 +1210,7 @@ func testSingleConsumerBigGasCallbackSandwich( c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) consumer := uni.vrfConsumers[0] @@ -1331,7 +1332,7 @@ func testSingleConsumerMultipleGasLanes( c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, cheapKey, expensiveKey) @@ -1448,7 +1449,7 @@ func testSingleConsumerAlwaysRevertingCallbackStillFulfilled( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key) consumer := uni.reverter @@ -1521,7 +1522,7 @@ func testConsumerProxyHappyPath( })(c, s) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1, key2) consumerOwner := uni.neil @@ -1645,9 +1646,9 @@ func testMaliciousConsumer( c.EVM[0].GasEstimator.PriceMax = assets.GWei(1) c.EVM[0].GasEstimator.PriceDefault = assets.GWei(1) c.EVM[0].GasEstimator.FeeCapDefault = assets.GWei(1) - c.EVM[0].ChainID = (*utils.Big)(testutils.SimulatedChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.SimulatedChainID) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) carol := uni.vrfConsumers[0] @@ -1681,11 +1682,7 @@ func testMaliciousConsumer( time.Sleep(1 * time.Second) // Register a proving key associated with the VRF job. - p, err := vrfkey.PublicKey.Point() - require.NoError(t, err) - _, err = uni.rootContract.RegisterProvingKey( - uni.neil, uni.nallory.From, pair(secp256k1.Coordinates(p))) - require.NoError(t, err) + registerProvingKeyHelper(t, uni, uni.rootContract, vrfkey) subFunding := decimal.RequireFromString("1000000000000000000") _, err = uni.maliciousConsumerContract.CreateSubscriptionAndFund(carol, diff --git a/core/services/vrf/v2/integration_v2_plus_test.go b/core/services/vrf/v2/integration_v2_plus_test.go index 1564f0f6343..e5eed6f09bc 100644 --- a/core/services/vrf/v2/integration_v2_plus_test.go +++ b/core/services/vrf/v2/integration_v2_plus_test.go @@ -16,9 +16,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2plus" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" @@ -44,14 +46,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "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/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/extraargs" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/proof" v22 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type coordinatorV2PlusUniverse struct { @@ -850,12 +849,7 @@ func TestVRFV2PlusIntegration_RequestCost(t *testing.T) { vrfkey, err := app.GetKeyStore().VRF().Create() require.NoError(t, err) - p, err := vrfkey.PublicKey.Point() - require.NoError(t, err) - _, err = uni.rootContract.RegisterProvingKey( - uni.neil, uni.neil.From, pair(secp256k1.Coordinates(p))) - require.NoError(t, err) - uni.backend.Commit() + registerProvingKeyHelper(t, uni.coordinatorV2UniverseCommon, uni.rootContract, vrfkey) t.Run("non-proxied consumer", func(tt *testing.T) { carol := uni.vrfConsumers[0] carolContract := uni.consumerContracts[0] @@ -1010,12 +1004,7 @@ func TestVRFV2PlusIntegration_FulfillmentCost(t *testing.T) { vrfkey, err := app.GetKeyStore().VRF().Create() require.NoError(t, err) - p, err := vrfkey.PublicKey.Point() - require.NoError(t, err) - _, err = uni.rootContract.RegisterProvingKey( - uni.neil, uni.neil.From, pair(secp256k1.Coordinates(p))) - require.NoError(t, err) - uni.backend.Commit() + registerProvingKeyHelper(t, uni.coordinatorV2UniverseCommon, uni.rootContract, vrfkey) t.Run("non-proxied consumer", func(tt *testing.T) { carol := uni.vrfConsumers[0] @@ -1158,7 +1147,7 @@ func TestVRFV2PlusIntegration_Migration(t *testing.T) { c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](5_000_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, config, uni.backend, ownerKey, key1) diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index fa95b694f98..d415793ede4 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -30,7 +30,9 @@ import ( "github.com/jmoiron/sqlx" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -40,6 +42,8 @@ import ( evmlogger "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "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" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_vrf_coordinator_v2" @@ -79,7 +83,6 @@ import ( v22 "github.com/smartcontractkit/chainlink/v2/core/services/vrf/v2" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrftesthelpers" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -427,7 +430,7 @@ func deployOldCoordinator( ) { ctx := testutils.Context(t) bytecode := hexutil.MustDecode("0x60e06040523480156200001157600080fd5b506040516200608c3803806200608c8339810160408190526200003491620001b1565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e8565b5050506001600160601b0319606093841b811660805290831b811660a052911b1660c052620001fb565b6001600160a01b038116331415620001435760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001ac57600080fd5b919050565b600080600060608486031215620001c757600080fd5b620001d28462000194565b9250620001e26020850162000194565b9150620001f26040850162000194565b90509250925092565b60805160601c60a05160601c60c05160601c615e2762000265600039600081816105260152613bd901526000818161061d015261402401526000818161036d01528181611599015281816125960152818161302c0152818161318201526138360152615e276000f3fe608060405234801561001057600080fd5b506004361061025b5760003560e01c80636f64f03f11610145578063ad178361116100bd578063d2f9f9a71161008c578063e72f6e3011610071578063e72f6e30146106fa578063e82ad7d41461070d578063f2fde38b1461073057600080fd5b8063d2f9f9a7146106d4578063d7ae1d30146106e757600080fd5b8063ad17836114610618578063af198b971461063f578063c3f909d41461066f578063caf70c4a146106c157600080fd5b80638da5cb5b11610114578063a21a23e4116100f9578063a21a23e4146105da578063a47c7696146105e2578063a4c0ed361461060557600080fd5b80638da5cb5b146105a95780639f87fad7146105c757600080fd5b80636f64f03f146105685780637341c10c1461057b57806379ba50971461058e578063823597401461059657600080fd5b8063356dac71116101d85780635fbbc0d2116101a757806366316d8d1161018c57806366316d8d1461050e578063689c45171461052157806369bcdb7d1461054857600080fd5b80635fbbc0d21461040057806364d51a2a1461050657600080fd5b8063356dac71146103b457806340d6bb82146103bc5780634cb48a54146103da5780635d3b1d30146103ed57600080fd5b806308821d581161022f57806315c48b841161021457806315c48b841461030e578063181f5a77146103295780631b6b6d231461036857600080fd5b806308821d58146102cf57806312b58349146102e257600080fd5b80620122911461026057806302bcc5b61461028057806304c357cb1461029557806306bfa637146102a8575b600080fd5b610268610743565b60405161027793929190615964565b60405180910390f35b61029361028e366004615792565b6107bf565b005b6102936102a33660046157ad565b61086b565b60055467ffffffffffffffff165b60405167ffffffffffffffff9091168152602001610277565b6102936102dd3660046154a3565b610a60565b6005546801000000000000000090046bffffffffffffffffffffffff165b604051908152602001610277565b61031660c881565b60405161ffff9091168152602001610277565b604080518082018252601681527f565246436f6f7264696e61746f72563220312e302e30000000000000000000006020820152905161027791906158f1565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610277565b600a54610300565b6103c56101f481565b60405163ffffffff9091168152602001610277565b6102936103e836600461563c565b610c3f565b6103006103fb366004615516565b611036565b600c546040805163ffffffff80841682526401000000008404811660208301526801000000000000000084048116928201929092526c010000000000000000000000008304821660608201527001000000000000000000000000000000008304909116608082015262ffffff740100000000000000000000000000000000000000008304811660a0830152770100000000000000000000000000000000000000000000008304811660c08301527a0100000000000000000000000000000000000000000000000000008304811660e08301527d01000000000000000000000000000000000000000000000000000000000090920490911661010082015261012001610277565b610316606481565b61029361051c36600461545b565b611444565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b610300610556366004615779565b60009081526009602052604090205490565b6102936105763660046153a0565b6116ad565b6102936105893660046157ad565b6117f7565b610293611a85565b6102936105a4366004615792565b611b82565b60005473ffffffffffffffffffffffffffffffffffffffff1661038f565b6102936105d53660046157ad565b611d7c565b6102b66121fd565b6105f56105f0366004615792565b6123ed565b6040516102779493929190615b02565b6102936106133660046153d4565b612537565b61038f7f000000000000000000000000000000000000000000000000000000000000000081565b61065261064d366004615574565b6127a8565b6040516bffffffffffffffffffffffff9091168152602001610277565b600b546040805161ffff8316815263ffffffff6201000084048116602083015267010000000000000084048116928201929092526b010000000000000000000000909204166060820152608001610277565b6103006106cf3660046154bf565b612c6d565b6103c56106e2366004615792565b612c9d565b6102936106f53660046157ad565b612e92565b610293610708366004615385565b612ff3565b61072061071b366004615792565b613257565b6040519015158152602001610277565b61029361073e366004615385565b6134ae565b600b546007805460408051602080840282018101909252828152600094859460609461ffff8316946201000090930463ffffffff169391928391908301828280156107ad57602002820191906000526020600020905b815481526020019060010190808311610799575b50505050509050925092509250909192565b6107c76134bf565b67ffffffffffffffff811660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1661082d576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660009081526003602052604090205461086890829073ffffffffffffffffffffffffffffffffffffffff16613542565b50565b67ffffffffffffffff8216600090815260036020526040902054829073ffffffffffffffffffffffffffffffffffffffff16806108d4576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821614610940576040517fd8a3fb5200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b600b546601000000000000900460ff1615610987576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff841660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff848116911614610a5a5767ffffffffffffffff841660008181526003602090815260409182902060010180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88169081179091558251338152918201527f69436ea6df009049404f564eff6622cd00522b0bd6a89efd9e52a355c4a879be91015b60405180910390a25b50505050565b610a686134bf565b604080518082018252600091610a97919084906002908390839080828437600092019190915250612c6d915050565b60008181526006602052604090205490915073ffffffffffffffffffffffffffffffffffffffff1680610af9576040517f77f5b84c00000000000000000000000000000000000000000000000000000000815260048101839052602401610937565b600082815260066020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b600754811015610be9578260078281548110610b4c57610b4c615dbc565b90600052602060002001541415610bd7576007805460009190610b7190600190615c76565b81548110610b8157610b81615dbc565b906000526020600020015490508060078381548110610ba257610ba2615dbc565b6000918252602090912001556007805480610bbf57610bbf615d8d565b60019003818190600052602060002001600090559055505b80610be181615cba565b915050610b2e565b508073ffffffffffffffffffffffffffffffffffffffff167f72be339577868f868798bac2c93e52d6f034fef4689a9848996c14ebb7416c0d83604051610c3291815260200190565b60405180910390a2505050565b610c476134bf565b60c861ffff87161115610c9a576040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff871660048201819052602482015260c86044820152606401610937565b60008213610cd7576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610937565b6040805160a0808201835261ffff891680835263ffffffff89811660208086018290526000868801528a831660608088018290528b85166080988901819052600b80547fffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000001690971762010000909502949094177fffffffffffffffffffffffffffffffffff000000000000000000ffffffffffff166701000000000000009092027fffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffff16919091176b010000000000000000000000909302929092179093558651600c80549489015189890151938a0151978a0151968a015160c08b015160e08c01516101008d01519588167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009099169890981764010000000093881693909302929092177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000958716959095027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16949094176c0100000000000000000000000098861698909802979097177fffffffffffffffffff00000000000000ffffffffffffffffffffffffffffffff1670010000000000000000000000000000000096909416959095027fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff16929092177401000000000000000000000000000000000000000062ffffff92831602177fffffff000000000000ffffffffffffffffffffffffffffffffffffffffffffff1677010000000000000000000000000000000000000000000000958216959095027fffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffff16949094177a01000000000000000000000000000000000000000000000000000092851692909202919091177cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167d0100000000000000000000000000000000000000000000000000000000009390911692909202919091178155600a84905590517fc21e3bd2e0b339d2848f0dd956947a88966c242c0c0c582a33137a5c1ceb5cb2916110269189918991899189918991906159c3565b60405180910390a1505050505050565b600b546000906601000000000000900460ff1615611080576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff851660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff166110e6576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260026020908152604080832067ffffffffffffffff808a1685529252909120541680611156576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff87166004820152336024820152604401610937565b600b5461ffff9081169086161080611172575060c861ffff8616115b156111c257600b546040517fa738697600000000000000000000000000000000000000000000000000000000815261ffff8088166004830152909116602482015260c86044820152606401610937565b600b5463ffffffff620100009091048116908516111561122957600b546040517ff5d7e01e00000000000000000000000000000000000000000000000000000000815263ffffffff8087166004830152620100009092049091166024820152604401610937565b6101f463ffffffff8416111561127b576040517f47386bec00000000000000000000000000000000000000000000000000000000815263ffffffff841660048201526101f46024820152604401610937565b6000611288826001615bd2565b6040805160208082018c9052338284015267ffffffffffffffff808c16606084015284166080808401919091528351808403909101815260a08301845280519082012060c083018d905260e080840182905284518085039091018152610100909301909352815191012091925060009182916040805160208101849052439181019190915267ffffffffffffffff8c16606082015263ffffffff808b166080830152891660a08201523360c0820152919350915060e001604080518083037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018152828252805160209182012060008681526009835283902055848352820183905261ffff8a169082015263ffffffff808916606083015287166080820152339067ffffffffffffffff8b16908c907f63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a97729060a00160405180910390a45033600090815260026020908152604080832067ffffffffffffffff808d16855292529091208054919093167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009091161790915591505095945050505050565b600b546601000000000000900460ff161561148b576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600860205260409020546bffffffffffffffffffffffff808316911610156114e5576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260086020526040812080548392906115129084906bffffffffffffffffffffffff16615c8d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555080600560088282829054906101000a90046bffffffffffffffffffffffff166115699190615c8d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff1660e01b815260040161162192919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b602060405180830381600087803b15801561163b57600080fd5b505af115801561164f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167391906154db565b6116a9576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b6116b56134bf565b6040805180820182526000916116e4919084906002908390839080828437600092019190915250612c6d915050565b60008181526006602052604090205490915073ffffffffffffffffffffffffffffffffffffffff1615611746576040517f4a0b8fa700000000000000000000000000000000000000000000000000000000815260048101829052602401610937565b600081815260066020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88169081179091556007805460018101825594527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688909301849055518381527fe729ae16526293f74ade739043022254f1489f616295a25bf72dfb4511ed73b89101610c32565b67ffffffffffffffff8216600090815260036020526040902054829073ffffffffffffffffffffffffffffffffffffffff1680611860576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff8216146118c7576040517fd8a3fb5200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610937565b600b546601000000000000900460ff161561190e576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff841660009081526003602052604090206002015460641415611965576040517f05a48e0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020908152604080832067ffffffffffffffff808916855292529091205416156119ac57610a5a565b73ffffffffffffffffffffffffffffffffffffffff8316600081815260026020818152604080842067ffffffffffffffff8a1680865290835281852080547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001908117909155600384528286209094018054948501815585529382902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001685179055905192835290917f43dc749a04ac8fb825cbd514f7c0e13f13bc6f2ee66043b76629d51776cff8e09101610a51565b60015473ffffffffffffffffffffffffffffffffffffffff163314611b06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e6572000000000000000000006044820152606401610937565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b600b546601000000000000900460ff1615611bc9576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff16611c2f576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff811660009081526003602052604090206001015473ffffffffffffffffffffffffffffffffffffffff163314611cd15767ffffffffffffffff8116600090815260036020526040908190206001015490517fd084e97500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401610937565b67ffffffffffffffff81166000818152600360209081526040918290208054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560019093018054909316909255835173ffffffffffffffffffffffffffffffffffffffff909116808252928101919091529092917f6f1dc65165ffffedfd8e507b4a0f1fcfdada045ed11f6c26ba27cedfe87802f0910160405180910390a25050565b67ffffffffffffffff8216600090815260036020526040902054829073ffffffffffffffffffffffffffffffffffffffff1680611de5576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821614611e4c576040517fd8a3fb5200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610937565b600b546601000000000000900460ff1615611e93576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020908152604080832067ffffffffffffffff808916855292529091205416611f2e576040517ff0019fe600000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff84166024820152604401610937565b67ffffffffffffffff8416600090815260036020908152604080832060020180548251818502810185019093528083529192909190830182828015611fa957602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611f7e575b50505050509050600060018251611fc09190615c76565b905060005b825181101561215f578573ffffffffffffffffffffffffffffffffffffffff16838281518110611ff757611ff7615dbc565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16141561214d57600083838151811061202f5761202f615dbc565b6020026020010151905080600360008a67ffffffffffffffff1667ffffffffffffffff168152602001908152602001600020600201838154811061207557612075615dbc565b600091825260208083209190910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff949094169390931790925567ffffffffffffffff8a1681526003909152604090206002018054806120ef576120ef615d8d565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190555061215f565b8061215781615cba565b915050611fc5565b5073ffffffffffffffffffffffffffffffffffffffff8516600081815260026020908152604080832067ffffffffffffffff8b168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690555192835290917f182bff9831466789164ca77075fffd84916d35a8180ba73c27e45634549b445b91015b60405180910390a2505050505050565b600b546000906601000000000000900460ff1615612247576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005805467ffffffffffffffff1690600061226183615cf3565b82546101009290920a67ffffffffffffffff8181021990931691831602179091556005541690506000806040519080825280602002602001820160405280156122b4578160200160208202803683370190505b506040805180820182526000808252602080830182815267ffffffffffffffff888116808552600484528685209551865493516bffffffffffffffffffffffff9091167fffffffffffffffffffffffff0000000000000000000000000000000000000000948516176c010000000000000000000000009190931602919091179094558451606081018652338152808301848152818701888152958552600384529590932083518154831673ffffffffffffffffffffffffffffffffffffffff918216178255955160018201805490931696169590951790559151805194955090936123a592600285019201906150c5565b505060405133815267ffffffffffffffff841691507f464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf9060200160405180910390a250905090565b67ffffffffffffffff81166000908152600360205260408120548190819060609073ffffffffffffffffffffffffffffffffffffffff1661245a576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff80861660009081526004602090815260408083205460038352928190208054600290910180548351818602810186019094528084526bffffffffffffffffffffffff8616966c010000000000000000000000009096049095169473ffffffffffffffffffffffffffffffffffffffff90921693909291839183018282801561252157602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116124f6575b5050505050905093509350935093509193509193565b600b546601000000000000900460ff161561257e576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146125ed576040517f44b0e3c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208114612627576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061263582840184615792565b67ffffffffffffffff811660009081526003602052604090205490915073ffffffffffffffffffffffffffffffffffffffff1661269e576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff8116600090815260046020526040812080546bffffffffffffffffffffffff16918691906126d58385615bfe565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff16021790555084600560088282829054906101000a90046bffffffffffffffffffffffff1661272c9190615bfe565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508167ffffffffffffffff167fd39ec07f4e209f627a4c427971473820dc129761ba28de8906bd56f57101d4f88287846127939190615bba565b604080519283526020830191909152016121ed565b600b546000906601000000000000900460ff16156127f2576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a9050600080600061280687876139b5565b9250925092506000866060015163ffffffff1667ffffffffffffffff81111561283157612831615deb565b60405190808252806020026020018201604052801561285a578160200160208202803683370190505b50905060005b876060015163ffffffff168110156128ce5760408051602081018590529081018290526060016040516020818303038152906040528051906020012060001c8282815181106128b1576128b1615dbc565b6020908102919091010152806128c681615cba565b915050612860565b506000838152600960205260408082208290555181907f1fe543e300000000000000000000000000000000000000000000000000000000906129169087908690602401615ab4565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff166601000000000000179055908a015160808b01519192506000916129e49163ffffffff169084613d04565b600b80547fffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffff1690556020808c01805167ffffffffffffffff9081166000908152600490935260408084205492518216845290922080549394506c01000000000000000000000000918290048316936001939192600c92612a68928692900416615bd2565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506000612abf8a600b600001600b9054906101000a900463ffffffff1663ffffffff16612ab985612c9d565b3a613d52565b6020808e015167ffffffffffffffff166000908152600490915260409020549091506bffffffffffffffffffffffff80831691161015612b2b576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6020808d015167ffffffffffffffff1660009081526004909152604081208054839290612b679084906bffffffffffffffffffffffff16615c8d565b82546101009290920a6bffffffffffffffffffffffff81810219909316918316021790915560008b81526006602090815260408083205473ffffffffffffffffffffffffffffffffffffffff1683526008909152812080548594509092612bd091859116615bfe565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550877f7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4888386604051612c53939291909283526bffffffffffffffffffffffff9190911660208301521515604082015260600190565b60405180910390a299505050505050505050505b92915050565b600081604051602001612c8091906158e3565b604051602081830303815290604052805190602001209050919050565b6040805161012081018252600c5463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c010000000000000000000000008104831660608301527001000000000000000000000000000000008104909216608082015262ffffff740100000000000000000000000000000000000000008304811660a08301819052770100000000000000000000000000000000000000000000008404821660c08401527a0100000000000000000000000000000000000000000000000000008404821660e08401527d0100000000000000000000000000000000000000000000000000000000009093041661010082015260009167ffffffffffffffff841611612dbb575192915050565b8267ffffffffffffffff168160a0015162ffffff16108015612df057508060c0015162ffffff168367ffffffffffffffff1611155b15612dff576020015192915050565b8267ffffffffffffffff168160c0015162ffffff16108015612e3457508060e0015162ffffff168367ffffffffffffffff1611155b15612e43576040015192915050565b8267ffffffffffffffff168160e0015162ffffff16108015612e79575080610100015162ffffff168367ffffffffffffffff1611155b15612e88576060015192915050565b6080015192915050565b67ffffffffffffffff8216600090815260036020526040902054829073ffffffffffffffffffffffffffffffffffffffff1680612efb576040517f1f6a65b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821614612f62576040517fd8a3fb5200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401610937565b600b546601000000000000900460ff1615612fa9576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612fb284613257565b15612fe9576040517fb42f66e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a5a8484613542565b612ffb6134bf565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a082319060240160206040518083038186803b15801561308357600080fd5b505afa158015613097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130bb91906154fd565b6005549091506801000000000000000090046bffffffffffffffffffffffff168181111561311f576040517fa99da3020000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401610937565b818110156132525760006131338284615c76565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb90604401602060405180830381600087803b1580156131c857600080fd5b505af11580156131dc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061320091906154db565b506040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527f59bfc682b673f8cbf945f1e454df9334834abf7dfe7f92237ca29ecb9b436600910160405180910390a1505b505050565b67ffffffffffffffff811660009081526003602090815260408083208151606081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015416818501526002820180548451818702810187018652818152879693958601939092919083018282801561330657602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116132db575b505050505081525050905060005b8160400151518110156134a45760005b60075481101561349157600061345a6007838154811061334657613346615dbc565b90600052602060002001548560400151858151811061336757613367615dbc565b602002602001015188600260008960400151898151811061338a5761338a615dbc565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff808f168352935220541660408051602080820187905273ffffffffffffffffffffffffffffffffffffffff959095168183015267ffffffffffffffff9384166060820152919092166080808301919091528251808303909101815260a08201835280519084012060c082019490945260e080820185905282518083039091018152610100909101909152805191012091565b506000818152600960205260409020549091501561347e5750600195945050505050565b508061348981615cba565b915050613324565b508061349c81615cba565b915050613314565b5060009392505050565b6134b66134bf565b61086881613e5a565b60005473ffffffffffffffffffffffffffffffffffffffff163314613540576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610937565b565b600b546601000000000000900460ff1615613589576040517fed3ba6a600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff821660009081526003602090815260408083208151606081018352815473ffffffffffffffffffffffffffffffffffffffff90811682526001830154168185015260028201805484518187028101870186528181529295939486019383018282801561363457602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311613609575b5050509190925250505067ffffffffffffffff80851660009081526004602090815260408083208151808301909252546bffffffffffffffffffffffff81168083526c01000000000000000000000000909104909416918101919091529293505b83604001515181101561373b5760026000856040015183815181106136bc576136bc615dbc565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040908101600090812067ffffffffffffffff8a168252909252902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001690558061373381615cba565b915050613695565b5067ffffffffffffffff8516600090815260036020526040812080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081168255600182018054909116905590613796600283018261514f565b505067ffffffffffffffff8516600090815260046020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055600580548291906008906138069084906801000000000000000090046bffffffffffffffffffffffff16615c8d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85836bffffffffffffffffffffffff166040518363ffffffff1660e01b81526004016138be92919073ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b602060405180830381600087803b1580156138d857600080fd5b505af11580156138ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061391091906154db565b613946576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805173ffffffffffffffffffffffffffffffffffffffff861681526bffffffffffffffffffffffff8316602082015267ffffffffffffffff8716917fe8ed5b475a5b5987aa9165e8731bb78043f39eee32ec5a1169a89e27fcd49815910160405180910390a25050505050565b60008060006139c78560000151612c6d565b60008181526006602052604090205490935073ffffffffffffffffffffffffffffffffffffffff1680613a29576040517f77f5b84c00000000000000000000000000000000000000000000000000000000815260048101859052602401610937565b6080860151604051613a48918691602001918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291815281516020928301206000818152600990935291205490935080613ac5576040517f3688124a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85516020808801516040808a015160608b015160808c01519251613b3e968b96909594910195865267ffffffffffffffff948516602087015292909316604085015263ffffffff908116606085015291909116608083015273ffffffffffffffffffffffffffffffffffffffff1660a082015260c00190565b604051602081830303815290604052805190602001208114613b8c576040517fd529142c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855167ffffffffffffffff164080613cb05786516040517fe9413d3800000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90911660048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063e9413d389060240160206040518083038186803b158015613c3057600080fd5b505afa158015613c44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c6891906154fd565b905080613cb05786516040517f175dadad00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9091166004820152602401610937565b6000886080015182604051602001613cd2929190918252602082015260400190565b6040516020818303038152906040528051906020012060001c9050613cf78982613f50565b9450505050509250925092565b60005a611388811015613d1657600080fd5b611388810390508460408204820311613d2e57600080fd5b50823b613d3a57600080fd5b60008083516020850160008789f190505b9392505050565b600080613d5d613fd9565b905060008113613d9c576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101829052602401610937565b6000815a613daa8989615bba565b613db49190615c76565b613dc686670de0b6b3a7640000615c39565b613dd09190615c39565b613dda9190615c25565b90506000613df363ffffffff871664e8d4a51000615c39565b9050613e0b816b033b2e3c9fd0803ce8000000615c76565b821115613e44576040517fe80fa38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b613e4e8183615bba565b98975050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116331415613eda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610937565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000613f848360000151846020015185604001518660600151868860a001518960c001518a60e001518b61010001516140ed565b60038360200151604051602001613f9c929190615aa0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b600b54604080517ffeaf968c0000000000000000000000000000000000000000000000000000000081529051600092670100000000000000900463ffffffff169182151591849182917f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169163feaf968c9160048083019260a0929190829003018186803b15801561407f57600080fd5b505afa158015614093573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140b791906157d7565b5094509092508491505080156140db57506140d28242615c76565b8463ffffffff16105b156140e55750600a545b949350505050565b6140f6896143c4565b61415c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f7075626c6963206b6579206973206e6f74206f6e2063757276650000000000006044820152606401610937565b614165886143c4565b6141cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f67616d6d61206973206e6f74206f6e20637572766500000000000000000000006044820152606401610937565b6141d4836143c4565b61423a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f6347616d6d615769746e657373206973206e6f74206f6e2063757276650000006044820152606401610937565b614243826143c4565b6142a9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f73486173685769746e657373206973206e6f74206f6e206375727665000000006044820152606401610937565b6142b5878a888761451f565b61431b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f6164647228632a706b2b732a6729213d5f755769746e657373000000000000006044820152606401610937565b60006143278a876146c2565b9050600061433a898b878b868989614726565b9050600061434b838d8d8a866148ae565b9050808a146143b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f696e76616c69642070726f6f66000000000000000000000000000000000000006044820152606401610937565b505050505050505050505050565b80516000907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f11614451576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c696420782d6f7264696e61746500000000000000000000000000006044820152606401610937565b60208201517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f116144de576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f696e76616c696420792d6f7264696e61746500000000000000000000000000006044820152606401610937565b60208201517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f9080096145188360005b602002015161490c565b1492915050565b600073ffffffffffffffffffffffffffffffffffffffff821661459e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f626164207769746e6573730000000000000000000000000000000000000000006044820152606401610937565b6020840151600090600116156145b557601c6145b8565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418587600060200201510986517ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141918203925060009190890987516040805160008082526020820180845287905260ff88169282019290925260608101929092526080820183905291925060019060a0016020604051602081039080840390855afa15801561466f573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015173ffffffffffffffffffffffffffffffffffffffff9081169088161495505050505050949350505050565b6146ca61516d565b6146f7600184846040516020016146e3939291906158c2565b604051602081830303815290604052614964565b90505b614703816143c4565b612c6757805160408051602081019290925261471f91016146e3565b90506146fa565b61472e61516d565b825186517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f90819006910614156147c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f706f696e747320696e2073756d206d7573742062652064697374696e637400006044820152606401610937565b6147cc8789886149cd565b614832576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4669727374206d756c20636865636b206661696c6564000000000000000000006044820152606401610937565b61483d8486856149cd565b6148a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5365636f6e64206d756c20636865636b206661696c65640000000000000000006044820152606401610937565b613e4e868484614b5a565b6000600286868685876040516020016148cc96959493929190615850565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209695505050505050565b6000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f80848509840990507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f600782089392505050565b61496c61516d565b61497582614c89565b815261498a61498582600061450e565b614cde565b6020820181905260029006600114156149c8576020810180517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0390525b919050565b600082614a36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f7a65726f207363616c61720000000000000000000000000000000000000000006044820152606401610937565b83516020850151600090614a4c90600290615d1b565b15614a5857601c614a5b565b601b5b905060007ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641418387096040805160008082526020820180845281905260ff86169282019290925260608101869052608081018390529192509060019060a0016020604051602081039080840390855afa158015614adb573d6000803e3d6000fd5b505050602060405103519050600086604051602001614afa919061583e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012073ffffffffffffffffffffffffffffffffffffffff92831692169190911498975050505050505050565b614b6261516d565b835160208086015185519186015160009384938493614b8393909190614d18565b919450925090507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f858209600114614c17576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f696e765a206d75737420626520696e7665727365206f66207a000000000000006044820152606401610937565b60405180604001604052807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f80614c5057614c50615d5e565b87860981526020017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8785099052979650505050505050565b805160208201205b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f81106149c857604080516020808201939093528151808203840181529082019091528051910120614c91565b6000612c67826002614d117ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f6001615bba565b901c614eae565b60008080600180827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f897ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f038808905060007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f038a0890506000614dc083838585614fa2565b9098509050614dd188828e88614ffa565b9098509050614de288828c87614ffa565b90985090506000614df58d878b85614ffa565b9098509050614e0688828686614fa2565b9098509050614e1788828e89614ffa565b9098509050818114614e9a577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f818a0998507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f82890997507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8183099650614e9e565b8196505b5050505050509450945094915050565b600080614eb961518b565b6020808252818101819052604082015260608101859052608081018490527ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f60a0820152614f056151a9565b60208160c08460057ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa925082614f98576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f6269674d6f64457870206661696c7572652100000000000000000000000000006044820152606401610937565b5195945050505050565b6000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8487097ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8487099097909650945050505050565b600080807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f878509905060007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f87877ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f030990507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8183087ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f86890990999098509650505050505050565b82805482825590600052602060002090810192821561513f579160200282015b8281111561513f57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9091161782556020909201916001909101906150e5565b5061514b9291506151c7565b5090565b508054600082559060005260206000209081019061086891906151c7565b60405180604001604052806002906020820280368337509192915050565b6040518060c001604052806006906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b8082111561514b57600081556001016151c8565b803573ffffffffffffffffffffffffffffffffffffffff811681146149c857600080fd5b8060408101831015612c6757600080fd5b600082601f83011261522257600080fd5b6040516040810181811067ffffffffffffffff8211171561524557615245615deb565b806040525080838560408601111561525c57600080fd5b60005b600281101561527e57813583526020928301929091019060010161525f565b509195945050505050565b600060a0828403121561529b57600080fd5b60405160a0810181811067ffffffffffffffff821117156152be576152be615deb565b6040529050806152cd83615353565b81526152db60208401615353565b60208201526152ec6040840161533f565b60408201526152fd6060840161533f565b606082015261530e608084016151dc565b60808201525092915050565b803561ffff811681146149c857600080fd5b803562ffffff811681146149c857600080fd5b803563ffffffff811681146149c857600080fd5b803567ffffffffffffffff811681146149c857600080fd5b805169ffffffffffffffffffff811681146149c857600080fd5b60006020828403121561539757600080fd5b613d4b826151dc565b600080606083850312156153b357600080fd5b6153bc836151dc565b91506153cb8460208501615200565b90509250929050565b600080600080606085870312156153ea57600080fd5b6153f3856151dc565b935060208501359250604085013567ffffffffffffffff8082111561541757600080fd5b818701915087601f83011261542b57600080fd5b81358181111561543a57600080fd5b88602082850101111561544c57600080fd5b95989497505060200194505050565b6000806040838503121561546e57600080fd5b615477836151dc565b915060208301356bffffffffffffffffffffffff8116811461549857600080fd5b809150509250929050565b6000604082840312156154b557600080fd5b613d4b8383615200565b6000604082840312156154d157600080fd5b613d4b8383615211565b6000602082840312156154ed57600080fd5b81518015158114613d4b57600080fd5b60006020828403121561550f57600080fd5b5051919050565b600080600080600060a0868803121561552e57600080fd5b8535945061553e60208701615353565b935061554c6040870161531a565b925061555a6060870161533f565b91506155686080870161533f565b90509295509295909350565b60008082840361024081121561558957600080fd5b6101a08082121561559957600080fd5b6155a1615b90565b91506155ad8686615211565b82526155bc8660408701615211565b60208301526080850135604083015260a0850135606083015260c085013560808301526155eb60e086016151dc565b60a08301526101006155ff87828801615211565b60c0840152615612876101408801615211565b60e0840152610180860135818401525081935061563186828701615289565b925050509250929050565b6000806000806000808688036101c081121561565757600080fd5b6156608861531a565b965061566e6020890161533f565b955061567c6040890161533f565b945061568a6060890161533f565b935060808801359250610120807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60830112156156c557600080fd5b6156cd615b90565b91506156db60a08a0161533f565b82526156e960c08a0161533f565b60208301526156fa60e08a0161533f565b604083015261010061570d818b0161533f565b606084015261571d828b0161533f565b608084015261572f6101408b0161532c565b60a08401526157416101608b0161532c565b60c08401526157536101808b0161532c565b60e08401526157656101a08b0161532c565b818401525050809150509295509295509295565b60006020828403121561578b57600080fd5b5035919050565b6000602082840312156157a457600080fd5b613d4b82615353565b600080604083850312156157c057600080fd5b6157c983615353565b91506153cb602084016151dc565b600080600080600060a086880312156157ef57600080fd5b6157f88661536b565b94506020860151935060408601519250606086015191506155686080870161536b565b8060005b6002811015610a5a57815184526020938401939091019060010161581f565b615848818361581b565b604001919050565b868152615860602082018761581b565b61586d606082018661581b565b61587a60a082018561581b565b61588760e082018461581b565b60609190911b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166101208201526101340195945050505050565b8381526158d2602082018461581b565b606081019190915260800192915050565b60408101612c67828461581b565b600060208083528351808285015260005b8181101561591e57858101830151858201604001528201615902565b81811115615930576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b60006060820161ffff86168352602063ffffffff86168185015260606040850152818551808452608086019150828701935060005b818110156159b557845183529383019391830191600101615999565b509098975050505050505050565b60006101c08201905061ffff8816825263ffffffff808816602084015280871660408401528086166060840152846080840152835481811660a0850152615a1760c08501838360201c1663ffffffff169052565b615a2e60e08501838360401c1663ffffffff169052565b615a466101008501838360601c1663ffffffff169052565b615a5e6101208501838360801c1663ffffffff169052565b62ffffff60a082901c811661014086015260b882901c811661016086015260d082901c1661018085015260e81c6101a090930192909252979650505050505050565b82815260608101613d4b602083018461581b565b6000604082018483526020604081850152818551808452606086019150828701935060005b81811015615af557845183529383019391830191600101615ad9565b5090979650505050505050565b6000608082016bffffffffffffffffffffffff87168352602067ffffffffffffffff87168185015273ffffffffffffffffffffffffffffffffffffffff80871660408601526080606086015282865180855260a087019150838801945060005b81811015615b80578551841683529484019491840191600101615b62565b50909a9950505050505050505050565b604051610120810167ffffffffffffffff81118282101715615bb457615bb4615deb565b60405290565b60008219821115615bcd57615bcd615d2f565b500190565b600067ffffffffffffffff808316818516808303821115615bf557615bf5615d2f565b01949350505050565b60006bffffffffffffffffffffffff808316818516808303821115615bf557615bf5615d2f565b600082615c3457615c34615d5e565b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615615c7157615c71615d2f565b500290565b600082821015615c8857615c88615d2f565b500390565b60006bffffffffffffffffffffffff83811690831681811015615cb257615cb2615d2f565b039392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415615cec57615cec615d2f565b5060010190565b600067ffffffffffffffff80831681811415615d1157615d11615d2f565b6001019392505050565b600082615d2a57615d2a615d5e565b500690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fdfea164736f6c6343000806000a") - ctorArgs, err := utils.ABIEncode(`[{"type":"address"}, {"type":"address"}, {"type":"address"}]`, linkAddress, bhsAddress, linkEthFeed) + ctorArgs, err := evmutils.ABIEncode(`[{"type":"address"}, {"type":"address"}, {"type":"address"}]`, linkAddress, bhsAddress, linkEthFeed) require.NoError(t, err) bytecode = append(bytecode, ctorArgs...) nonce, err := backend.PendingNonceAt(ctx, neil.From) @@ -1174,7 +1177,7 @@ func TestVRFV2Integration_SingleConsumer_Wrapper(t *testing.T) { require.NoError(t, err) // Fund Subscription. - b, err := utils.ABIEncode(`[{"type":"uint64"}]`, wrapperSubID) + b, err := evmutils.ABIEncode(`[{"type":"uint64"}]`, wrapperSubID) require.NoError(t, err) _, err = uni.linkContract.TransferAndCall(uni.sergey, uni.rootContractAddress, assets.Ether(100).ToInt(), b) require.NoError(t, err) @@ -1224,7 +1227,7 @@ func TestVRFV2Integration_Wrapper_High_Gas(t *testing.T) { c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](3_500_000) c.EVM[0].MinIncomingConfirmations = ptr[uint32](2) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) }) ownerKey := cltest.MustGenerateRandomKey(t) uni := newVRFCoordinatorV2Universe(t, ownerKey, 1) @@ -1256,7 +1259,7 @@ func TestVRFV2Integration_Wrapper_High_Gas(t *testing.T) { require.NoError(t, err) // Fund Subscription. - b, err := utils.ABIEncode(`[{"type":"uint64"}]`, wrapperSubID) + b, err := evmutils.ABIEncode(`[{"type":"uint64"}]`, wrapperSubID) require.NoError(t, err) _, err = uni.linkContract.TransferAndCall(uni.sergey, uni.rootContractAddress, assets.Ether(100).ToInt(), b) require.NoError(t, err) @@ -1463,13 +1466,13 @@ func simulatedOverrides(t *testing.T, defaultGasPrice *assets.Wei, ks ...toml.Ke c.EVM[0].GasEstimator.LimitDefault = ptr[uint32](3_500_000) c.Feature.LogPoller = ptr(true) - c.EVM[0].LogPollInterval = models.MustNewDuration(1 * time.Second) + c.EVM[0].LogPollInterval = commonconfig.MustNewDuration(1 * time.Second) c.EVM[0].HeadTracker.MaxBufferSize = ptr[uint32](100) - c.EVM[0].HeadTracker.SamplingInterval = models.MustNewDuration(0) // Head sampling disabled + c.EVM[0].HeadTracker.SamplingInterval = commonconfig.MustNewDuration(0) // Head sampling disabled - c.EVM[0].Transactions.ResendAfterThreshold = models.MustNewDuration(0) - c.EVM[0].Transactions.ReaperThreshold = models.MustNewDuration(100 * time.Millisecond) + c.EVM[0].Transactions.ResendAfterThreshold = commonconfig.MustNewDuration(0) + c.EVM[0].Transactions.ReaperThreshold = commonconfig.MustNewDuration(100 * time.Millisecond) c.EVM[0].FinalityDepth = ptr[uint32](15) c.EVM[0].MinIncomingConfirmations = ptr[uint32](1) @@ -1482,8 +1485,13 @@ func registerProvingKeyHelper(t *testing.T, uni coordinatorV2UniverseCommon, coo // Register a proving key associated with the VRF job. p, err := vrfkey.PublicKey.Point() require.NoError(t, err) - _, err = coordinator.RegisterProvingKey( - uni.neil, uni.nallory.From, pair(secp256k1.Coordinates(p))) + if uni.rootContract.Version() == vrfcommon.V2Plus { + _, err = coordinator.RegisterProvingKey( + uni.neil, nil, pair(secp256k1.Coordinates(p))) + } else { + _, err = coordinator.RegisterProvingKey( + uni.neil, &uni.nallory.From, pair(secp256k1.Coordinates(p))) + } require.NoError(t, err) uni.backend.Commit() } @@ -1529,7 +1537,7 @@ func TestExternalOwnerConsumerExample(t *testing.T) { _, err = coordinator.CreateSubscription(owner) require.NoError(t, err) backend.Commit() - b, err := utils.ABIEncode(`[{"type":"uint64"}]`, uint64(1)) + b, err := evmutils.ABIEncode(`[{"type":"uint64"}]`, uint64(1)) require.NoError(t, err) _, err = linkContract.TransferAndCall(owner, coordinatorAddress, big.NewInt(0), b) require.NoError(t, err) @@ -1803,13 +1811,7 @@ func TestRequestCost(t *testing.T) { vrfkey, err := app.GetKeyStore().VRF().Create() require.NoError(t, err) - p, err := vrfkey.PublicKey.Point() - require.NoError(t, err) - _, err = uni.rootContract.RegisterProvingKey( - uni.neil, uni.neil.From, pair(secp256k1.Coordinates(p))) - require.NoError(t, err) - uni.backend.Commit() - + registerProvingKeyHelper(t, uni.coordinatorV2UniverseCommon, uni.rootContract, vrfkey) t.Run("non-proxied consumer", func(tt *testing.T) { carol := uni.vrfConsumers[0] carolContract := uni.consumerContracts[0] @@ -1912,18 +1914,10 @@ func TestFulfillmentCost(t *testing.T) { app := cltest.NewApplicationWithConfigV2AndKeyOnSimulatedBlockchain(t, cfg, uni.backend, key) require.NoError(t, app.Start(testutils.Context(t))) - var vrfkey vrfkey.KeyV2 - { - var err error - vrfkey, err = app.GetKeyStore().VRF().Create() - require.NoError(t, err) - p, err := vrfkey.PublicKey.Point() - require.NoError(t, err) - _, err = uni.rootContract.RegisterProvingKey( - uni.neil, uni.neil.From, pair(secp256k1.Coordinates(p))) - require.NoError(t, err) - uni.backend.Commit() - } + vrfkey, err := app.GetKeyStore().VRF().Create() + require.NoError(t, err) + registerProvingKeyHelper(t, uni.coordinatorV2UniverseCommon, uni.rootContract, vrfkey) + var ( nonProxiedConsumerGasEstimate uint64 proxiedConsumerGasEstimate uint64 @@ -2043,21 +2037,21 @@ func TestStartingCountsV1(t *testing.T) { require.NoError(t, err) b := time.Now() n1, n2, n3, n4 := evmtypes.Nonce(0), evmtypes.Nonce(1), evmtypes.Nonce(2), evmtypes.Nonce(3) - reqID := utils.PadByteToHash(0x10) + reqID := evmutils.PadByteToHash(0x10) m1 := txmgr.TxMeta{ RequestID: &reqID, } md1, err := json.Marshal(&m1) require.NoError(t, err) md1SQL := sqlutil.JSON(md1) - reqID2 := utils.PadByteToHash(0x11) + reqID2 := evmutils.PadByteToHash(0x11) m2 := txmgr.TxMeta{ RequestID: &reqID2, } md2, err := json.Marshal(&m2) md2SQL := sqlutil.JSON(md2) require.NoError(t, err) - chainID := utils.NewBig(testutils.SimulatedChainID) + chainID := ubig.New(testutils.SimulatedChainID) confirmedTxes := []txmgr.Tx{ { Sequence: &n1, @@ -2111,7 +2105,7 @@ func TestStartingCountsV1(t *testing.T) { // add unconfirmed txes unconfirmedTxes := []txmgr.Tx{} for i := int64(4); i < 6; i++ { - reqID3 := utils.PadByteToHash(0x12) + reqID3 := evmutils.PadByteToHash(0x12) md, err2 := json.Marshal(&txmgr.TxMeta{ RequestID: &reqID3, }) @@ -2145,7 +2139,7 @@ func TestStartingCountsV1(t *testing.T) { TxID: int64(i + 1), TxFee: gas.EvmFee{Legacy: assets.NewWeiI(100)}, SignedRawTx: []byte(`blah`), - Hash: utils.NewHash(), + Hash: evmutils.NewHash(), BroadcastBeforeBlockNum: &broadcastBlock, State: txmgrtypes.TxAttemptBroadcast, CreatedAt: time.Now(), @@ -2158,7 +2152,7 @@ func TestStartingCountsV1(t *testing.T) { TxID: int64(i + 1 + len(confirmedTxes)), TxFee: gas.EvmFee{Legacy: assets.NewWeiI(100)}, SignedRawTx: []byte(`blah`), - Hash: utils.NewHash(), + Hash: evmutils.NewHash(), State: txmgrtypes.TxAttemptInProgress, CreatedAt: time.Now(), ChainSpecificFeeLimit: uint32(100), @@ -2176,7 +2170,7 @@ func TestStartingCountsV1(t *testing.T) { receipts := []evmtypes.Receipt{} for i := 0; i < 4; i++ { receipts = append(receipts, evmtypes.Receipt{ - BlockHash: utils.NewHash(), + BlockHash: evmutils.NewHash(), TxHash: txAttempts[i].Hash, BlockNumber: big.NewInt(broadcastBlock), TransactionIndex: 1, @@ -2190,9 +2184,9 @@ func TestStartingCountsV1(t *testing.T) { counts, err = listenerV1.GetStartingResponseCountsV1(testutils.Context(t)) require.NoError(t, err) assert.Equal(t, 3, len(counts)) - assert.Equal(t, uint64(1), counts[utils.PadByteToHash(0x10)]) - assert.Equal(t, uint64(2), counts[utils.PadByteToHash(0x11)]) - assert.Equal(t, uint64(2), counts[utils.PadByteToHash(0x12)]) + assert.Equal(t, uint64(1), counts[evmutils.PadByteToHash(0x10)]) + assert.Equal(t, uint64(2), counts[evmutils.PadByteToHash(0x11)]) + assert.Equal(t, uint64(2), counts[evmutils.PadByteToHash(0x12)]) countsV2, err := listenerV2.GetStartingResponseCountsV2(testutils.Context(t)) require.NoError(t, err) diff --git a/core/services/vrf/v2/listener_v2.go b/core/services/vrf/v2/listener_v2.go index 5878bf54763..6556bbd2186 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" + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" diff --git a/core/services/vrf/v2/listener_v2_log_listener.go b/core/services/vrf/v2/listener_v2_log_listener.go index b35593bd1ca..07b4c2c3800 100644 --- a/core/services/vrf/v2/listener_v2_log_listener.go +++ b/core/services/vrf/v2/listener_v2_log_listener.go @@ -10,12 +10,12 @@ import ( "github.com/ethereum/go-ethereum/common" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) func (lsn *listenerV2) runLogListener( diff --git a/core/services/vrf/v2/listener_v2_log_listener_test.go b/core/services/vrf/v2/listener_v2_log_listener_test.go new file mode 100644 index 00000000000..6f5177c230a --- /dev/null +++ b/core/services/vrf/v2/listener_v2_log_listener_test.go @@ -0,0 +1,1040 @@ +package v2 + +import ( + "context" + "fmt" + "math/big" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" + evmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm/mocks" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_log_emitter" + "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/keystore" + "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" + "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +var ( + emitterABI, _ = abi.JSON(strings.NewReader(log_emitter.LogEmitterABI)) + vrfEmitterABI, _ = abi.JSON(strings.NewReader(vrf_log_emitter.VRFLogEmitterABI)) +) + +type vrfLogPollerListenerTH struct { + Lggr logger.Logger + ChainID *big.Int + ORM *logpoller.DbORM + LogPoller logpoller.LogPollerTest + Client *backends.SimulatedBackend + Emitter *log_emitter.LogEmitter + EmitterAddress common.Address + VRFLogEmitter *vrf_log_emitter.VRFLogEmitter + VRFEmitterAddress common.Address + Owner *bind.TransactOpts + EthDB ethdb.Database + Db *sqlx.DB + Listener *listenerV2 + Ctx context.Context +} + +func setupVRFLogPollerListenerTH(t *testing.T, + useFinalityTag bool, + finalityDepth, backfillBatchSize, + rpcBatchSize, keepFinalizedBlocksDepth int64, + mockChainUpdateFn func(*evmmocks.Chain, *vrfLogPollerListenerTH)) *vrfLogPollerListenerTH { + + lggr := logger.TestLogger(t) + chainID := testutils.NewRandomEVMChainID() + db := pgtest.NewSqlxDB(t) + + o := logpoller.NewORM(chainID, db, lggr, pgtest.NewQConfig(true)) + owner := testutils.MustNewSimTransactor(t) + ethDB := rawdb.NewMemoryDatabase() + ec := backends.NewSimulatedBackendWithDatabase(ethDB, map[common.Address]core.GenesisAccount{ + owner.From: { + Balance: big.NewInt(0).Mul(big.NewInt(10), big.NewInt(1e18)), + }, + }, 10e6) + // VRF Listener relies on block timestamps, but SimulatedBackend uses by default clock starting from 1970-01-01 + // This trick is used to move the clock closer to the current time. We set first block to be X hours ago. + // FirstBlockAge is used to compute first block's timestamp in SimulatedBackend (time.Now() - FirstBlockAge) + const FirstBlockAge = 24 * time.Hour + blockTime := time.UnixMilli(int64(ec.Blockchain().CurrentHeader().Time)) + err := ec.AdjustTime(time.Since(blockTime) - FirstBlockAge) + require.NoError(t, err) + ec.Commit() + + esc := client.NewSimulatedBackendClient(t, ec, chainID) + // Mark genesis block as finalized to avoid any nulls in the tests + head := esc.Backend().Blockchain().CurrentHeader() + esc.Backend().Blockchain().SetFinalized(head) + + // Poll period doesn't matter, we intend to call poll and save logs directly in the test. + // Set it to some insanely high value to not interfere with any tests. + lp := logpoller.NewLogPoller(o, esc, lggr, 1*time.Hour, useFinalityTag, finalityDepth, backfillBatchSize, rpcBatchSize, keepFinalizedBlocksDepth) + + emitterAddress1, _, emitter1, err := log_emitter.DeployLogEmitter(owner, ec) + require.NoError(t, err) + vrfLogEmitterAddress, _, vrfLogEmitter, err := vrf_log_emitter.DeployVRFLogEmitter(owner, ec) + require.NoError(t, err) + ec.Commit() + + // Log Poller Listener + cfg := pgtest.NewQConfig(false) + ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr, cfg) + require.NoError(t, ks.Unlock("blah")) + j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ + RequestedConfsDelay: 10, + EVMChainID: chainID.String(), + }).Toml()) + require.NoError(t, err) + + coordinatorV2, err := vrf_coordinator_v2.NewVRFCoordinatorV2(vrfLogEmitter.Address(), ec) + require.Nil(t, err) + coordinator := NewCoordinatorV2(coordinatorV2) + + chain := evmmocks.NewChain(t) + listener := &listenerV2{ + respCount: map[string]uint64{}, + job: j, + chain: chain, + l: logger.Sugared(lggr), + coordinator: coordinator, + } + ctx := testutils.Context(t) + + // Filter registration is idempotent, so we can just call it every time + // and retry on errors using the ticker. + err = lp.RegisterFilter(logpoller.Filter{ + Name: fmt.Sprintf("vrf_%s_keyhash_%s_job_%d", "v2", listener.job.VRFSpec.PublicKey.MustHash().String(), listener.job.ID), + EventSigs: evmtypes.HashArray{ + vrf_log_emitter.VRFLogEmitterRandomWordsRequested{}.Topic(), + vrf_log_emitter.VRFLogEmitterRandomWordsFulfilled{}.Topic(), + }, + Addresses: evmtypes.AddressArray{ + vrfLogEmitter.Address(), + // listener.job.VRFSpec.CoordinatorAddress.Address(), + }, + }) + require.Nil(t, err) + require.NoError(t, lp.RegisterFilter(logpoller.Filter{ + Name: "Integration test", + EventSigs: []common.Hash{emitterABI.Events["Log1"].ID}, + Addresses: []common.Address{emitterAddress1}, + Retention: 0})) + require.Nil(t, err) + require.Len(t, lp.Filter(nil, nil, nil).Addresses, 2) + require.Len(t, lp.Filter(nil, nil, nil).Topics, 1) + require.Len(t, lp.Filter(nil, nil, nil).Topics[0], 3) + + th := &vrfLogPollerListenerTH{ + Lggr: lggr, + ChainID: chainID, + ORM: o, + LogPoller: lp, + Emitter: emitter1, + EmitterAddress: emitterAddress1, + VRFLogEmitter: vrfLogEmitter, + VRFEmitterAddress: vrfLogEmitterAddress, + Client: ec, + Owner: owner, + EthDB: ethDB, + Db: db, + Listener: listener, + Ctx: ctx, + } + mockChainUpdateFn(chain, th) + return th +} + +/* Tests for initializeLastProcessedBlock: BEGIN + * TestInitProcessedBlock_NoVRFReqs + * TestInitProcessedBlock_NoUnfulfilledVRFReqs + * TestInitProcessedBlock_OneUnfulfilledVRFReq + * TestInitProcessedBlock_SomeUnfulfilledVRFReqs + * TestInitProcessedBlock_UnfulfilledNFulfilledVRFReqs + */ + +func TestInitProcessedBlock_NoVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, th *vrfLogPollerListenerTH) { + mockChain.On("ID").Return(th.ChainID) + mockChain.On("LogPoller").Return(th.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Emit some logs from block 5 to 9 (Inclusive) + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 5 (EmitLog blocks) = 9 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(testutils.Context(t))) + + // The poller starts on a new chain at latest-finality (finalityDepth + 5 in this case), + // Replaying from block 4 should guarantee we have block 4 immediately. (We will also get + // block 3 once the backup poller runs, since it always starts 100 blocks behind.) + require.NoError(t, th.LogPoller.Replay(testutils.Context(t), 4)) + + // Should return logs from block 5 to 7 (inclusive) + logs, err := th.LogPoller.Logs(4, 7, emitterABI.Events["Log1"].ID, th.EmitterAddress, + pg.WithParentCtx(testutils.Context(t))) + require.NoError(t, err) + require.Equal(t, 3, len(logs)) + + lastProcessedBlock, err := th.Listener.initializeLastProcessedBlock(th.Ctx) + require.Nil(t, err) + require.Equal(t, int64(6), lastProcessedBlock) +} + +func TestInitProcessedBlock_NoUnfulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("ID").Return(curTH.ChainID) + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Create VRF request block and a fulfillment block + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID := big.NewInt(1) + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + _, err2 = th.VRFLogEmitter.EmitRandomWordsFulfilled(th.Owner, reqID, preSeed, big.NewInt(10), true) + require.NoError(t, err2) + th.Client.Commit() + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 2 (VRF req/resp block) + 5 (EmitLog blocks) = 11 + latestBlock := int64(2 + 2 + 2 + 5) + + // A replay is needed so that log poller has a latest block + // Replay from block 11 (latest) onwards, so that log poller has a latest block + // Then test if log poller is able to replay from finalizedBlockNumber (8 --> onwards) + // since there are no pending VRF requests + // Blocks: 1 2 3 4 [5;Request] [6;Fulfilment] 7 8 9 10 11 + require.NoError(t, th.LogPoller.Replay(th.Ctx, latestBlock)) + + // initializeLastProcessedBlock must return the finalizedBlockNumber (8) instead of + // VRF request block number (5), since all VRF requests are fulfilled + lastProcessedBlock, err := th.Listener.initializeLastProcessedBlock(th.Ctx) + require.Nil(t, err) + require.Equal(t, int64(8), lastProcessedBlock) +} + +func TestInitProcessedBlock_OneUnfulfilledVRFReq(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("ID").Return(curTH.ChainID) + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Make a VRF request without fulfilling it + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID := big.NewInt(1) + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + th.Client.Commit() + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 1 (VRF req block) + 5 (EmitLog blocks) = 10 + latestBlock := int64(2 + 2 + 1 + 5) + + // A replay is needed so that log poller has a latest block + // Replay from block 10 (latest) onwards, so that log poller has a latest block + // Then test if log poller is able to replay from earliestUnprocessedBlock (5 --> onwards) + // Blocks: 1 2 3 4 [5;Request] 6 7 8 9 10 + require.NoError(t, th.LogPoller.Replay(th.Ctx, latestBlock)) + + // initializeLastProcessedBlock must return the unfulfilled VRF + // request block number (5) instead of finalizedBlockNumber (8) + lastProcessedBlock, err := th.Listener.initializeLastProcessedBlock(th.Ctx) + require.Nil(t, err) + require.Equal(t, int64(5), lastProcessedBlock) +} + +func TestInitProcessedBlock_SomeUnfulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("ID").Return(curTH.ChainID) + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Emit some logs in blocks with VRF reqs interspersed + // No fulfillment for any VRF requests + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + + // Create 2 blocks with VRF requests in each iteration + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(2 * i)) + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + reqID2 := big.NewInt(int64(2*i + 1)) + _, err2 = th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID2, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + } + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 3*5 (EmitLog + VRF req/resp blocks) = 19 + latestBlock := int64(2 + 2 + 3*5) + + // A replay is needed so that log poller has a latest block + // Replay from block 19 (latest) onwards, so that log poller has a latest block + // Then test if log poller is able to replay from earliestUnprocessedBlock (6 --> onwards) + // Blocks: 1 2 3 4 5 [6;Request] [7;Request] 8 [9;Request] [10;Request] + // 11 [12;Request] [13;Request] 14 [15;Request] [16;Request] + // 17 [18;Request] [19;Request] + require.NoError(t, th.LogPoller.Replay(th.Ctx, latestBlock)) + + // initializeLastProcessedBlock must return the earliest unfulfilled VRF request block + // number instead of finalizedBlockNumber + lastProcessedBlock, err := th.Listener.initializeLastProcessedBlock(th.Ctx) + require.Nil(t, err) + require.Equal(t, int64(6), lastProcessedBlock) +} + +func TestInitProcessedBlock_UnfulfilledNFulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("ID").Return(curTH.ChainID) + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Emit some logs in blocks with VRF reqs interspersed + // One VRF request in each iteration is fulfilled to imitate mixed workload + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + + // Create 2 blocks with VRF requests in each iteration and fulfill one + // of them. This creates a mixed workload of fulfilled and unfulfilled + // VRF requests for testing the VRF listener + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(2 * i)) + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + reqID2 := big.NewInt(int64(2*i + 1)) + _, err2 = th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID2, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + + _, err2 = th.VRFLogEmitter.EmitRandomWordsFulfilled(th.Owner, reqID1, preSeed, big.NewInt(10), true) + require.NoError(t, err2) + th.Client.Commit() + } + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 3*5 (EmitLog + VRF req/resp blocks) = 19 + latestBlock := int64(2 + 2 + 3*5) + // A replay is needed so that log poller has a latest block + // Replay from block 19 (latest) onwards, so that log poller has a latest block + // Then test if log poller is able to replay from earliestUnprocessedBlock (7 --> onwards) + // Blocks: 1 2 3 4 5 [6;Request] [7;Request;6-Fulfilment] 8 [9;Request] [10;Request;9-Fulfilment] + // 11 [12;Request] [13;Request;12-Fulfilment] 14 [15;Request] [16;Request;15-Fulfilment] + // 17 [18;Request] [19;Request;18-Fulfilment] + require.NoError(t, th.LogPoller.Replay(th.Ctx, latestBlock)) + + // initializeLastProcessedBlock must return the earliest unfulfilled VRF request block + // number instead of finalizedBlockNumber + lastProcessedBlock, err := th.Listener.initializeLastProcessedBlock(th.Ctx) + require.Nil(t, err) + require.Equal(t, int64(7), lastProcessedBlock) +} + +/* Tests for initializeLastProcessedBlock: END */ + +/* Tests for updateLastProcessedBlock: BEGIN + * TestUpdateLastProcessedBlock_NoVRFReqs + * TestUpdateLastProcessedBlock_NoUnfulfilledVRFReqs + * TestUpdateLastProcessedBlock_OneUnfulfilledVRFReq + * TestUpdateLastProcessedBlock_SomeUnfulfilledVRFReqs + * TestUpdateLastProcessedBlock_UnfulfilledNFulfilledVRFReqs + */ + +func TestUpdateLastProcessedBlock_NoVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Create VRF request logs + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(1)) + + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + reqID2 := big.NewInt(int64(2)) + _, err2 = th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID2, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 2 (VRF req blocks) + 5 (EmitLog blocks) = 11 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // We've to replay from before VRF request log, since updateLastProcessedBlock + // does not internally call LogPoller.Replay + require.NoError(t, th.LogPoller.Replay(th.Ctx, 4)) + + // updateLastProcessedBlock must return the finalizedBlockNumber as there are + // no VRF requests, after currLastProcessedBlock (block 6). The VRF requests + // made above are before the currLastProcessedBlock (7) passed in below + lastProcessedBlock, err := th.Listener.updateLastProcessedBlock(th.Ctx, 7) + require.Nil(t, err) + require.Equal(t, int64(8), lastProcessedBlock) +} + +func TestUpdateLastProcessedBlock_NoUnfulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Create VRF request log block with a fulfillment log block + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(1)) + + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + _, err2 = th.VRFLogEmitter.EmitRandomWordsFulfilled(th.Owner, reqID1, preSeed, big.NewInt(10), true) + require.NoError(t, err2) + th.Client.Commit() + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 2 (VRF req/resp blocks) + 5 (EmitLog blocks) = 11 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // We've to replay from before VRF request log, since updateLastProcessedBlock + // does not internally call LogPoller.Replay + require.NoError(t, th.LogPoller.Replay(th.Ctx, 4)) + + // updateLastProcessedBlock must return the finalizedBlockNumber (8) though we have + // a VRF req at block (5) after currLastProcessedBlock (4) passed below, because + // the VRF request is fulfilled + lastProcessedBlock, err := th.Listener.updateLastProcessedBlock(th.Ctx, 4) + require.Nil(t, err) + require.Equal(t, int64(8), lastProcessedBlock) +} + +func TestUpdateLastProcessedBlock_OneUnfulfilledVRFReq(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Create VRF request logs without a fulfillment log block + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(1)) + + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 1 (VRF req block) + 5 (EmitLog blocks) = 10 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // We've to replay from before VRF request log, since updateLastProcessedBlock + // does not internally call LogPoller.Replay + require.NoError(t, th.LogPoller.Replay(th.Ctx, 4)) + + // updateLastProcessedBlock must return the VRF req at block (5) instead of + // finalizedBlockNumber (8) after currLastProcessedBlock (4) passed below, + // because the VRF request is unfulfilled + lastProcessedBlock, err := th.Listener.updateLastProcessedBlock(th.Ctx, 4) + require.Nil(t, err) + require.Equal(t, int64(5), lastProcessedBlock) +} + +func TestUpdateLastProcessedBlock_SomeUnfulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + + // Create 2 blocks with VRF requests in each iteration + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(2 * i)) + + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + reqID2 := big.NewInt(int64(2*i + 1)) + _, err2 = th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID2, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 3*5 (EmitLog + VRF req blocks) = 19 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // We've to replay from before VRF request log, since updateLastProcessedBlock + // does not internally call LogPoller.Replay + require.NoError(t, th.LogPoller.Replay(th.Ctx, 4)) + + // updateLastProcessedBlock must return the VRF req at block (6) instead of + // finalizedBlockNumber (16) after currLastProcessedBlock (4) passed below, + // as block 6 contains the earliest unfulfilled VRF request + lastProcessedBlock, err := th.Listener.updateLastProcessedBlock(th.Ctx, 4) + require.Nil(t, err) + require.Equal(t, int64(6), lastProcessedBlock) +} + +func TestUpdateLastProcessedBlock_UnfulfilledNFulfilledVRFReqs(t *testing.T) { + t.Parallel() + + finalityDepth := int64(3) + th := setupVRFLogPollerListenerTH(t, false, finalityDepth, 3, 2, 1000, func(mockChain *evmmocks.Chain, curTH *vrfLogPollerListenerTH) { + mockChain.On("LogPoller").Return(curTH.LogPoller) + }) + + // Block 3 to finalityDepth. Ensure we have finality number of blocks + for i := 1; i < int(finalityDepth); i++ { + th.Client.Commit() + } + + // Emit some logs in blocks to make the VRF req and fulfillment older than finalityDepth from latestBlock + n := 5 + for i := 0; i < n; i++ { + _, err1 := th.Emitter.EmitLog1(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + _, err1 = th.Emitter.EmitLog2(th.Owner, []*big.Int{big.NewInt(int64(i))}) + require.NoError(t, err1) + th.Client.Commit() + + // Create 2 blocks with VRF requests in each iteration and fulfill one + // of them. This creates a mixed workload of fulfilled and unfulfilled + // VRF requests for testing the VRF listener + keyHash := [32]byte(th.Listener.job.VRFSpec.PublicKey.MustHash().Bytes()) + preSeed := big.NewInt(105) + subID := uint64(1) + reqID1 := big.NewInt(int64(2 * i)) + + _, err2 := th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID1, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + th.Client.Commit() + + reqID2 := big.NewInt(int64(2*i + 1)) + _, err2 = th.VRFLogEmitter.EmitRandomWordsRequested(th.Owner, + keyHash, reqID2, preSeed, subID, 10, 10000, 2, th.Owner.From) + require.NoError(t, err2) + _, err2 = th.VRFLogEmitter.EmitRandomWordsFulfilled(th.Owner, reqID1, preSeed, big.NewInt(10), true) + require.NoError(t, err2) + th.Client.Commit() + } + + // Blocks till now: 2 (in SetupTH) + 2 (empty blocks) + 3*5 (EmitLog + VRF req blocks) = 19 + + // Calling Start() after RegisterFilter() simulates a node restart after job creation, should reload Filter from db. + require.NoError(t, th.LogPoller.Start(th.Ctx)) + + // We've to replay from before VRF request log, since updateLastProcessedBlock + // does not internally call LogPoller.Replay + require.NoError(t, th.LogPoller.Replay(th.Ctx, 4)) + + // updateLastProcessedBlock must return the VRF req at block (7) instead of + // finalizedBlockNumber (16) after currLastProcessedBlock (4) passed below, + // as block 7 contains the earliest unfulfilled VRF request. VRF request + // in block 6 has been fulfilled in block 7. + lastProcessedBlock, err := th.Listener.updateLastProcessedBlock(th.Ctx, 4) + require.Nil(t, err) + require.Equal(t, int64(7), lastProcessedBlock) +} + +/* Tests for updateLastProcessedBlock: END */ + +/* Tests for getUnfulfilled: BEGIN + * TestGetUnfulfilled_NoVRFReqs + * TestGetUnfulfilled_NoUnfulfilledVRFReqs + * TestGetUnfulfilled_OneUnfulfilledVRFReq + * TestGetUnfulfilled_SomeUnfulfilledVRFReqs + * TestGetUnfulfilled_UnfulfilledNFulfilledVRFReqs + */ + +func SetupGetUnfulfilledTH(t *testing.T) (*listenerV2, *ubig.Big) { + chainID := ubig.New(big.NewInt(12345)) + lggr := logger.TestLogger(t) + j, err := vrfcommon.ValidatedVRFSpec(testspecs.GenerateVRFSpec(testspecs.VRFSpecParams{ + RequestedConfsDelay: 10, + EVMChainID: chainID.String(), + }).Toml()) + require.NoError(t, err) + chain := evmmocks.NewChain(t) + + // Construct CoordinatorV2_X object for VRF listener + owner := testutils.MustNewSimTransactor(t) + ethDB := rawdb.NewMemoryDatabase() + ec := backends.NewSimulatedBackendWithDatabase(ethDB, map[common.Address]core.GenesisAccount{ + owner.From: { + Balance: big.NewInt(0).Mul(big.NewInt(10), big.NewInt(1e18)), + }, + }, 10e6) + _, _, vrfLogEmitter, err := vrf_log_emitter.DeployVRFLogEmitter(owner, ec) + require.NoError(t, err) + ec.Commit() + coordinatorV2, err := vrf_coordinator_v2.NewVRFCoordinatorV2(vrfLogEmitter.Address(), ec) + require.Nil(t, err) + coordinator := NewCoordinatorV2(coordinatorV2) + + listener := &listenerV2{ + respCount: map[string]uint64{}, + job: j, + chain: chain, + l: logger.Sugared(lggr), + coordinator: coordinator, + } + return listener, chainID +} + +func TestGetUnfulfilled_NoVRFReqs(t *testing.T) { + t.Parallel() + + listener, chainID := SetupGetUnfulfilledTH(t) + + logs := []logpoller.Log{} + for i := 0; i < 10; i++ { + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(i))), + BlockNumber: int64(i), + BlockTimestamp: time.Now(), + Topics: [][]byte{ + []byte("0x46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a8"), + }, + EventSig: emitterABI.Events["Log1"].ID, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(i))), + Data: nil, + CreatedAt: time.Now(), + }) + } + + unfulfilled, _, fulfilled := listener.getUnfulfilled(logs, listener.l) + require.Empty(t, unfulfilled) + require.Empty(t, fulfilled) +} + +func TestGetUnfulfilled_NoUnfulfilledVRFReqs(t *testing.T) { + t.Parallel() + + listener, chainID := SetupGetUnfulfilledTH(t) + + logs := []logpoller.Log{} + for i := 0; i < 10; i++ { + eventSig := emitterABI.Events["Log1"].ID + topics := [][]byte{ + common.FromHex("0x46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a8"), + } + if i%2 == 0 { + eventSig = vrfEmitterABI.Events["RandomWordsRequested"].ID + topics = [][]byte{ + common.FromHex("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772"), + common.FromHex("0xc0a6c424ac7157ae408398df7e5f4552091a69125d5dfcb7b8c2659029395bdf"), + common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001"), + common.FromHex("0x0000000000000000000000005ee3b50502b5c4c9184dcb281471a0614d4b2ef9"), + } + } + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2 * i))), + BlockNumber: int64(2 * i), + BlockTimestamp: time.Now(), + Topics: topics, + EventSig: eventSig, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2 * i))), + Data: common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i) + "000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000002"), + CreatedAt: time.Now(), + }) + if i%2 == 0 { + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2*i + 1))), + BlockNumber: int64(2*i + 1), + BlockTimestamp: time.Now(), + Topics: [][]byte{ + common.FromHex("0x7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4"), + common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i)), + }, + EventSig: vrfEmitterABI.Events["RandomWordsFulfilled"].ID, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2*i + 1))), + Data: common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000069000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001"), + CreatedAt: time.Now(), + }) + } + } + + unfulfilled, _, fulfilled := listener.getUnfulfilled(logs, listener.l) + require.Empty(t, unfulfilled) + require.Len(t, fulfilled, 5) +} + +func TestGetUnfulfilled_OneUnfulfilledVRFReq(t *testing.T) { + t.Parallel() + + listener, chainID := SetupGetUnfulfilledTH(t) + + logs := []logpoller.Log{} + for i := 0; i < 10; i++ { + eventSig := emitterABI.Events["Log1"].ID + topics := [][]byte{ + common.FromHex("0x46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a8"), + } + if i == 4 { + eventSig = vrfEmitterABI.Events["RandomWordsRequested"].ID + topics = [][]byte{ + common.FromHex("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772"), + common.FromHex("0xc0a6c424ac7157ae408398df7e5f4552091a69125d5dfcb7b8c2659029395bdf"), + common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001"), + common.FromHex("0x0000000000000000000000005ee3b50502b5c4c9184dcb281471a0614d4b2ef9"), + } + } + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2 * i))), + BlockNumber: int64(2 * i), + BlockTimestamp: time.Now(), + Topics: topics, + EventSig: eventSig, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2 * i))), + Data: common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i) + "000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000002"), + CreatedAt: time.Now(), + }) + } + + unfulfilled, _, fulfilled := listener.getUnfulfilled(logs, listener.l) + require.Equal(t, unfulfilled[0].RequestID().Int64(), big.NewInt(4).Int64()) + require.Len(t, unfulfilled, 1) + require.Empty(t, fulfilled) +} + +func TestGetUnfulfilled_SomeUnfulfilledVRFReq(t *testing.T) { + t.Parallel() + + listener, chainID := SetupGetUnfulfilledTH(t) + + logs := []logpoller.Log{} + for i := 0; i < 10; i++ { + eventSig := emitterABI.Events["Log1"].ID + topics := [][]byte{ + common.FromHex("0x46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a8"), + } + if i%2 == 0 { + eventSig = vrfEmitterABI.Events["RandomWordsRequested"].ID + topics = [][]byte{ + common.FromHex("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772"), + common.FromHex("0xc0a6c424ac7157ae408398df7e5f4552091a69125d5dfcb7b8c2659029395bdf"), + common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001"), + common.FromHex("0x0000000000000000000000005ee3b50502b5c4c9184dcb281471a0614d4b2ef9"), + } + } + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2 * i))), + BlockNumber: int64(2 * i), + BlockTimestamp: time.Now(), + Topics: topics, + EventSig: eventSig, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2 * i))), + Data: common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i) + "000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000002"), + CreatedAt: time.Now(), + }) + } + + unfulfilled, _, fulfilled := listener.getUnfulfilled(logs, listener.l) + require.Len(t, unfulfilled, 5) + require.Len(t, fulfilled, 0) + expected := map[int64]bool{0: true, 2: true, 4: true, 6: true, 8: true} + for _, u := range unfulfilled { + v, ok := expected[u.RequestID().Int64()] + require.Equal(t, ok, true) + require.Equal(t, v, true) + } + require.Equal(t, len(expected), len(unfulfilled)) +} + +func TestGetUnfulfilled_UnfulfilledNFulfilledVRFReqs(t *testing.T) { + t.Parallel() + + listener, chainID := SetupGetUnfulfilledTH(t) + + logs := []logpoller.Log{} + for i := 0; i < 10; i++ { + eventSig := emitterABI.Events["Log1"].ID + topics := [][]byte{ + common.FromHex("0x46692c0e59ca9cd1ad8f984a9d11715ec83424398b7eed4e05c8ce84662415a8"), + } + if i%2 == 0 { + eventSig = vrfEmitterABI.Events["RandomWordsRequested"].ID + topics = [][]byte{ + common.FromHex("0x63373d1c4696214b898952999c9aaec57dac1ee2723cec59bea6888f489a9772"), + common.FromHex("0xc0a6c424ac7157ae408398df7e5f4552091a69125d5dfcb7b8c2659029395bdf"), + common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000001"), + common.FromHex("0x0000000000000000000000005ee3b50502b5c4c9184dcb281471a0614d4b2ef9"), + } + } + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2 * i))), + BlockNumber: int64(2 * i), + BlockTimestamp: time.Now(), + Topics: topics, + EventSig: eventSig, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2 * i))), + Data: common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i) + "000000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000002"), + CreatedAt: time.Now(), + }) + if i%2 == 0 && i < 6 { + logs = append(logs, logpoller.Log{ + EvmChainId: chainID, + LogIndex: 0, + BlockHash: common.BigToHash(big.NewInt(int64(2*i + 1))), + BlockNumber: int64(2*i + 1), + BlockTimestamp: time.Now(), + Topics: [][]byte{ + common.FromHex("0x7dffc5ae5ee4e2e4df1651cf6ad329a73cebdb728f37ea0187b9b17e036756e4"), + common.FromHex("0x000000000000000000000000000000000000000000000000000000000000000" + fmt.Sprintf("%d", i)), + }, + EventSig: vrfEmitterABI.Events["RandomWordsFulfilled"].ID, + Address: common.Address{}, + TxHash: common.BigToHash(big.NewInt(int64(2*i + 1))), + Data: common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000069000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001"), + CreatedAt: time.Now(), + }) + } + } + + unfulfilled, _, fulfilled := listener.getUnfulfilled(logs, listener.l) + require.Len(t, unfulfilled, 2) + require.Len(t, fulfilled, 3) + expected := map[int64]bool{6: true, 8: true} + for _, u := range unfulfilled { + v, ok := expected[u.RequestID().Int64()] + require.Equal(t, ok, true) + require.Equal(t, v, true) + } + require.Equal(t, len(expected), len(unfulfilled)) +} + +/* Tests for getUnfulfilled: END */ diff --git a/core/services/vrf/v2/listener_v2_log_processor.go b/core/services/vrf/v2/listener_v2_log_processor.go index 004ab4c4905..eebe9038c0c 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/utils/hex" txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" @@ -1182,7 +1183,13 @@ func (lsn *listenerV2) simulateFulfillment( res.err = errors.New("expected []uint8 final result") return res } - res.maxFee = utils.HexToBig(hexutil.Encode(b)[2:]) + + res.maxFee, err = hex.ParseBig(hexutil.Encode(b)[2:]) + if err != nil { + res.err = err + return res + } + for _, trr := range trrs { if trr.Task.Type() == pipeline.TaskTypeVRFV2 { m := trr.Result.Value.(map[string]interface{}) diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index 6192db95dfe..d8bc0a6695b 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -17,6 +17,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + clnull "github.com/smartcontractkit/chainlink-common/pkg/utils/null" + txmgrcommon "github.com/smartcontractkit/chainlink/v2/common/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" @@ -28,7 +30,6 @@ import ( "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" - clnull "github.com/smartcontractkit/chainlink/v2/core/null" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" diff --git a/core/services/webhook/delegate.go b/core/services/webhook/delegate.go index 237245b81c9..7e6aab0bb07 100644 --- a/core/services/webhook/delegate.go +++ b/core/services/webhook/delegate.go @@ -21,6 +21,7 @@ type ( webhookJobRunner *webhookJobRunner externalInitiatorManager ExternalInitiatorManager lggr logger.Logger + stopCh services.StopChan } JobRunner interface { @@ -36,6 +37,7 @@ func NewDelegate(runner pipeline.Runner, externalInitiatorManager ExternalInitia externalInitiatorManager: externalInitiatorManager, webhookJobRunner: newWebhookJobRunner(runner, lggr), lggr: lggr, + stopCh: make(services.StopChan), } } @@ -49,7 +51,9 @@ func (d *Delegate) JobType() job.Type { func (d *Delegate) BeforeJobCreated(spec job.Job) {} func (d *Delegate) AfterJobCreated(jb job.Job) { - err := d.externalInitiatorManager.Notify(*jb.WebhookSpecID) + ctx, cancel := d.stopCh.NewCtx() + defer cancel() + err := d.externalInitiatorManager.Notify(ctx, *jb.WebhookSpecID) if err != nil { d.lggr.Errorw("Webhook delegate AfterJobCreated errored", "err", err, @@ -59,7 +63,9 @@ func (d *Delegate) AfterJobCreated(jb job.Job) { } func (d *Delegate) BeforeJobDeleted(spec job.Job) { - err := d.externalInitiatorManager.DeleteJob(*spec.WebhookSpecID) + ctx, cancel := d.stopCh.NewCtx() + defer cancel() + err := d.externalInitiatorManager.DeleteJob(ctx, *spec.WebhookSpecID) if err != nil { d.lggr.Errorw("Webhook delegate OnDeleteJob errored", "err", err, diff --git a/core/services/webhook/external_initiator_manager.go b/core/services/webhook/external_initiator_manager.go index 01edf82b114..0c035abde7a 100644 --- a/core/services/webhook/external_initiator_manager.go +++ b/core/services/webhook/external_initiator_manager.go @@ -2,6 +2,7 @@ package webhook import ( "bytes" + "context" "encoding/json" "fmt" "net/http" @@ -24,8 +25,8 @@ import ( // ExternalInitiatorManager manages HTTP requests to remote external initiators type ExternalInitiatorManager interface { - Notify(webhookSpecID int32) error - DeleteJob(webhookSpecID int32) error + Notify(ctx context.Context, webhookSpecID int32) error + DeleteJob(ctx context.Context, webhookSpecID int32) error FindExternalInitiatorByName(name string) (bridges.ExternalInitiator, error) } @@ -52,7 +53,7 @@ func NewExternalInitiatorManager(db *sqlx.DB, httpclient HTTPClient, lggr logger // Notify sends a POST notification to the External Initiator // responsible for initiating the Job Spec. -func (m externalInitiatorManager) Notify(webhookSpecID int32) error { +func (m externalInitiatorManager) Notify(ctx context.Context, webhookSpecID int32) error { eiWebhookSpecs, jobID, err := m.Load(webhookSpecID) if err != nil { return err @@ -71,7 +72,7 @@ func (m externalInitiatorManager) Notify(webhookSpecID int32) error { if err != nil { return errors.Wrap(err, "new Job Spec notification") } - req, err := newNotifyHTTPRequest(buf, ei) + req, err := newNotifyHTTPRequest(ctx, buf, ei) if err != nil { return errors.Wrap(err, "creating notify HTTP request") } @@ -136,7 +137,7 @@ func (m externalInitiatorManager) eagerLoadExternalInitiator(q pg.Queryer, txs [ return nil } -func (m externalInitiatorManager) DeleteJob(webhookSpecID int32) error { +func (m externalInitiatorManager) DeleteJob(ctx context.Context, webhookSpecID int32) error { eiWebhookSpecs, jobID, err := m.Load(webhookSpecID) if err != nil { return err @@ -147,7 +148,7 @@ func (m externalInitiatorManager) DeleteJob(webhookSpecID int32) error { continue } - req, err := newDeleteJobFromExternalInitiatorHTTPRequest(ei, jobID) + req, err := newDeleteJobFromExternalInitiatorHTTPRequest(ctx, ei, jobID) if err != nil { return errors.Wrap(err, "creating delete HTTP request") } @@ -178,8 +179,8 @@ type JobSpecNotice struct { Params models.JSON `json:"params,omitempty"` } -func newNotifyHTTPRequest(buf []byte, ei bridges.ExternalInitiator) (*http.Request, error) { - req, err := http.NewRequest(http.MethodPost, ei.URL.String(), bytes.NewBuffer(buf)) +func newNotifyHTTPRequest(ctx context.Context, buf []byte, ei bridges.ExternalInitiator) (*http.Request, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodPost, ei.URL.String(), bytes.NewBuffer(buf)) if err != nil { return nil, err } @@ -187,10 +188,10 @@ func newNotifyHTTPRequest(buf []byte, ei bridges.ExternalInitiator) (*http.Reque return req, nil } -func newDeleteJobFromExternalInitiatorHTTPRequest(ei bridges.ExternalInitiator, jobID uuid.UUID) (*http.Request, error) { +func newDeleteJobFromExternalInitiatorHTTPRequest(ctx context.Context, ei bridges.ExternalInitiator, jobID uuid.UUID) (*http.Request, error) { url := fmt.Sprintf("%s/%s", ei.URL.String(), jobID) - req, err := http.NewRequest(http.MethodDelete, url, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodDelete, url, nil) if err != nil { return nil, err } @@ -208,8 +209,8 @@ type NullExternalInitiatorManager struct{} var _ ExternalInitiatorManager = (*NullExternalInitiatorManager)(nil) -func (NullExternalInitiatorManager) Notify(int32) error { return nil } -func (NullExternalInitiatorManager) DeleteJob(int32) error { return nil } +func (NullExternalInitiatorManager) Notify(context.Context, int32) error { return nil } +func (NullExternalInitiatorManager) DeleteJob(context.Context, int32) error { return nil } func (NullExternalInitiatorManager) FindExternalInitiatorByName(name string) (bridges.ExternalInitiator, error) { return bridges.ExternalInitiator{}, nil } diff --git a/core/services/webhook/external_initiator_manager_test.go b/core/services/webhook/external_initiator_manager_test.go index 568008c2117..553455ebe63 100644 --- a/core/services/webhook/external_initiator_manager_test.go +++ b/core/services/webhook/external_initiator_manager_test.go @@ -12,7 +12,9 @@ import ( "github.com/stretchr/testify/require" "github.com/tidwall/gjson" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "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/pg" @@ -57,6 +59,7 @@ func Test_ExternalInitiatorManager_Load(t *testing.T) { } func Test_ExternalInitiatorManager_Notify(t *testing.T) { + ctx := tests.Context(t) db := pgtest.NewSqlxDB(t) cfg := pgtest.NewQConfig(true) borm := newBridgeORM(t, db, cfg) @@ -78,7 +81,7 @@ func Test_ExternalInitiatorManager_Notify(t *testing.T) { eim := webhook.NewExternalInitiatorManager(db, client, logger.TestLogger(t), cfg) // Does nothing with no EI - require.NoError(t, eim.Notify(webhookSpecNoEIs.ID)) + require.NoError(t, eim.Notify(ctx, webhookSpecNoEIs.ID)) client.On("Do", mock.MatchedBy(func(r *http.Request) bool { body, err := r.GetBody() @@ -92,10 +95,11 @@ func Test_ExternalInitiatorManager_Notify(t *testing.T) { return r.Method == "POST" && r.URL.String() == eiWithURL.URL.String() && r.Header["Content-Type"][0] == "application/json" && r.Header["X-Chainlink-Ea-Accesskey"][0] == "token" && r.Header["X-Chainlink-Ea-Secret"][0] == "secret" })).Once().Return(&http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(""))}, nil) - require.NoError(t, eim.Notify(webhookSpecTwoEIs.ID)) + require.NoError(t, eim.Notify(ctx, webhookSpecTwoEIs.ID)) } func Test_ExternalInitiatorManager_DeleteJob(t *testing.T) { + ctx := testutils.Context(t) db := pgtest.NewSqlxDB(t) cfg := pgtest.NewQConfig(true) borm := newBridgeORM(t, db, cfg) @@ -117,11 +121,11 @@ func Test_ExternalInitiatorManager_DeleteJob(t *testing.T) { eim := webhook.NewExternalInitiatorManager(db, client, logger.TestLogger(t), cfg) // Does nothing with no EI - require.NoError(t, eim.DeleteJob(webhookSpecNoEIs.ID)) + require.NoError(t, eim.DeleteJob(ctx, webhookSpecNoEIs.ID)) client.On("Do", mock.MatchedBy(func(r *http.Request) bool { expectedURL := fmt.Sprintf("%s/%s", eiWithURL.URL.String(), jb.ExternalJobID.String()) return r.Method == "DELETE" && r.URL.String() == expectedURL && r.Header["Content-Type"][0] == "application/json" && r.Header["X-Chainlink-Ea-Accesskey"][0] == "token" && r.Header["X-Chainlink-Ea-Secret"][0] == "secret" })).Once().Return(&http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(""))}, nil) - require.NoError(t, eim.DeleteJob(webhookSpecTwoEIs.ID)) + require.NoError(t, eim.DeleteJob(ctx, webhookSpecTwoEIs.ID)) } diff --git a/core/services/webhook/mocks/external_initiator_manager.go b/core/services/webhook/mocks/external_initiator_manager.go index a94f2ffe97d..010b6f8db0a 100644 --- a/core/services/webhook/mocks/external_initiator_manager.go +++ b/core/services/webhook/mocks/external_initiator_manager.go @@ -1,9 +1,12 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks import ( + context "context" + bridges "github.com/smartcontractkit/chainlink/v2/core/bridges" + mock "github.com/stretchr/testify/mock" ) @@ -12,13 +15,17 @@ type ExternalInitiatorManager struct { mock.Mock } -// DeleteJob provides a mock function with given fields: webhookSpecID -func (_m *ExternalInitiatorManager) DeleteJob(webhookSpecID int32) error { - ret := _m.Called(webhookSpecID) +// DeleteJob provides a mock function with given fields: ctx, webhookSpecID +func (_m *ExternalInitiatorManager) DeleteJob(ctx context.Context, webhookSpecID int32) error { + ret := _m.Called(ctx, webhookSpecID) + + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } var r0 error - if rf, ok := ret.Get(0).(func(int32) error); ok { - r0 = rf(webhookSpecID) + if rf, ok := ret.Get(0).(func(context.Context, int32) error); ok { + r0 = rf(ctx, webhookSpecID) } else { r0 = ret.Error(0) } @@ -30,6 +37,10 @@ func (_m *ExternalInitiatorManager) DeleteJob(webhookSpecID int32) error { func (_m *ExternalInitiatorManager) FindExternalInitiatorByName(name string) (bridges.ExternalInitiator, error) { ret := _m.Called(name) + if len(ret) == 0 { + panic("no return value specified for FindExternalInitiatorByName") + } + var r0 bridges.ExternalInitiator var r1 error if rf, ok := ret.Get(0).(func(string) (bridges.ExternalInitiator, error)); ok { @@ -50,13 +61,17 @@ func (_m *ExternalInitiatorManager) FindExternalInitiatorByName(name string) (br return r0, r1 } -// Notify provides a mock function with given fields: webhookSpecID -func (_m *ExternalInitiatorManager) Notify(webhookSpecID int32) error { - ret := _m.Called(webhookSpecID) +// Notify provides a mock function with given fields: ctx, webhookSpecID +func (_m *ExternalInitiatorManager) Notify(ctx context.Context, webhookSpecID int32) error { + ret := _m.Called(ctx, webhookSpecID) + + if len(ret) == 0 { + panic("no return value specified for Notify") + } var r0 error - if rf, ok := ret.Get(0).(func(int32) error); ok { - r0 = rf(webhookSpecID) + if rf, ok := ret.Get(0).(func(context.Context, int32) error); ok { + r0 = rf(ctx, webhookSpecID) } else { r0 = ret.Error(0) } diff --git a/core/services/webhook/mocks/http_client.go b/core/services/webhook/mocks/http_client.go index b5b448a56d0..fa4f597dc4f 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type HTTPClient struct { func (_m *HTTPClient) Do(req *http.Request) (*http.Response, error) { ret := _m.Called(req) + if len(ret) == 0 { + panic("no return value specified for Do") + } + var r0 *http.Response var r1 error if rf, ok := ret.Get(0).(func(*http.Request) (*http.Response, error)); ok { diff --git a/core/sessions/ldapauth/helpers_test.go b/core/sessions/ldapauth/helpers_test.go index 3566ea84380..5c19afd17d3 100644 --- a/core/sessions/ldapauth/helpers_test.go +++ b/core/sessions/ldapauth/helpers_test.go @@ -5,11 +5,11 @@ import ( "github.com/jmoiron/sqlx" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/store/models" ) // Returns an instantiated ldapAuthenticator struct without validation for testing @@ -66,16 +66,16 @@ func (t *TestConfig) ServerTLS() bool { return false } -func (t *TestConfig) SessionTimeout() models.Duration { - return models.MustMakeDuration(time.Duration(0)) +func (t *TestConfig) SessionTimeout() commonconfig.Duration { + return *commonconfig.MustNewDuration(time.Duration(0)) } func (t *TestConfig) QueryTimeout() time.Duration { return time.Duration(0) } -func (t *TestConfig) UserAPITokenDuration() models.Duration { - return models.MustMakeDuration(time.Duration(0)) +func (t *TestConfig) UserAPITokenDuration() commonconfig.Duration { + return *commonconfig.MustNewDuration(time.Duration(0)) } func (t *TestConfig) BaseUserAttr() string { @@ -122,10 +122,10 @@ func (t *TestConfig) UserApiTokenEnabled() bool { return true } -func (t *TestConfig) UpstreamSyncInterval() models.Duration { - return models.MustMakeDuration(time.Duration(0)) +func (t *TestConfig) UpstreamSyncInterval() commonconfig.Duration { + return *commonconfig.MustNewDuration(time.Duration(0)) } -func (t *TestConfig) UpstreamSyncRateLimit() models.Duration { - return models.MustMakeDuration(time.Duration(0)) +func (t *TestConfig) UpstreamSyncRateLimit() commonconfig.Duration { + return *commonconfig.MustNewDuration(time.Duration(0)) } diff --git a/core/sessions/ldapauth/ldap.go b/core/sessions/ldapauth/ldap.go index 04f6fbfbbb6..147f8bd2aed 100644 --- a/core/sessions/ldapauth/ldap.go +++ b/core/sessions/ldapauth/ldap.go @@ -34,6 +34,7 @@ import ( "github.com/go-ldap/ldap/v3" "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/config" @@ -42,7 +43,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) const ( diff --git a/core/sessions/ldapauth/mocks/ldap_client.go b/core/sessions/ldapauth/mocks/ldap_client.go index 7a44778dcaa..63021636018 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type LDAPClient struct { func (_m *LDAPClient) CreateEphemeralConnection() (ldapauth.LDAPConn, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for CreateEphemeralConnection") + } + var r0 ldapauth.LDAPConn var r1 error if rf, ok := ret.Get(0).(func() (ldapauth.LDAPConn, error)); ok { diff --git a/core/sessions/ldapauth/mocks/ldap_conn.go b/core/sessions/ldapauth/mocks/ldap_conn.go index c05fb6c4fa6..8b4fff82047 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -17,6 +17,10 @@ type LDAPConn struct { func (_m *LDAPConn) Bind(username string, password string) error { ret := _m.Called(username, password) + if len(ret) == 0 { + panic("no return value specified for Bind") + } + var r0 error if rf, ok := ret.Get(0).(func(string, string) error); ok { r0 = rf(username, password) @@ -31,6 +35,10 @@ func (_m *LDAPConn) Bind(username string, password string) error { func (_m *LDAPConn) Close() error { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for Close") + } + var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() @@ -45,6 +53,10 @@ func (_m *LDAPConn) Close() error { func (_m *LDAPConn) Search(searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error) { ret := _m.Called(searchRequest) + if len(ret) == 0 { + panic("no return value specified for Search") + } + var r0 *ldap.SearchResult var r1 error if rf, ok := ret.Get(0).(func(*ldap.SearchRequest) (*ldap.SearchResult, error)); ok { diff --git a/core/sessions/ldapauth/sync.go b/core/sessions/ldapauth/sync.go index 67f101b62a4..74c606a9684 100644 --- a/core/sessions/ldapauth/sync.go +++ b/core/sessions/ldapauth/sync.go @@ -9,11 +9,11 @@ import ( "github.com/jmoiron/sqlx" "github.com/lib/pq" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/sessions" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type LDAPServerStateSyncer struct { @@ -30,7 +30,7 @@ func NewLDAPServerStateSync( pgCfg pg.QConfig, config config.LDAP, lggr logger.Logger, -) utils.SleeperTask { +) *utils.SleeperTask { namedLogger := lggr.Named("LDAPServerStateSync") serverSync := LDAPServerStateSyncer{ q: pg.NewQ(db, namedLogger, pgCfg), diff --git a/core/sessions/localauth/orm.go b/core/sessions/localauth/orm.go index 090dc468a62..013f719ad34 100644 --- a/core/sessions/localauth/orm.go +++ b/core/sessions/localauth/orm.go @@ -9,6 +9,7 @@ import ( "github.com/jmoiron/sqlx" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/utils/mathutil" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -16,7 +17,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/mathutil" ) type orm struct { diff --git a/core/sessions/localauth/reaper.go b/core/sessions/localauth/reaper.go index 77d1b1abef2..eef884367aa 100644 --- a/core/sessions/localauth/reaper.go +++ b/core/sessions/localauth/reaper.go @@ -4,9 +4,9 @@ import ( "database/sql" "time" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type sessionReaper struct { @@ -16,12 +16,12 @@ type sessionReaper struct { } type SessionReaperConfig interface { - SessionTimeout() models.Duration - SessionReaperExpiration() models.Duration + SessionTimeout() commonconfig.Duration + SessionReaperExpiration() commonconfig.Duration } // NewSessionReaper creates a reaper that cleans stale sessions from the store. -func NewSessionReaper(db *sql.DB, config SessionReaperConfig, lggr logger.Logger) utils.SleeperTask { +func NewSessionReaper(db *sql.DB, config SessionReaperConfig, lggr logger.Logger) *utils.SleeperTask { return utils.NewSleeperTask(&sessionReaper{ db, config, diff --git a/core/sessions/localauth/reaper_test.go b/core/sessions/localauth/reaper_test.go index 43a263d0321..fa9d882f743 100644 --- a/core/sessions/localauth/reaper_test.go +++ b/core/sessions/localauth/reaper_test.go @@ -4,27 +4,28 @@ import ( "testing" "time" + "github.com/onsi/gomega" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - - "github.com/onsi/gomega" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) type sessionReaperConfig struct{} -func (c sessionReaperConfig) SessionTimeout() models.Duration { - return models.MustMakeDuration(42 * time.Second) +func (c sessionReaperConfig) SessionTimeout() commonconfig.Duration { + return *commonconfig.MustNewDuration(42 * time.Second) } -func (c sessionReaperConfig) SessionReaperExpiration() models.Duration { - return models.MustMakeDuration(142 * time.Second) +func (c sessionReaperConfig) SessionReaperExpiration() commonconfig.Duration { + return *commonconfig.MustNewDuration(142 * time.Second) } func TestSessionReaper_ReapSessions(t *testing.T) { diff --git a/core/sessions/mocks/authentication_provider.go b/core/sessions/mocks/authentication_provider.go index d6e33d11e45..d1b846c318b 100644 --- a/core/sessions/mocks/authentication_provider.go +++ b/core/sessions/mocks/authentication_provider.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -20,6 +20,10 @@ type AuthenticationProvider struct { func (_m *AuthenticationProvider) AuthorizedUserWithSession(sessionID string) (sessions.User, error) { ret := _m.Called(sessionID) + if len(ret) == 0 { + panic("no return value specified for AuthorizedUserWithSession") + } + var r0 sessions.User var r1 error if rf, ok := ret.Get(0).(func(string) (sessions.User, error)); ok { @@ -44,6 +48,10 @@ func (_m *AuthenticationProvider) AuthorizedUserWithSession(sessionID string) (s func (_m *AuthenticationProvider) ClearNonCurrentSessions(sessionID string) error { ret := _m.Called(sessionID) + if len(ret) == 0 { + panic("no return value specified for ClearNonCurrentSessions") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(sessionID) @@ -58,6 +66,10 @@ func (_m *AuthenticationProvider) ClearNonCurrentSessions(sessionID string) erro func (_m *AuthenticationProvider) CreateAndSetAuthToken(user *sessions.User) (*auth.Token, error) { ret := _m.Called(user) + if len(ret) == 0 { + panic("no return value specified for CreateAndSetAuthToken") + } + var r0 *auth.Token var r1 error if rf, ok := ret.Get(0).(func(*sessions.User) (*auth.Token, error)); ok { @@ -84,6 +96,10 @@ func (_m *AuthenticationProvider) CreateAndSetAuthToken(user *sessions.User) (*a func (_m *AuthenticationProvider) CreateSession(sr sessions.SessionRequest) (string, error) { ret := _m.Called(sr) + if len(ret) == 0 { + panic("no return value specified for CreateSession") + } + var r0 string var r1 error if rf, ok := ret.Get(0).(func(sessions.SessionRequest) (string, error)); ok { @@ -108,6 +124,10 @@ func (_m *AuthenticationProvider) CreateSession(sr sessions.SessionRequest) (str func (_m *AuthenticationProvider) CreateUser(user *sessions.User) error { ret := _m.Called(user) + if len(ret) == 0 { + panic("no return value specified for CreateUser") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.User) error); ok { r0 = rf(user) @@ -122,6 +142,10 @@ func (_m *AuthenticationProvider) CreateUser(user *sessions.User) error { func (_m *AuthenticationProvider) DeleteAuthToken(user *sessions.User) error { ret := _m.Called(user) + if len(ret) == 0 { + panic("no return value specified for DeleteAuthToken") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.User) error); ok { r0 = rf(user) @@ -136,6 +160,10 @@ func (_m *AuthenticationProvider) DeleteAuthToken(user *sessions.User) error { func (_m *AuthenticationProvider) DeleteUser(email string) error { ret := _m.Called(email) + if len(ret) == 0 { + panic("no return value specified for DeleteUser") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(email) @@ -150,6 +178,10 @@ func (_m *AuthenticationProvider) DeleteUser(email string) error { func (_m *AuthenticationProvider) DeleteUserSession(sessionID string) error { ret := _m.Called(sessionID) + if len(ret) == 0 { + panic("no return value specified for DeleteUserSession") + } + var r0 error if rf, ok := ret.Get(0).(func(string) error); ok { r0 = rf(sessionID) @@ -164,6 +196,10 @@ func (_m *AuthenticationProvider) DeleteUserSession(sessionID string) error { func (_m *AuthenticationProvider) FindExternalInitiator(eia *auth.Token) (*bridges.ExternalInitiator, error) { ret := _m.Called(eia) + if len(ret) == 0 { + panic("no return value specified for FindExternalInitiator") + } + var r0 *bridges.ExternalInitiator var r1 error if rf, ok := ret.Get(0).(func(*auth.Token) (*bridges.ExternalInitiator, error)); ok { @@ -190,6 +226,10 @@ func (_m *AuthenticationProvider) FindExternalInitiator(eia *auth.Token) (*bridg func (_m *AuthenticationProvider) FindUser(email string) (sessions.User, error) { ret := _m.Called(email) + if len(ret) == 0 { + panic("no return value specified for FindUser") + } + var r0 sessions.User var r1 error if rf, ok := ret.Get(0).(func(string) (sessions.User, error)); ok { @@ -214,6 +254,10 @@ func (_m *AuthenticationProvider) FindUser(email string) (sessions.User, error) func (_m *AuthenticationProvider) FindUserByAPIToken(apiToken string) (sessions.User, error) { ret := _m.Called(apiToken) + if len(ret) == 0 { + panic("no return value specified for FindUserByAPIToken") + } + var r0 sessions.User var r1 error if rf, ok := ret.Get(0).(func(string) (sessions.User, error)); ok { @@ -238,6 +282,10 @@ func (_m *AuthenticationProvider) FindUserByAPIToken(apiToken string) (sessions. func (_m *AuthenticationProvider) GetUserWebAuthn(email string) ([]sessions.WebAuthn, error) { ret := _m.Called(email) + if len(ret) == 0 { + panic("no return value specified for GetUserWebAuthn") + } + var r0 []sessions.WebAuthn var r1 error if rf, ok := ret.Get(0).(func(string) ([]sessions.WebAuthn, error)); ok { @@ -264,6 +312,10 @@ func (_m *AuthenticationProvider) GetUserWebAuthn(email string) ([]sessions.WebA func (_m *AuthenticationProvider) ListUsers() ([]sessions.User, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListUsers") + } + var r0 []sessions.User var r1 error if rf, ok := ret.Get(0).(func() ([]sessions.User, error)); ok { @@ -290,6 +342,10 @@ func (_m *AuthenticationProvider) ListUsers() ([]sessions.User, error) { func (_m *AuthenticationProvider) SaveWebAuthn(token *sessions.WebAuthn) error { ret := _m.Called(token) + if len(ret) == 0 { + panic("no return value specified for SaveWebAuthn") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.WebAuthn) error); ok { r0 = rf(token) @@ -304,6 +360,10 @@ func (_m *AuthenticationProvider) SaveWebAuthn(token *sessions.WebAuthn) error { func (_m *AuthenticationProvider) Sessions(offset int, limit int) ([]sessions.Session, error) { ret := _m.Called(offset, limit) + if len(ret) == 0 { + panic("no return value specified for Sessions") + } + var r0 []sessions.Session var r1 error if rf, ok := ret.Get(0).(func(int, int) ([]sessions.Session, error)); ok { @@ -330,6 +390,10 @@ func (_m *AuthenticationProvider) Sessions(offset int, limit int) ([]sessions.Se func (_m *AuthenticationProvider) SetAuthToken(user *sessions.User, token *auth.Token) error { ret := _m.Called(user, token) + if len(ret) == 0 { + panic("no return value specified for SetAuthToken") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.User, *auth.Token) error); ok { r0 = rf(user, token) @@ -344,6 +408,10 @@ func (_m *AuthenticationProvider) SetAuthToken(user *sessions.User, token *auth. func (_m *AuthenticationProvider) SetPassword(user *sessions.User, newPassword string) error { ret := _m.Called(user, newPassword) + if len(ret) == 0 { + panic("no return value specified for SetPassword") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.User, string) error); ok { r0 = rf(user, newPassword) @@ -358,6 +426,10 @@ func (_m *AuthenticationProvider) SetPassword(user *sessions.User, newPassword s func (_m *AuthenticationProvider) TestPassword(email string, password string) error { ret := _m.Called(email, password) + if len(ret) == 0 { + panic("no return value specified for TestPassword") + } + var r0 error if rf, ok := ret.Get(0).(func(string, string) error); ok { r0 = rf(email, password) @@ -372,6 +444,10 @@ func (_m *AuthenticationProvider) TestPassword(email string, password string) er func (_m *AuthenticationProvider) UpdateRole(email string, newRole string) (sessions.User, error) { ret := _m.Called(email, newRole) + if len(ret) == 0 { + panic("no return value specified for UpdateRole") + } + var r0 sessions.User var r1 error if rf, ok := ret.Get(0).(func(string, string) (sessions.User, error)); ok { diff --git a/core/sessions/mocks/basic_admin_users_orm.go b/core/sessions/mocks/basic_admin_users_orm.go index 845e2d8880e..44ee0b1f705 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.35.4. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -16,6 +16,10 @@ type BasicAdminUsersORM struct { func (_m *BasicAdminUsersORM) CreateUser(user *sessions.User) error { ret := _m.Called(user) + if len(ret) == 0 { + panic("no return value specified for CreateUser") + } + var r0 error if rf, ok := ret.Get(0).(func(*sessions.User) error); ok { r0 = rf(user) @@ -30,6 +34,10 @@ func (_m *BasicAdminUsersORM) CreateUser(user *sessions.User) error { func (_m *BasicAdminUsersORM) FindUser(email string) (sessions.User, error) { ret := _m.Called(email) + if len(ret) == 0 { + panic("no return value specified for FindUser") + } + var r0 sessions.User var r1 error if rf, ok := ret.Get(0).(func(string) (sessions.User, error)); ok { @@ -54,6 +62,10 @@ func (_m *BasicAdminUsersORM) FindUser(email string) (sessions.User, error) { func (_m *BasicAdminUsersORM) ListUsers() ([]sessions.User, error) { ret := _m.Called() + if len(ret) == 0 { + panic("no return value specified for ListUsers") + } + var r0 []sessions.User var r1 error if rf, ok := ret.Get(0).(func() ([]sessions.User, error)); ok { diff --git a/core/store/migrate/migrate_test.go b/core/store/migrate/migrate_test.go index 43ddd41d56f..56d1fe41eb5 100644 --- a/core/store/migrate/migrate_test.go +++ b/core/store/migrate/migrate_test.go @@ -16,6 +16,7 @@ import ( evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest/heavyweight" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -29,7 +30,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/store/migrate" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var migrationDir = "migrations" @@ -417,7 +417,7 @@ func TestMigrate(t *testing.T) { func TestSetMigrationENVVars(t *testing.T) { t.Run("ValidEVMConfig", func(t *testing.T) { - chainID := utils.NewBig(big.NewInt(1337)) + chainID := ubig.New(big.NewInt(1337)) testConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { evmEnabled := true c.EVM = evmcfg.EVMConfigs{&evmcfg.EVMConfig{ @@ -433,7 +433,7 @@ func TestSetMigrationENVVars(t *testing.T) { }) t.Run("EVMConfigMissing", func(t *testing.T) { - chainID := utils.NewBig(big.NewInt(1337)) + chainID := ubig.New(big.NewInt(1337)) testConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM = nil }) require.NoError(t, migrate.SetMigrationENVVars(testConfig)) @@ -516,6 +516,31 @@ func TestDatabaseBackFillWithMigration202(t *testing.T) { } } +func TestNoTriggers(t *testing.T) { + _, db := heavyweight.FullTestDBEmptyV2(t, nil) + + assert_num_triggers := func(expected int) { + + row := db.DB.QueryRow("select count(*) from information_schema.triggers") + var count int + err := row.Scan(&count) + + require.NoError(t, err) + require.Equal(t, expected, count) + } + + // if you find yourself here and are tempted to add a trigger, something has gone wrong + // and you should talk to the foundations team before proceeding + assert_num_triggers(0) + + // version prior to removal of all triggers + v := 217 + err := goose.UpTo(db.DB, migrationDir, int64(v)) + require.NoError(t, err) + assert_num_triggers(1) + +} + func BenchmarkBackfillingRecordsWithMigration202(b *testing.B) { previousMigration := int64(201) backfillMigration := int64(202) @@ -535,7 +560,7 @@ func BenchmarkBackfillingRecordsWithMigration202(b *testing.B) { var blocks []logpoller.LogPollerBlock for i := 0; i < maxLogsSize; i++ { blocks = append(blocks, logpoller.LogPollerBlock{ - EvmChainId: utils.NewBigI(int64(j + 1)), + EvmChainId: ubig.NewI(int64(j + 1)), BlockHash: testutils.Random32Byte(), BlockNumber: int64(i + 1000), FinalizedBlockNumber: 0, diff --git a/core/store/migrate/migrations/0212_ocr_oracle_specs_drop_p2p_bootstrap_peers.sql b/core/store/migrate/migrations/0212_ocr_oracle_specs_drop_p2p_bootstrap_peers.sql new file mode 100644 index 00000000000..d38370e3f2e --- /dev/null +++ b/core/store/migrate/migrations/0212_ocr_oracle_specs_drop_p2p_bootstrap_peers.sql @@ -0,0 +1,5 @@ +-- +goose Up +ALTER TABLE ocr_oracle_specs DROP COLUMN p2p_bootstrap_peers; + +-- +goose Down +ALTER TABLE ocr_oracle_specs ADD COLUMN p2p_bootstrap_peers text[]; diff --git a/core/store/migrate/migrations/0213_liquidity_balancer_specs.sql b/core/store/migrate/migrations/0213_liquidity_balancer_specs.sql new file mode 100644 index 00000000000..cd717181f58 --- /dev/null +++ b/core/store/migrate/migrations/0213_liquidity_balancer_specs.sql @@ -0,0 +1,49 @@ +-- +goose Up +CREATE TABLE liquidity_balancer_specs ( + id BIGSERIAL PRIMARY KEY, + liquidity_balancer_config JSONB NOT NULL +); + +ALTER TABLE + jobs +ADD COLUMN + liquidity_balancer_spec_id BIGINT REFERENCES liquidity_balancer_specs(id), +DROP CONSTRAINT chk_only_one_spec, +ADD CONSTRAINT chk_only_one_spec CHECK ( + num_nonnulls( + ocr_oracle_spec_id, ocr2_oracle_spec_id, + direct_request_spec_id, flux_monitor_spec_id, + keeper_spec_id, cron_spec_id, webhook_spec_id, + vrf_spec_id, blockhash_store_spec_id, + block_header_feeder_spec_id, bootstrap_spec_id, + gateway_spec_id, + legacy_gas_station_server_spec_id, + legacy_gas_station_sidecar_spec_id, + eal_spec_id, + liquidity_balancer_spec_id + ) = 1 +); + +-- +goose Down +ALTER TABLE + jobs +DROP CONSTRAINT chk_only_one_spec, +ADD CONSTRAINT chk_only_one_spec CHECK ( + num_nonnulls( + ocr_oracle_spec_id, ocr2_oracle_spec_id, + direct_request_spec_id, flux_monitor_spec_id, + keeper_spec_id, cron_spec_id, webhook_spec_id, + vrf_spec_id, blockhash_store_spec_id, + block_header_feeder_spec_id, bootstrap_spec_id, + gateway_spec_id, + legacy_gas_station_server_spec_id, + legacy_gas_station_sidecar_spec_id, + eal_spec_id + ) = 1 +); +ALTER TABLE + jobs +DROP COLUMN + liquidity_balancer_spec_id; +DROP TABLE + liquidity_balancer_specs; diff --git a/core/store/migrate/migrations/0214_add_custom_reverts_vrf.sql b/core/store/migrate/migrations/0214_add_custom_reverts_vrf.sql new file mode 100644 index 00000000000..a2865fce816 --- /dev/null +++ b/core/store/migrate/migrations/0214_add_custom_reverts_vrf.sql @@ -0,0 +1,5 @@ +-- +goose Up +ALTER TABLE vrf_specs ADD COLUMN custom_reverts_pipeline_enabled boolean DEFAULT FALSE NOT NULL; + +-- +goose Down +ALTER TABLE vrf_specs DROP COLUMN custom_reverts_pipeline_enabled; diff --git a/core/store/migrate/migrations/0215_functions_subscriptions.sql b/core/store/migrate/migrations/0215_functions_subscriptions.sql new file mode 100644 index 00000000000..c3859d42f63 --- /dev/null +++ b/core/store/migrate/migrations/0215_functions_subscriptions.sql @@ -0,0 +1,19 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE functions_subscriptions( + router_contract_address bytea, + subscription_id bigint, + owner bytea CHECK (octet_length(owner) = 20) NOT NULL, + balance bigint, + blocked_balance bigint, + proposed_owner bytea, + consumers bytea[], + flags bytea, + PRIMARY KEY(router_contract_address, subscription_id) +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE IF EXISTS functions_subscriptions; +-- +goose StatementEnd diff --git a/core/store/migrate/migrations/0216_drop_terra_state_transition_trigger.sql b/core/store/migrate/migrations/0216_drop_terra_state_transition_trigger.sql new file mode 100644 index 00000000000..77a7c04a4f6 --- /dev/null +++ b/core/store/migrate/migrations/0216_drop_terra_state_transition_trigger.sql @@ -0,0 +1,27 @@ +-- +goose Up + +-- +goose StatementBegin +DROP FUNCTION IF EXISTS PUBLIC.check_terra_msg_state_transition; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin + +CREATE OR REPLACE FUNCTION PUBLIC.check_terra_msg_state_transition() RETURNS TRIGGER AS $$ +DECLARE +state_transition_map jsonb := json_build_object( + 'unstarted', json_build_object('errored', true, 'started', true), + 'started', json_build_object('errored', true, 'broadcasted', true), + 'broadcasted', json_build_object('errored', true, 'confirmed', true)); +BEGIN + IF NOT state_transition_map ? OLD.state THEN + RAISE EXCEPTION 'Invalid from state %. Valid from states %', OLD.state, state_transition_map; +END IF; + IF NOT state_transition_map->OLD.state ? NEW.state THEN + RAISE EXCEPTION 'Invalid state transition from % to %. Valid to states %', OLD.state, NEW.state, state_transition_map->OLD.state; +END IF; +RETURN NEW; +END +$$ LANGUAGE plpgsql; + +-- +goose StatementEnd \ No newline at end of file diff --git a/core/store/migrate/migrations/0217_drop_unused_job_triggers.sql b/core/store/migrate/migrations/0217_drop_unused_job_triggers.sql new file mode 100644 index 00000000000..a59e5d5b225 --- /dev/null +++ b/core/store/migrate/migrations/0217_drop_unused_job_triggers.sql @@ -0,0 +1,48 @@ +-- +goose Up +-- +goose StatementBegin +DROP TRIGGER IF EXISTS notify_job_created ON PUBLIC.jobs; +DROP FUNCTION IF EXISTS PUBLIC.notifyjobcreated(); + +DROP TRIGGER IF EXISTS notify_job_deleted ON PUBLIC.jobs; +DROP FUNCTION IF EXISTS PUBLIC.notifyjobdeleted(); + +DROP TRIGGER IF EXISTS notify_pipeline_run_started ON PUBLIC.pipeline_runs; +DROP FUNCTION IF EXISTS PUBLIC.notifypipelinerunstarted(); +-- +goose StatementEnd + + +-- +goose Down +-- +goose StatementBegin +CREATE FUNCTION PUBLIC.notifyjobcreated() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + PERFORM pg_notify('insert_on_jobs', NEW.id::text); + RETURN NEW; + END + $$; +CREATE TRIGGER notify_job_created AFTER INSERT ON PUBLIC.jobs FOR EACH ROW EXECUTE PROCEDURE PUBLIC.notifyjobcreated(); + +CREATE FUNCTION PUBLIC.notifyjobdeleted() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + PERFORM pg_notify('delete_from_jobs', OLD.id::text); + RETURN OLD; + END + $$; +CREATE TRIGGER notify_job_deleted AFTER DELETE ON PUBLIC.jobs FOR EACH ROW EXECUTE PROCEDURE PUBLIC.notifyjobdeleted(); + +CREATE FUNCTION PUBLIC.notifypipelinerunstarted() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + IF NEW.finished_at IS NULL THEN + PERFORM pg_notify('pipeline_run_started', NEW.id::text); + END IF; + RETURN NEW; + END + $$; +CREATE TRIGGER notify_pipeline_run_started AFTER INSERT ON PUBLIC.pipeline_runs FOR EACH ROW EXECUTE PROCEDURE PUBLIC.notifypipelinerunstarted(); + +-- +goose StatementEnd diff --git a/core/store/migrate/migrations/0218_drop_log_topic_trigger.sql b/core/store/migrate/migrations/0218_drop_log_topic_trigger.sql new file mode 100644 index 00000000000..ea80cccd2b5 --- /dev/null +++ b/core/store/migrate/migrations/0218_drop_log_topic_trigger.sql @@ -0,0 +1,27 @@ +-- +goose Up +-- +goose StatementBegin +DROP TRIGGER IF EXISTS notify_insert_on_logs_topics ON EVM.logs; +DROP FUNCTION IF EXISTS evm.notifysavedlogtopics(); + +-- +goose StatementEnd + + +-- +goose Down +-- +goose StatementBegin + +CREATE FUNCTION evm.notifysavedlogtopics() RETURNS trigger + LANGUAGE plpgsql +AS $$ +BEGIN + PERFORM pg_notify( + 'evm.insert_on_logs'::text, + -- hex encoded address plus comma separated list of hex encoded topic values + -- e.g. "
:," + encode(NEW.address, 'hex') || ':' || array_to_string(array(SELECT encode(unnest(NEW.topics), 'hex')), ',') + ); + RETURN NULL; +END +$$; + +CREATE TRIGGER notify_insert_on_logs_topics AFTER INSERT ON evm.logs FOR EACH ROW EXECUTE PROCEDURE evm.notifysavedlogtopics(); +-- +goose StatementEnd diff --git a/core/store/migrate/migrations/0219_drop_notifytxinsertion.sql b/core/store/migrate/migrations/0219_drop_notifytxinsertion.sql new file mode 100644 index 00000000000..9569fa48728 --- /dev/null +++ b/core/store/migrate/migrations/0219_drop_notifytxinsertion.sql @@ -0,0 +1,16 @@ +-- +goose Up +-- +goose StatementBegin +DROP FUNCTION IF EXISTS evm.notifytxinsertion(); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +CREATE OR REPLACE FUNCTION evm.notifytxinsertion() RETURNS trigger + LANGUAGE plpgsql + AS $$ + BEGIN + PERFORM pg_notify('evm.insert_on_txes'::text, encode(NEW.from_address, 'hex')); + RETURN NULL; + END + $$; +-- +goose StatementEnd diff --git a/core/store/migrate/migrations/0220_stream_specs.sql b/core/store/migrate/migrations/0220_stream_specs.sql new file mode 100644 index 00000000000..f446928702c --- /dev/null +++ b/core/store/migrate/migrations/0220_stream_specs.sql @@ -0,0 +1,40 @@ +-- +goose Up +ALTER TABLE + jobs +DROP + CONSTRAINT chk_only_one_spec, +ADD + CONSTRAINT chk_specs CHECK ( + num_nonnulls( + ocr_oracle_spec_id, ocr2_oracle_spec_id, + direct_request_spec_id, flux_monitor_spec_id, + keeper_spec_id, cron_spec_id, webhook_spec_id, + vrf_spec_id, blockhash_store_spec_id, + block_header_feeder_spec_id, bootstrap_spec_id, + gateway_spec_id, + legacy_gas_station_server_spec_id, + legacy_gas_station_sidecar_spec_id, + eal_spec_id, + CASE "type" WHEN 'stream' THEN 1 ELSE NULL END -- 'stream' type lacks a spec but should not cause validation to fail + ) = 1 + ); + +-- +goose Down +ALTER TABLE + jobs +DROP + CONSTRAINT chk_specs, +ADD + CONSTRAINT chk_only_one_spec CHECK ( + num_nonnulls( + ocr_oracle_spec_id, ocr2_oracle_spec_id, + direct_request_spec_id, flux_monitor_spec_id, + keeper_spec_id, cron_spec_id, webhook_spec_id, + vrf_spec_id, blockhash_store_spec_id, + block_header_feeder_spec_id, bootstrap_spec_id, + gateway_spec_id, + legacy_gas_station_server_spec_id, + legacy_gas_station_sidecar_spec_id, + eal_spec_id + ) = 1 + ); diff --git a/core/store/migrate/migrations/0221_functions_allowlist.sql b/core/store/migrate/migrations/0221_functions_allowlist.sql new file mode 100644 index 00000000000..e97b2fc4077 --- /dev/null +++ b/core/store/migrate/migrations/0221_functions_allowlist.sql @@ -0,0 +1,22 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE functions_allowlist( + id BIGSERIAL, + router_contract_address bytea CHECK (octet_length(router_contract_address) = 20) NOT NULL, + allowed_address bytea CHECK (octet_length(allowed_address) = 20) NOT NULL, + PRIMARY KEY(router_contract_address, allowed_address) +); + +ALTER TABLE functions_subscriptions +ADD CONSTRAINT router_contract_address_octet_length CHECK (octet_length(router_contract_address) = 20); + +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin + +ALTER TABLE functions_subscriptions +DROP CONSTRAINT router_contract_address_octet_length; + +DROP TABLE IF EXISTS functions_allowlist; +-- +goose StatementEnd diff --git a/core/store/models/common.go b/core/store/models/common.go index 10f391861e1..e446481ff64 100644 --- a/core/store/models/common.go +++ b/core/store/models/common.go @@ -18,7 +18,7 @@ import ( "go.uber.org/multierr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // CronParser is the global parser for crontabs. @@ -197,119 +197,6 @@ func (c Cron) String() string { return string(c) } -// Duration is a non-negative time duration. -type Duration struct{ d time.Duration } - -func MakeDuration(d time.Duration) (Duration, error) { - if d < time.Duration(0) { - return Duration{}, fmt.Errorf("cannot make negative time duration: %s", d) - } - return Duration{d: d}, nil -} - -func ParseDuration(s string) (Duration, error) { - d, err := time.ParseDuration(s) - if err != nil { - return Duration{}, err - } - - return MakeDuration(d) -} - -func MustMakeDuration(d time.Duration) Duration { - rv, err := MakeDuration(d) - if err != nil { - panic(err) - } - return rv -} - -func MustNewDuration(d time.Duration) *Duration { - rv := MustMakeDuration(d) - return &rv -} - -// Duration returns the value as the standard time.Duration value. -func (d Duration) Duration() time.Duration { - return d.d -} - -// Before returns the time d units before time t -func (d Duration) Before(t time.Time) time.Time { - return t.Add(-d.Duration()) -} - -// Shorter returns true if and only if d is shorter than od. -func (d Duration) Shorter(od Duration) bool { return d.d < od.d } - -// IsInstant is true if and only if d is of duration 0 -func (d Duration) IsInstant() bool { return d.d == 0 } - -// String returns a string representing the duration in the form "72h3m0.5s". -// Leading zero units are omitted. As a special case, durations less than one -// second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure -// that the leading digit is non-zero. The zero duration formats as 0s. -func (d Duration) String() string { - return d.Duration().String() -} - -// MarshalJSON implements the json.Marshaler interface. -func (d Duration) MarshalJSON() ([]byte, error) { - return json.Marshal(d.String()) -} - -// UnmarshalJSON implements the json.Unmarshaler interface. -func (d *Duration) UnmarshalJSON(input []byte) error { - var txt string - err := json.Unmarshal(input, &txt) - if err != nil { - return err - } - v, err := time.ParseDuration(string(txt)) - if err != nil { - return err - } - *d, err = MakeDuration(v) - if err != nil { - return err - } - return nil -} - -func (d *Duration) Scan(v interface{}) (err error) { - switch tv := v.(type) { - case int64: - *d, err = MakeDuration(time.Duration(tv)) - return err - default: - return errors.Errorf(`don't know how to parse "%s" of type %T as a `+ - `models.Duration`, tv, tv) - } -} - -func (d Duration) Value() (driver.Value, error) { - return int64(d.d), nil -} - -// MarshalText implements the text.Marshaler interface. -func (d Duration) MarshalText() ([]byte, error) { - return []byte(d.d.String()), nil -} - -// UnmarshalText implements the text.Unmarshaler interface. -func (d *Duration) UnmarshalText(input []byte) error { - v, err := time.ParseDuration(string(input)) - if err != nil { - return err - } - pd, err := MakeDuration(v) - if err != nil { - return err - } - *d = pd - return nil -} - // Interval represents a time.Duration stored as a Postgres interval type type Interval time.Duration @@ -365,7 +252,7 @@ type SendEtherRequest struct { DestinationAddress common.Address `json:"address"` FromAddress common.Address `json:"from"` Amount assets.Eth `json:"amount"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` AllowHigherAmounts bool `json:"allowHigherAmounts"` SkipWaitTxAttempt bool `json:"skipWaitTxAttempt"` WaitAttemptTimeout *time.Duration `json:"waitAttemptTimeout"` @@ -513,60 +400,6 @@ func (s Sha256Hash) Value() (driver.Value, error) { return b, nil } -// URL extends url.URL to implement encoding.TextMarshaler. -type URL url.URL - -func ParseURL(s string) (*URL, error) { - u, err := url.Parse(s) - if err != nil { - return nil, err - } - return (*URL)(u), nil -} - -func MustParseURL(s string) *URL { - u, err := ParseURL(s) - if err != nil { - panic(err) - } - return u -} - -func (u *URL) String() string { - return (*url.URL)(u).String() -} - -// URL returns a copy of u as a *url.URL -func (u *URL) URL() *url.URL { - if u == nil { - return nil - } - // defensive copy - r := url.URL(*u) - if u.User != nil { - r.User = new(url.Userinfo) - *r.User = *u.User - } - return &r -} - -func (u *URL) IsZero() bool { - return (url.URL)(*u) == url.URL{} -} - -func (u *URL) MarshalText() ([]byte, error) { - return []byte(u.String()), nil -} - -func (u *URL) UnmarshalText(input []byte) error { - v, err := url.Parse(string(input)) - if err != nil { - return err - } - *u = URL(*v) - return nil -} - // ServiceHeader is an HTTP header to include in POST to log service. type ServiceHeader struct { Header string diff --git a/core/store/models/common_test.go b/core/store/models/common_test.go index 57b7ca73c6b..eca703d5f3a 100644 --- a/core/store/models/common_test.go +++ b/core/store/models/common_test.go @@ -189,27 +189,6 @@ func TestWebURL_String_HasNilURL(t *testing.T) { assert.Equal(t, "", w.String()) } -func TestDuration_MarshalJSON(t *testing.T) { - tests := []struct { - name string - input models.Duration - want string - }{ - {"zero", models.MustMakeDuration(0), `"0s"`}, - {"one second", models.MustMakeDuration(time.Second), `"1s"`}, - {"one minute", models.MustMakeDuration(time.Minute), `"1m0s"`}, - {"one hour", models.MustMakeDuration(time.Hour), `"1h0m0s"`}, - {"one hour thirty minutes", models.MustMakeDuration(time.Hour + 30*time.Minute), `"1h30m0s"`}, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - b, err := json.Marshal(test.input) - assert.NoError(t, err) - assert.Equal(t, test.want, string(b)) - }) - } -} - func TestCron_UnmarshalJSON_Success(t *testing.T) { t.Parallel() @@ -385,49 +364,6 @@ func TestInterval_MarshalText_UnmarshalText(t *testing.T) { require.Equal(t, i, iNew) } -func TestDuration_Scan_Value(t *testing.T) { - t.Parallel() - - d := models.MustMakeDuration(100) - require.NotNil(t, d) - - val, err := d.Value() - require.NoError(t, err) - - dNew := models.MustMakeDuration(0) - err = dNew.Scan(val) - require.NoError(t, err) - - require.Equal(t, d, dNew) -} - -func TestDuration_MarshalJSON_UnmarshalJSON(t *testing.T) { - t.Parallel() - - d := models.MustMakeDuration(100) - require.NotNil(t, d) - - json, err := d.MarshalJSON() - require.NoError(t, err) - - dNew := models.MustMakeDuration(0) - err = dNew.UnmarshalJSON(json) - require.NoError(t, err) - - require.Equal(t, d, dNew) -} - -func TestDuration_MakeDurationFromString(t *testing.T) { - t.Parallel() - - d, err := models.ParseDuration("1s") - require.NoError(t, err) - require.Equal(t, 1*time.Second, d.Duration()) - - _, err = models.ParseDuration("xyz") - require.Error(t, err) -} - func TestWebURL_Scan_Value(t *testing.T) { t.Parallel() diff --git a/core/store/models/secrets.go b/core/store/models/secrets.go index a7afc95b6cc..ac5cac01734 100644 --- a/core/store/models/secrets.go +++ b/core/store/models/secrets.go @@ -4,6 +4,8 @@ import ( "encoding" "fmt" "net/url" + + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) const redacted = "xxxxx" @@ -33,22 +35,22 @@ var ( ) // SecretURL is a URL that formats and encodes redacted, as "xxxxx". -type SecretURL URL +type SecretURL commonconfig.URL -func NewSecretURL(u *URL) *SecretURL { return (*SecretURL)(u) } +func NewSecretURL(u *commonconfig.URL) *SecretURL { return (*SecretURL)(u) } -func MustSecretURL(u string) *SecretURL { return NewSecretURL(MustParseURL(u)) } +func MustSecretURL(u string) *SecretURL { return NewSecretURL(commonconfig.MustParseURL(u)) } func (s *SecretURL) String() string { return redacted } func (s *SecretURL) GoString() string { return redacted } -func (s *SecretURL) URL() *url.URL { return (*URL)(s).URL() } +func (s *SecretURL) URL() *url.URL { return (*commonconfig.URL)(s).URL() } func (s *SecretURL) MarshalText() ([]byte, error) { return []byte(redacted), nil } func (s *SecretURL) UnmarshalText(text []byte) error { - if err := (*URL)(s).UnmarshalText(text); err != nil { + if err := (*commonconfig.URL)(s).UnmarshalText(text); err != nil { //opt: if errors.Is(url.Error), just redact the err.URL field? return fmt.Errorf("failed to parse url: %s", redacted) } diff --git a/core/testdata/testspecs/v2_specs.go b/core/testdata/testspecs/v2_specs.go index 0ecb85f1e49..e66971a7a11 100644 --- a/core/testdata/testspecs/v2_specs.go +++ b/core/testdata/testspecs/v2_specs.go @@ -9,9 +9,9 @@ import ( "github.com/google/uuid" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -234,6 +234,7 @@ type VRFSpecParams struct { BatchCoordinatorAddress string VRFOwnerAddress string BatchFulfillmentEnabled bool + CustomRevertsPipelineEnabled bool BatchFulfillmentGasMultiplier float64 MinIncomingConfirmations int FromAddresses []string @@ -403,6 +404,7 @@ evmChainID = "%s" batchCoordinatorAddress = "%s" batchFulfillmentEnabled = %v batchFulfillmentGasMultiplier = %s +customRevertsPipelineEnabled = %v minIncomingConfirmations = %d requestedConfsDelay = %d requestTimeout = "%s" @@ -419,6 +421,7 @@ observationSource = """ toml := fmt.Sprintf(template, jobID, name, coordinatorAddress, params.EVMChainID, batchCoordinatorAddress, params.BatchFulfillmentEnabled, strconv.FormatFloat(batchFulfillmentGasMultiplier, 'f', 2, 64), + params.CustomRevertsPipelineEnabled, confirmations, params.RequestedConfsDelay, requestTimeout.String(), publicKey, chunkSize, params.BackoffInitialDelay.String(), params.BackoffMaxDelay.String(), gasLanePrice.String(), pollPeriod.String(), observationSource) @@ -511,10 +514,7 @@ contractAddress = "%s" evmChainID = %s p2pPeerID = "12D3KooWPjceQrSwdWXPyLLeABRXmuqt69Rg3sBYbU1Nft9HyQ6X" externalJobID = "%s" -p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", -] -p2pv2Bootstrappers = [] +p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] isBootstrapPeer = false keyBundleID = "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5" monitoringEndpoint = "chain.link:4321" @@ -828,3 +828,34 @@ storeBlockhashesBatchSize = %d return BlockHeaderFeederSpec{BlockHeaderFeederSpecParams: params, toml: toml} } + +type StreamSpecParams struct { + Name string +} + +type StreamSpec struct { + StreamSpecParams + toml string +} + +// Toml returns the BlockhashStoreSpec in TOML string form. +func (b StreamSpec) Toml() string { + return b.toml +} + +func GenerateStreamSpec(params StreamSpecParams) StreamSpec { + template := ` +type = "stream" +schemaVersion = 1 +name = "%s" +observationSource = """ +ds [type=http method=GET url="https://chain.link/ETH-USD"]; +ds_parse [type=jsonparse path="data,price"]; +ds_multiply [type=multiply times=100]; +ds -> ds_parse -> ds_multiply; +""" +` + + toml := fmt.Sprintf(template, params.Name) + return StreamSpec{StreamSpecParams: params, toml: toml} +} diff --git a/core/utils/config/toml.go b/core/utils/config/toml.go deleted file mode 100644 index f51db76365e..00000000000 --- a/core/utils/config/toml.go +++ /dev/null @@ -1,22 +0,0 @@ -package config - -import ( - "errors" - "io" - - "github.com/pelletier/go-toml/v2" -) - -// DecodeTOML decodes toml from r in to v. -// Requires strict field matches and returns full toml.StrictMissingError details. -func DecodeTOML(r io.Reader, v any) error { - d := toml.NewDecoder(r).DisallowUnknownFields() - if err := d.Decode(v); err != nil { - var strict *toml.StrictMissingError - if errors.As(err, &strict) { - return errors.New(strict.String()) - } - return err - } - return nil -} diff --git a/core/utils/hash_helpers.go b/core/utils/hash_helpers.go deleted file mode 100644 index b0a284be716..00000000000 --- a/core/utils/hash_helpers.go +++ /dev/null @@ -1,24 +0,0 @@ -package utils - -import ( - "crypto/rand" - - "github.com/ethereum/go-ethereum/common" -) - -// NewHash return random Keccak256 -func NewHash() common.Hash { - b := make([]byte, 32) - _, err := rand.Read(b) - if err != nil { - panic(err) - } - return common.BytesToHash(b) -} - -// PadByteToHash returns a hash with zeros padded on the left of the given byte. -func PadByteToHash(b byte) common.Hash { - var h [32]byte - h[31] = b - return h -} diff --git a/core/utils/hash_helpers_test.go b/core/utils/hash_helpers_test.go deleted file mode 100644 index 8fc864dc407..00000000000 --- a/core/utils/hash_helpers_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package utils_test - -import ( - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" - - "github.com/smartcontractkit/chainlink/v2/core/utils" -) - -func TestNewHash(t *testing.T) { - t.Parallel() - - h1 := utils.NewHash() - h2 := utils.NewHash() - assert.NotEqual(t, h1, h2) - assert.NotEqual(t, h1, common.HexToHash("0x0")) - assert.NotEqual(t, h2, common.HexToHash("0x0")) -} - -func TestPadByteToHash(t *testing.T) { - t.Parallel() - - h := utils.PadByteToHash(1) - assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000001", h.String()) -} diff --git a/core/utils/http/http_test.go b/core/utils/http/http_test.go index db7a593a8cd..7ef2f1523ab 100644 --- a/core/utils/http/http_test.go +++ b/core/utils/http/http_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/utils/http" ) @@ -20,7 +21,7 @@ func TestUnrestrictedHTTPClient(t *testing.T) { assert.True(t, client.Transport.(*netHttp.Transport).DisableCompression) client.Transport = newMockTransport() - netReq, err := netHttp.NewRequest("GET", "http://localhost", bytes.NewReader([]byte{})) + netReq, err := netHttp.NewRequestWithContext(testutils.Context(t), "GET", "http://localhost", bytes.NewReader([]byte{})) assert.NoError(t, err) req := &http.HTTPRequest{ diff --git a/core/utils/mailbox.go b/core/utils/mailbox.go deleted file mode 100644 index 87fe1627f37..00000000000 --- a/core/utils/mailbox.go +++ /dev/null @@ -1,126 +0,0 @@ -package utils - -import ( - "sync" - "sync/atomic" -) - -// Mailbox contains a notify channel, -// a mutual exclusive lock, -// a queue of interfaces, -// and a queue capacity. -type Mailbox[T any] struct { - mu sync.Mutex - chNotify chan struct{} - queue []T - queueLen atomic.Int64 // atomic so monitor can read w/o blocking the queue - - // capacity - number of items the mailbox can buffer - // NOTE: if the capacity is 1, it's possible that an empty Retrieve may occur after a notification. - capacity uint64 - // onCloseFn is a hook used to stop monitoring, if non-nil - onCloseFn func() -} - -// NewHighCapacityMailbox create a new mailbox with a capacity -// that is better able to handle e.g. large log replays. -func NewHighCapacityMailbox[T any]() *Mailbox[T] { - return NewMailbox[T](100_000) -} - -// NewSingleMailbox returns a new Mailbox with capacity one. -func NewSingleMailbox[T any]() *Mailbox[T] { return NewMailbox[T](1) } - -// NewMailbox creates a new mailbox instance. If name is non-empty, it must be unique and calling Start will launch -// prometheus metric monitor that periodically reports mailbox load until Close() is called. -func NewMailbox[T any](capacity uint64) *Mailbox[T] { - queueCap := capacity - if queueCap == 0 { - queueCap = 100 - } - return &Mailbox[T]{ - chNotify: make(chan struct{}, 1), - queue: make([]T, 0, queueCap), - capacity: capacity, - } -} - -// Notify returns the contents of the notify channel -func (m *Mailbox[T]) Notify() <-chan struct{} { - return m.chNotify -} - -func (m *Mailbox[T]) Close() error { - if m.onCloseFn != nil { - m.onCloseFn() - } - return nil -} - -func (m *Mailbox[T]) onClose(fn func()) { m.onCloseFn = fn } - -func (m *Mailbox[T]) load() (capacity uint64, loadPercent float64) { - capacity = m.capacity - loadPercent = 100 * float64(m.queueLen.Load()) / float64(capacity) - return -} - -// Deliver appends to the queue and returns true if the queue was full, causing a message to be dropped. -func (m *Mailbox[T]) Deliver(x T) (wasOverCapacity bool) { - m.mu.Lock() - defer m.mu.Unlock() - - m.queue = append([]T{x}, m.queue...) - if uint64(len(m.queue)) > m.capacity && m.capacity > 0 { - m.queue = m.queue[:len(m.queue)-1] - wasOverCapacity = true - } else { - m.queueLen.Add(1) - } - - select { - case m.chNotify <- struct{}{}: - default: - } - return -} - -// Retrieve fetches one element from the queue. -func (m *Mailbox[T]) Retrieve() (t T, ok bool) { - m.mu.Lock() - defer m.mu.Unlock() - if len(m.queue) == 0 { - return - } - t = m.queue[len(m.queue)-1] - m.queue = m.queue[:len(m.queue)-1] - m.queueLen.Add(-1) - ok = true - return -} - -// RetrieveAll fetches all elements from the queue. -func (m *Mailbox[T]) RetrieveAll() []T { - m.mu.Lock() - defer m.mu.Unlock() - queue := m.queue - m.queue = nil - m.queueLen.Store(0) - for i, j := 0, len(queue)-1; i < j; i, j = i+1, j-1 { - queue[i], queue[j] = queue[j], queue[i] - } - return queue -} - -// RetrieveLatestAndClear fetch the latest value (or nil), and clears the rest of the queue (if any). -func (m *Mailbox[T]) RetrieveLatestAndClear() (t T) { - m.mu.Lock() - defer m.mu.Unlock() - if len(m.queue) == 0 { - return - } - t = m.queue[0] - m.queue = nil - m.queueLen.Store(0) - return -} diff --git a/core/utils/mailbox_prom.go b/core/utils/mailbox_prom.go deleted file mode 100644 index 33cbb2357b1..00000000000 --- a/core/utils/mailbox_prom.go +++ /dev/null @@ -1,93 +0,0 @@ -package utils - -import ( - "context" - "strconv" - "strings" - "sync" - "time" - - "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promauto" - - "github.com/smartcontractkit/chainlink-common/pkg/services" -) - -var mailboxLoad = promauto.NewGaugeVec(prometheus.GaugeOpts{ - Name: "mailbox_load_percent", - Help: "Percent of mailbox capacity used", -}, - []string{"appID", "name", "capacity"}, -) - -const mailboxPromInterval = 5 * time.Second - -type MailboxMonitor struct { - services.StateMachine - appID string - - mailboxes sync.Map - stop func() - done chan struct{} -} - -func NewMailboxMonitor(appID string) *MailboxMonitor { - return &MailboxMonitor{appID: appID} -} - -func (m *MailboxMonitor) Name() string { return "MailboxMonitor" } - -func (m *MailboxMonitor) Start(context.Context) error { - return m.StartOnce("MailboxMonitor", func() error { - t := time.NewTicker(WithJitter(mailboxPromInterval)) - ctx, cancel := context.WithCancel(context.Background()) - m.stop = func() { - t.Stop() - cancel() - } - m.done = make(chan struct{}) - go m.monitorLoop(ctx, t.C) - return nil - }) -} - -func (m *MailboxMonitor) Close() error { - return m.StopOnce("MailboxMonitor", func() error { - m.stop() - <-m.done - return nil - }) -} - -func (m *MailboxMonitor) HealthReport() map[string]error { - return map[string]error{m.Name(): m.Healthy()} -} - -func (m *MailboxMonitor) monitorLoop(ctx context.Context, c <-chan time.Time) { - defer close(m.done) - for { - select { - case <-ctx.Done(): - return - case <-c: - m.mailboxes.Range(func(k, v any) bool { - name, mb := k.(string), v.(mailbox) - c, p := mb.load() - capacity := strconv.FormatUint(c, 10) - mailboxLoad.WithLabelValues(m.appID, name, capacity).Set(p) - return true - }) - } - } -} - -type mailbox interface { - load() (capacity uint64, percent float64) - onClose(func()) -} - -func (m *MailboxMonitor) Monitor(mb mailbox, name ...string) { - n := strings.Join(name, ".") - m.mailboxes.Store(n, mb) - mb.onClose(func() { m.mailboxes.Delete(n) }) -} diff --git a/core/utils/mailbox_test.go b/core/utils/mailbox_test.go deleted file mode 100644 index c83d0035baa..00000000000 --- a/core/utils/mailbox_test.go +++ /dev/null @@ -1,181 +0,0 @@ -package utils - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestMailbox(t *testing.T) { - var ( - expected = []int{2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - toDeliver = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - ) - - const capacity = 10 - m := NewMailbox[int](capacity) - - // Queue deliveries - for i, d := range toDeliver { - atCapacity := m.Deliver(d) - if atCapacity && i < capacity { - t.Errorf("mailbox at capacity %d", i) - } else if !atCapacity && i >= capacity { - t.Errorf("mailbox below capacity %d", i) - } - } - - // Retrieve them - var recvd []int - chDone := make(chan struct{}) - go func() { - defer close(chDone) - for range m.Notify() { - for { - x, exists := m.Retrieve() - if !exists { - break - } - recvd = append(recvd, x) - } - } - }() - - close(m.chNotify) - <-chDone - - require.Equal(t, expected, recvd) -} - -func TestMailbox_RetrieveAll(t *testing.T) { - var ( - expected = []int{2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - toDeliver = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - ) - - const capacity = 10 - m := NewMailbox[int](capacity) - - // Queue deliveries - for i, d := range toDeliver { - atCapacity := m.Deliver(d) - if atCapacity && i < capacity { - t.Errorf("mailbox at capacity %d", i) - } else if !atCapacity && i >= capacity { - t.Errorf("mailbox below capacity %d", i) - } - } - - require.Equal(t, expected, m.RetrieveAll()) -} - -func TestMailbox_RetrieveLatestAndClear(t *testing.T) { - var ( - expected = 11 - toDeliver = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - ) - - const capacity = 10 - m := NewMailbox[int](capacity) - - // Queue deliveries - for i, d := range toDeliver { - atCapacity := m.Deliver(d) - if atCapacity && i < capacity { - t.Errorf("mailbox at capacity %d", i) - } else if !atCapacity && i >= capacity { - t.Errorf("mailbox below capacity %d", i) - } - } - - require.Equal(t, expected, m.RetrieveLatestAndClear()) - require.Len(t, m.RetrieveAll(), 0) -} - -func TestMailbox_NoEmptyReceivesWhenCapacityIsTwo(t *testing.T) { - m := NewMailbox[int](2) - - var ( - recvd []int - emptyReceives []int - ) - - chDone := make(chan struct{}) - go func() { - defer close(chDone) - for range m.Notify() { - x, exists := m.Retrieve() - if !exists { - emptyReceives = append(emptyReceives, recvd[len(recvd)-1]) - } else { - recvd = append(recvd, x) - } - } - }() - - for i := 0; i < 100000; i++ { - m.Deliver(i) - } - close(m.chNotify) - - <-chDone - require.Len(t, emptyReceives, 0) -} - -func TestMailbox_load(t *testing.T) { - for _, tt := range []struct { - name string - capacity uint64 - deliver []int - exp float64 - - retrieve int - exp2 float64 - - all bool - }{ - {"single-all", 1, []int{1}, 100, 0, 100, true}, - {"single-latest", 1, []int{1}, 100, 0, 100, false}, - {"ten-low", 10, []int{1}, 10, 1, 0.0, false}, - {"ten-full-all", 10, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 100, 5, 50, true}, - {"ten-full-latest", 10, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 100, 5, 50, false}, - {"ten-overflow", 10, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 100, 5, 50, false}, - {"nine", 9, []int{1, 2, 3}, 100.0 / 3.0, 2, 100.0 / 9.0, true}, - } { - t.Run(tt.name, func(t *testing.T) { - m := NewMailbox[int](tt.capacity) - - // Queue deliveries - for i, d := range tt.deliver { - atCapacity := m.Deliver(d) - if atCapacity && i < int(tt.capacity) { - t.Errorf("mailbox at capacity %d", i) - } else if !atCapacity && i >= int(tt.capacity) { - t.Errorf("mailbox below capacity %d", i) - } - } - gotCap, gotLoad := m.load() - require.Equal(t, gotCap, tt.capacity) - require.Equal(t, gotLoad, tt.exp) - - // Retrieve some - for i := 0; i < tt.retrieve; i++ { - _, ok := m.Retrieve() - require.True(t, ok) - } - gotCap, gotLoad = m.load() - require.Equal(t, gotCap, tt.capacity) - require.Equal(t, gotLoad, tt.exp2) - - // Drain it - if tt.all { - m.RetrieveAll() - } else { - m.RetrieveLatestAndClear() - } - gotCap, gotLoad = m.load() - require.Equal(t, gotCap, tt.capacity) - require.Equal(t, gotLoad, 0.0) - }) - } -} diff --git a/core/utils/mathutil/mathutil.go b/core/utils/mathutil/mathutil.go deleted file mode 100644 index e9659a1f151..00000000000 --- a/core/utils/mathutil/mathutil.go +++ /dev/null @@ -1,23 +0,0 @@ -package mathutil - -import "golang.org/x/exp/constraints" - -func Max[V constraints.Ordered](first V, vals ...V) V { - max := first - for _, v := range vals { - if v > max { - max = v - } - } - return max -} - -func Min[V constraints.Ordered](first V, vals ...V) V { - min := first - for _, v := range vals { - if v < min { - min = v - } - } - return min -} diff --git a/core/utils/mathutil/mathutil_test.go b/core/utils/mathutil/mathutil_test.go deleted file mode 100644 index 24a464bb398..00000000000 --- a/core/utils/mathutil/mathutil_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package mathutil - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestMax(t *testing.T) { - // Happy path - assert.Equal(t, 3, Max(3, 2, 1)) - // Single element - assert.Equal(t, 3, Max(3)) - // Signed - assert.Equal(t, -1, Max(-2, -1)) - // Uint64 - assert.Equal(t, uint64(2), Max(uint64(0), uint64(2))) - // String - assert.Equal(t, "c", Max("a", []string{"b", "c"}...)) -} - -func TestMin(t *testing.T) { - // Happy path - assert.Equal(t, 1, Min(3, 2, 1)) - // Single element - assert.Equal(t, 3, Min(3)) - // Signed - assert.Equal(t, -2, Min(-2, -1)) - // Uint64 - assert.Equal(t, uint64(0), Min(uint64(0), uint64(2))) - // String - assert.Equal(t, "a", Min("a", []string{"b", "c"}...)) -} diff --git a/core/utils/sleeper_task.go b/core/utils/sleeper_task.go deleted file mode 100644 index d84457e9325..00000000000 --- a/core/utils/sleeper_task.go +++ /dev/null @@ -1,129 +0,0 @@ -package utils - -import ( - "fmt" - "time" - - "github.com/smartcontractkit/chainlink-common/pkg/services" -) - -// SleeperTask represents a task that waits in the background to process some work. -type SleeperTask interface { - Stop() error - WakeUp() - WakeUpIfStarted() -} - -// Worker is a simple interface that represents some work to do repeatedly -type Worker interface { - Work() - Name() string -} - -type sleeperTask struct { - services.StateMachine - worker Worker - chQueue chan struct{} - chStop chan struct{} - chDone chan struct{} - chWorkDone chan struct{} -} - -// NewSleeperTask takes a worker and returns a SleeperTask. -// -// SleeperTask is guaranteed to call Work on the worker at least once for every -// WakeUp call. -// If the Worker is busy when WakeUp is called, the Worker will be called again -// immediately after it is finished. For this reason you should take care to -// make sure that Worker is idempotent. -// WakeUp does not block. -func NewSleeperTask(worker Worker) SleeperTask { - s := &sleeperTask{ - worker: worker, - chQueue: make(chan struct{}, 1), - chStop: make(chan struct{}), - chDone: make(chan struct{}), - chWorkDone: make(chan struct{}, 10), - } - - _ = s.StartOnce("SleeperTask-"+worker.Name(), func() error { - go s.workerLoop() - return nil - }) - - return s -} - -// Stop stops the SleeperTask -func (s *sleeperTask) Stop() error { - return s.StopOnce("SleeperTask-"+s.worker.Name(), func() error { - close(s.chStop) - select { - case <-s.chDone: - case <-time.After(15 * time.Second): - return fmt.Errorf("SleeperTask-%s took too long to stop", s.worker.Name()) - } - return nil - }) -} - -func (s *sleeperTask) WakeUpIfStarted() { - s.IfStarted(func() { - select { - case s.chQueue <- struct{}{}: - default: - } - }) -} - -// WakeUp wakes up the sleeper task, asking it to execute its Worker. -func (s *sleeperTask) WakeUp() { - if !s.IfStarted(func() { - select { - case s.chQueue <- struct{}{}: - default: - } - }) { - panic("cannot wake up stopped sleeper task") - } -} - -func (s *sleeperTask) workDone() { - select { - case s.chWorkDone <- struct{}{}: - default: - } -} - -// WorkDone isn't part of the SleeperTask interface, but can be -// useful in tests to assert that the work has been done. -func (s *sleeperTask) WorkDone() <-chan struct{} { - return s.chWorkDone -} - -func (s *sleeperTask) workerLoop() { - defer close(s.chDone) - - for { - select { - case <-s.chQueue: - s.worker.Work() - s.workDone() - case <-s.chStop: - return - } - } -} - -type sleeperTaskWorker struct { - name string - work func() -} - -// SleeperFuncTask returns a Worker to execute the given work function. -func SleeperFuncTask(work func(), name string) Worker { - return &sleeperTaskWorker{name: name, work: work} -} - -func (w *sleeperTaskWorker) Name() string { return w.name } -func (w *sleeperTaskWorker) Work() { w.work() } diff --git a/core/utils/sleeper_task_test.go b/core/utils/sleeper_task_test.go deleted file mode 100644 index 8c09350f523..00000000000 --- a/core/utils/sleeper_task_test.go +++ /dev/null @@ -1,118 +0,0 @@ -package utils_test - -import ( - "sync/atomic" - "testing" - "time" - - "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" -) - -type countingWorker struct { - numJobsPerformed atomic.Int32 - delay time.Duration -} - -func (t *countingWorker) Name() string { - return "CountingWorker" -} - -func (t *countingWorker) Work() { - if t.delay != 0 { - time.Sleep(t.delay) - } - // Without an atomic, the race detector fails - t.numJobsPerformed.Add(1) -} - -func (t *countingWorker) getNumJobsPerformed() int { - return int(t.numJobsPerformed.Load()) -} - -func TestSleeperTask_WakeupAfterStopPanics(t *testing.T) { - t.Parallel() - - worker := &countingWorker{} - sleeper := utils.NewSleeperTask(worker) - - require.NoError(t, sleeper.Stop()) - - require.Panics(t, func() { - sleeper.WakeUp() - }) - gomega.NewWithT(t).Eventually(worker.getNumJobsPerformed).Should(gomega.Equal(0)) -} - -func TestSleeperTask_CallingStopTwiceFails(t *testing.T) { - t.Parallel() - - worker := &countingWorker{} - sleeper := utils.NewSleeperTask(worker) - require.NoError(t, sleeper.Stop()) - require.Error(t, sleeper.Stop()) -} - -func TestSleeperTask_WakeupPerformsWork(t *testing.T) { - t.Parallel() - - worker := &countingWorker{} - sleeper := utils.NewSleeperTask(worker) - - sleeper.WakeUp() - gomega.NewWithT(t).Eventually(worker.getNumJobsPerformed).Should(gomega.Equal(1)) - require.NoError(t, sleeper.Stop()) -} - -type controllableWorker struct { - countingWorker - awaitWorkStarted chan struct{} - allowResumeWork chan struct{} - ignoreSignals bool -} - -func (w *controllableWorker) Work() { - if !w.ignoreSignals { - w.awaitWorkStarted <- struct{}{} - <-w.allowResumeWork - } - w.countingWorker.Work() -} - -func TestSleeperTask_WakeupEnqueuesMaxTwice(t *testing.T) { - t.Parallel() - - worker := &controllableWorker{awaitWorkStarted: make(chan struct{}), allowResumeWork: make(chan struct{})} - sleeper := utils.NewSleeperTask(worker) - - sleeper.WakeUp() - <-worker.awaitWorkStarted - sleeper.WakeUp() - sleeper.WakeUp() - sleeper.WakeUp() - sleeper.WakeUp() - sleeper.WakeUp() - worker.ignoreSignals = true - worker.allowResumeWork <- struct{}{} - - gomega.NewWithT(t).Eventually(worker.getNumJobsPerformed).Should(gomega.Equal(2)) - gomega.NewWithT(t).Consistently(worker.getNumJobsPerformed).Should(gomega.BeNumerically("<", 3)) - require.NoError(t, sleeper.Stop()) -} - -func TestSleeperTask_StopWaitsUntilWorkFinishes(t *testing.T) { - t.Parallel() - - worker := &controllableWorker{awaitWorkStarted: make(chan struct{}), allowResumeWork: make(chan struct{})} - sleeper := utils.NewSleeperTask(worker) - - sleeper.WakeUp() - <-worker.awaitWorkStarted - require.Equal(t, 0, worker.getNumJobsPerformed()) - worker.allowResumeWork <- struct{}{} - - require.NoError(t, sleeper.Stop()) - require.Equal(t, worker.getNumJobsPerformed(), 1) -} diff --git a/core/utils/utils.go b/core/utils/utils.go index 0df280775b5..78151517c62 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -2,7 +2,9 @@ package utils import ( + "bytes" "context" + "crypto/ed25519" "crypto/rand" "encoding/base64" "encoding/hex" @@ -10,7 +12,6 @@ import ( "errors" "fmt" "math" - "math/big" mrand "math/rand" "sort" "strings" @@ -18,79 +19,33 @@ import ( "sync/atomic" "time" - cryptop2p "github.com/libp2p/go-libp2p-core/crypto" - "golang.org/x/exp/constraints" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/google/uuid" "github.com/jpillora/backoff" - "github.com/libp2p/go-libp2p-core/peer" pkgerrors "github.com/pkg/errors" "github.com/robfig/cron/v3" "golang.org/x/crypto/bcrypt" "golang.org/x/crypto/sha3" - "github.com/smartcontractkit/chainlink-common/pkg/services" -) + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" -const ( - // DefaultSecretSize is the entropy in bytes to generate a base64 string of 64 characters. - DefaultSecretSize = 48 - // EVMWordByteLen the length of an EVM Word Byte - EVMWordByteLen = 32 + "github.com/smartcontractkit/chainlink-common/pkg/services" ) -// ZeroAddress is an address of all zeroes, otherwise in Ethereum as -// 0x0000000000000000000000000000000000000000 -var ZeroAddress = common.Address{} - -func RandomAddress() common.Address { - b := make([]byte, 20) - _, _ = rand.Read(b) // Assignment for errcheck. Only used in tests so we can ignore. - return common.BytesToAddress(b) -} - -func RandomBytes32() (r [32]byte) { - b := make([]byte, 32) - _, _ = rand.Read(b[:]) // Assignment for errcheck. Only used in tests so we can ignore. - copy(r[:], b) - return -} - -func Bytes32ToSlice(a [32]byte) (r []byte) { - r = append(r, a[:]...) - return -} +// DefaultSecretSize is the entropy in bytes to generate a base64 string of 64 characters. +const DefaultSecretSize = 48 func MustNewPeerID() string { - _, pubKey, err := cryptop2p.GenerateEd25519Key(rand.Reader) + pubKey, _, err := ed25519.GenerateKey(rand.Reader) if err != nil { panic(err) } - peerID, err := peer.IDFromPublicKey(pubKey) + peerID, err := ragep2ptypes.PeerIDFromPublicKey(pubKey) if err != nil { panic(err) } return peerID.String() } -// EmptyHash is a hash of all zeroes, otherwise in Ethereum as -// 0x0000000000000000000000000000000000000000000000000000000000000000 -var EmptyHash = common.Hash{} - -// Uint256ToBytes is x represented as the bytes of a uint256 -func Uint256ToBytes(x *big.Int) (uint256 []byte, err error) { - if x.Cmp(MaxUint256) > 0 { - return nil, fmt.Errorf("too large to convert to uint256") - } - uint256 = common.LeftPadBytes(x.Bytes(), EVMWordByteLen) - if x.Cmp(big.NewInt(0).SetBytes(uint256)) != 0 { - panic("failed to round-trip uint256 back to source big.Int") - } - return uint256, err -} - // ISO8601UTC formats given time to ISO8601. func ISO8601UTC(t time.Time) string { return t.UTC().Format(time.RFC3339) @@ -126,29 +81,6 @@ func NewSecret(n int) string { return base64.StdEncoding.EncodeToString(b) } -// RemoveHexPrefix removes the prefix (0x) of a given hex string. -func RemoveHexPrefix(str string) string { - if HasHexPrefix(str) { - return str[2:] - } - return str -} - -// HasHexPrefix returns true if the string starts with 0x. -func HasHexPrefix(str string) bool { - return len(str) >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X') -} - -// IsEmptyAddress checks that the address is empty, synonymous with the zero -// account/address. No logs can come from this address, as there is no contract -// present there. -// -// See https://stackoverflow.com/questions/48219716/what-is-address0-in-solidity -// for the more info on the zero address. -func IsEmptyAddress(addr common.Address) bool { - return addr == ZeroAddress -} - // StringToHex converts a standard string to a hex encoded string. func StringToHex(in string) string { return AddHexPrefix(hex.EncodeToString([]byte(in))) @@ -172,82 +104,6 @@ func IsEmpty(bytes []byte) bool { return true } -// Sleeper interface is used for tasks that need to be done on some -// interval, excluding Cron, like reconnecting. -type Sleeper interface { - Reset() - Sleep() - After() time.Duration - Duration() time.Duration -} - -// BackoffSleeper is a sleeper that backs off on subsequent attempts. -type BackoffSleeper struct { - backoff.Backoff - beenRun atomic.Bool -} - -// NewBackoffSleeper returns a BackoffSleeper that is configured to -// sleep for 0 seconds initially, then backs off from 1 second minimum -// to 10 seconds maximum. -func NewBackoffSleeper() *BackoffSleeper { - return &BackoffSleeper{ - Backoff: backoff.Backoff{ - Min: 1 * time.Second, - Max: 10 * time.Second, - }, - } -} - -// Sleep waits for the given duration, incrementing the back off. -func (bs *BackoffSleeper) Sleep() { - if bs.beenRun.CompareAndSwap(false, true) { - return - } - time.Sleep(bs.Backoff.Duration()) -} - -// After returns the duration for the next stop, and increments the backoff. -func (bs *BackoffSleeper) After() time.Duration { - if bs.beenRun.CompareAndSwap(false, true) { - return 0 - } - return bs.Backoff.Duration() -} - -// Duration returns the current duration value. -func (bs *BackoffSleeper) Duration() time.Duration { - if !bs.beenRun.Load() { - return 0 - } - return bs.ForAttempt(bs.Attempt()) -} - -// Reset resets the backoff intervals. -func (bs *BackoffSleeper) Reset() { - bs.beenRun.Store(false) - bs.Backoff.Reset() -} - -// RetryWithBackoff retries the sleeper and backs off if not Done -func RetryWithBackoff(ctx context.Context, fn func() (retry bool)) { - sleeper := NewBackoffSleeper() - sleeper.Reset() - for { - retry := fn() - if !retry { - return - } - - select { - case <-ctx.Done(): - return - case <-time.After(sleeper.After()): - continue - } - } -} - // UnmarshalToMap takes an input json string and returns a map[string]interface i.e. a raw object func UnmarshalToMap(input string) (map[string]interface{}, error) { var output map[string]interface{} @@ -276,24 +132,6 @@ func CheckPasswordHash(password, hash string) bool { return err == nil } -// Keccak256 is a simplified interface for the legacy SHA3 implementation that -// Ethereum uses. -func Keccak256(in []byte) ([]byte, error) { - hash := sha3.NewLegacyKeccak256() - _, err := hash.Write(in) - return hash.Sum(nil), err -} - -func Keccak256Fixed(in []byte) [32]byte { - hash := sha3.NewLegacyKeccak256() - // Note this Keccak256 cannot error https://github.com/golang/crypto/blob/master/sha3/sha3.go#L126 - // if we start supporting hashing algos which do, we can change this API to include an error. - hash.Write(in) - var h [32]byte - copy(h[:], hash.Sum(nil)) - return h -} - // Sha256 returns a hexadecimal encoded string of a hashed input func Sha256(in string) (string, error) { hasher := sha3.New256() @@ -304,99 +142,6 @@ func Sha256(in string) (string, error) { return hex.EncodeToString(hasher.Sum(nil)), nil } -// EIP55CapitalizedAddress returns true iff possibleAddressString has the correct -// capitalization for an Ethereum address, per EIP 55 -func EIP55CapitalizedAddress(possibleAddressString string) bool { - if !HasHexPrefix(possibleAddressString) { - possibleAddressString = "0x" + possibleAddressString - } - EIP55Capitalized := common.HexToAddress(possibleAddressString).Hex() - return possibleAddressString == EIP55Capitalized -} - -// ParseEthereumAddress returns addressString as a go-ethereum Address, or an -// error if it's invalid, e.g. if EIP 55 capitalization check fails -func ParseEthereumAddress(addressString string) (common.Address, error) { - if !common.IsHexAddress(addressString) { - return common.Address{}, fmt.Errorf( - "not a valid Ethereum address: %s", addressString) - } - address := common.HexToAddress(addressString) - if !EIP55CapitalizedAddress(addressString) { - return common.Address{}, fmt.Errorf( - "%s treated as Ethereum address, but it has an invalid capitalization! "+ - "The correctly-capitalized address would be %s, but "+ - "check carefully before copying and pasting! ", - addressString, address.Hex()) - } - return address, nil -} - -// MustHash returns the keccak256 hash, or panics on failure. -func MustHash(in string) common.Hash { - out, err := Keccak256([]byte(in)) - if err != nil { - panic(err) - } - return common.BytesToHash(out) -} - -// JustError takes a tuple and returns the last entry, the error. -func JustError(_ interface{}, err error) error { - return err -} - -var zero = big.NewInt(0) - -// CheckUint256 returns an error if n is out of bounds for a uint256 -func CheckUint256(n *big.Int) error { - if n.Cmp(zero) < 0 || n.Cmp(MaxUint256) >= 0 { - return fmt.Errorf("number out of range for uint256") - } - return nil -} - -// HexToUint256 returns the uint256 represented by s, or an error if it doesn't -// represent one. -func HexToUint256(s string) (*big.Int, error) { - rawNum, err := hexutil.Decode(s) - if err != nil { - return nil, pkgerrors.Wrapf(err, "while parsing %s as hex: ", s) - } - rv := big.NewInt(0).SetBytes(rawNum) // can't be negative number - if err := CheckUint256(rv); err != nil { - return nil, err - } - return rv, nil -} - -// HexToBig parses the given hex string or panics if it is invalid. -func HexToBig(s string) *big.Int { - n, ok := new(big.Int).SetString(s, 16) - if !ok { - panic(fmt.Errorf(`failed to convert "%s" as hex to big.Int`, s)) - } - return n -} - -// Uint256ToBytes32 returns the bytes32 encoding of the big int provided -func Uint256ToBytes32(n *big.Int) []byte { - if n.BitLen() > 256 { - panic("vrf.uint256ToBytes32: too big to marshal to uint256") - } - return common.LeftPadBytes(n.Bytes(), 32) -} - -// WaitGroupChan creates a channel that closes when the provided sync.WaitGroup is done. -func WaitGroupChan(wg *sync.WaitGroup) <-chan struct{} { - chAwait := make(chan struct{}) - go func() { - defer close(chAwait) - wg.Wait() - }() - return chAwait -} - // WithCloseChan wraps a context so that it is canceled if the passed in channel is closed. // Deprecated: Call [services.StopChan.Ctx] directly func WithCloseChan(parentCtx context.Context, chStop chan struct{}) (context.Context, context.CancelFunc) { @@ -421,40 +166,6 @@ type StopChan = services.StopChan // Deprecated: use services.StopRChan type StopRChan = services.StopRChan -// DependentAwaiter contains Dependent funcs -type DependentAwaiter interface { - AwaitDependents() <-chan struct{} - AddDependents(n int) - DependentReady() -} - -type dependentAwaiter struct { - wg *sync.WaitGroup - ch <-chan struct{} -} - -// NewDependentAwaiter creates a new DependentAwaiter -func NewDependentAwaiter() DependentAwaiter { - return &dependentAwaiter{ - wg: &sync.WaitGroup{}, - } -} - -func (da *dependentAwaiter) AwaitDependents() <-chan struct{} { - if da.ch == nil { - da.ch = WaitGroupChan(da.wg) - } - return da.ch -} - -func (da *dependentAwaiter) AddDependents(n int) { - da.wg.Add(n) -} - -func (da *dependentAwaiter) DependentReady() { - da.wg.Done() -} - // BoundedQueue is a FIFO queue that discards older items when it reaches its capacity. type BoundedQueue[T any] struct { capacity int @@ -575,20 +286,6 @@ func (q *BoundedPriorityQueue[T]) Empty() bool { return true } -// WrapIfError decorates an error with the given message. It is intended to -// be used with `defer` statements, like so: -// -// func SomeFunction() (err error) { -// defer WrapIfError(&err, "error in SomeFunction:") -// -// ... -// } -func WrapIfError(err *error, msg string) { - if *err != nil { - *err = pkgerrors.Wrap(*err, msg) - } -} - // TickerBase is an interface for pausable tickers. type TickerBase interface { Resume() @@ -751,16 +448,6 @@ func (t *ResettableTimer) Reset(duration time.Duration) { t.timer = time.NewTimer(duration) } -// EVMBytesToUint64 converts -// a bytebuffer to uint64 -func EVMBytesToUint64(buf []byte) uint64 { - var result uint64 - for _, b := range buf { - result = result<<8 + uint64(b) - } - return result -} - var ( ErrAlreadyStopped = errors.New("already stopped") ErrCannotStopUnstarted = errors.New("cannot stop unstarted service") @@ -837,23 +524,9 @@ func BoxOutput(errorMsgTemplate string, errorMsgValues ...interface{}) string { "\n\n" } -// AllEqual returns true iff all the provided elements are equal to each other. -func AllEqual[T comparable](elems ...T) bool { - for i := 1; i < len(elems); i++ { - if elems[i] != elems[0] { - return false - } - } - return true -} - -// RandUint256 generates a random bigNum up to 2 ** 256 - 1 -func RandUint256() *big.Int { - n, err := rand.Int(rand.Reader, MaxUint256) - if err != nil { - panic(err) - } - return n +// ConcatBytes appends a bunch of byte arrays into a single byte array +func ConcatBytes(bufs ...[]byte) []byte { + return bytes.Join(bufs, []byte{}) } func LeftPadBitString(input string, length int) string { @@ -863,42 +536,6 @@ func LeftPadBitString(input string, length int) string { return strings.Repeat("0", length-len(input)) + input } -// TryParseHex parses the given hex string to bytes, -// it can return error if the hex string is invalid. -// Follows the semantic of ethereum's FromHex. -func TryParseHex(s string) (b []byte, err error) { - if !HasHexPrefix(s) { - err = errors.New("hex string must have 0x prefix") - } else { - s = s[2:] - if len(s)%2 == 1 { - s = "0" + s - } - b, err = hex.DecodeString(s) - } - return -} - -// MinKey returns the minimum value of the given element array with respect -// to the given key function. In the event U is not a compound type (e.g a -// struct) an identity function can be provided. -func MinKey[U any, T constraints.Ordered](elems []U, key func(U) T) T { - var min T - if len(elems) == 0 { - return min - } - - min = key(elems[0]) - for i := 1; i < len(elems); i++ { - v := key(elems[i]) - if v < min { - min = v - } - } - - return min -} - // ErrorBuffer uses joinedErrors interface to join multiple errors into a single error. // This is useful to track the most recent N errors in a service and flush them as a single error. type ErrorBuffer struct { diff --git a/core/utils/utils_test.go b/core/utils/utils_test.go index e11c01a8e4f..c08983ff4b8 100644 --- a/core/utils/utils_test.go +++ b/core/utils/utils_test.go @@ -4,9 +4,6 @@ import ( "context" "encoding/hex" "fmt" - "math/big" - "strings" - "sync" "sync/atomic" "testing" "time" @@ -17,11 +14,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.uber.org/multierr" ) func TestUtils_NewBytes32ID(t *testing.T) { @@ -52,30 +46,6 @@ func TestUtils_NewSecret(t *testing.T) { } } -func TestUtils_IsEmptyAddress(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - addr common.Address - want bool - }{ - {"zero address", common.Address{}, true}, - {"non-zero address", testutils.NewAddress(), false}, - } - - for _, test := range tests { - test := test - - t.Run(test.name, func(t *testing.T) { - t.Parallel() - - actual := utils.IsEmptyAddress(test.addr) - assert.Equal(t, test.want, actual) - }) - } -} - func TestUtils_StringToHex(t *testing.T) { t.Parallel() @@ -99,26 +69,6 @@ func TestUtils_StringToHex(t *testing.T) { } } -func TestUtils_BackoffSleeper(t *testing.T) { - t.Parallel() - - bs := utils.NewBackoffSleeper() - assert.Equal(t, time.Duration(0), bs.Duration(), "should initially return immediately") - bs.Sleep() - - d := 1 * time.Nanosecond - bs.Min = d - bs.Factor = 2 - assert.Equal(t, d, bs.Duration()) - bs.Sleep() - - d2 := 2 * time.Nanosecond - assert.Equal(t, d2, bs.Duration()) - - bs.Reset() - assert.Equal(t, time.Duration(0), bs.Duration(), "should initially return immediately") -} - func TestUtils_DurationFromNow(t *testing.T) { t.Parallel() @@ -127,138 +77,6 @@ func TestUtils_DurationFromNow(t *testing.T) { assert.True(t, 0 < duration) } -func TestKeccak256(t *testing.T) { - t.Parallel() - - tests := []struct { - name string - input string - want string - }{ - {"basic", "0xf00b", "0x2433bb36d5f9b14e4fea87c2d32d79abfe34e56808b891e471f4400fca2a336c"}, - {"long input", "0xf00b2433bb36d5f9b14e4fea87c2d32d79abfe34e56808b891e471f4400fca2a336c", "0x6b917c56ad7bea7d09132b9e1e29bb5d9aa7d32d067c638dfa886bbbf6874cdf"}, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - input, err := hexutil.Decode(test.input) - assert.NoError(t, err) - result, err := utils.Keccak256(input) - assert.NoError(t, err) - - assert.Equal(t, test.want, hexutil.Encode(result)) - }) - } -} - -// From https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md#test-cases -var testAddresses = []string{ - "0x52908400098527886E0F7030069857D2E4169EE7", - "0x8617E340B3D01FA5F11F306F4090FD50E238070D", - "0xde709f2102306220921060314715629080e2fb77", - "0x27b1fdb04752bbc536007a920d24acb045561c26", - "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", - "0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359", - "0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB", - "0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb", -} - -func TestClient_EIP55CapitalizedAddress(t *testing.T) { - t.Parallel() - - valid := utils.EIP55CapitalizedAddress - for _, address := range testAddresses { - assert.True(t, valid(address)) - assert.False(t, valid(strings.ToLower(address)) && - valid(strings.ToUpper(address))) - } -} - -func TestClient_ParseEthereumAddress(t *testing.T) { - t.Parallel() - - parse := utils.ParseEthereumAddress - for _, address := range testAddresses { - a1, err := parse(address) - assert.NoError(t, err) - no0xPrefix := address[2:] - a2, err := parse(no0xPrefix) - assert.NoError(t, err) - assert.True(t, a1 == a2) - _, lowerErr := parse(strings.ToLower(address)) - _, upperErr := parse(strings.ToUpper(address)) - shouldBeError := multierr.Combine(lowerErr, upperErr) - assert.Error(t, shouldBeError) - assert.True(t, strings.Contains(shouldBeError.Error(), no0xPrefix)) - } - _, notHexErr := parse("0xCeci n'est pas une chaîne hexadécimale") - assert.Error(t, notHexErr) - _, tooLongErr := parse("0x0123456789abcdef0123456789abcdef0123456789abcdef") - assert.Error(t, tooLongErr) -} - -func TestWaitGroupChan(t *testing.T) { - t.Parallel() - - wg := &sync.WaitGroup{} - wg.Add(2) - - ch := utils.WaitGroupChan(wg) - - select { - case <-ch: - t.Fatal("should not fire immediately") - default: - } - - wg.Done() - - select { - case <-ch: - t.Fatal("should not fire until finished") - default: - } - - go func() { - time.Sleep(2 * time.Second) - wg.Done() - }() - - cltest.CallbackOrTimeout(t, "WaitGroupChan fires", func() { - <-ch - }, 5*time.Second) -} - -func TestDependentAwaiter(t *testing.T) { - t.Parallel() - - da := utils.NewDependentAwaiter() - da.AddDependents(2) - - select { - case <-da.AwaitDependents(): - t.Fatal("should not fire immediately") - default: - } - - da.DependentReady() - - select { - case <-da.AwaitDependents(): - t.Fatal("should not fire until finished") - default: - } - - go func() { - time.Sleep(2 * time.Second) - da.DependentReady() - }() - - cltest.CallbackOrTimeout(t, "dependents are now ready", func() { - <-da.AwaitDependents() - }, 5*time.Second) -} - func TestBoundedQueue(t *testing.T) { t.Parallel() @@ -351,17 +169,6 @@ func TestBoundedPriorityQueue(t *testing.T) { require.Zero(t, q.Take()) } -func TestEVMBytesToUint64(t *testing.T) { - t.Parallel() - - require.Equal(t, uint64(257), utils.EVMBytesToUint64([]byte{0x01, 0x01})) - require.Equal(t, uint64(257), utils.EVMBytesToUint64([]byte{0x00, 0x00, 0x01, 0x01})) - require.Equal(t, uint64(299140445700113), utils.EVMBytesToUint64([]byte{0x00, 0x01, 0x10, 0x11, 0x10, 0x01, 0x00, 0x11})) - - // overflows without erroring - require.Equal(t, uint64(17), utils.EVMBytesToUint64([]byte{0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11})) -} - func Test_WithJitter(t *testing.T) { t.Parallel() @@ -374,14 +181,6 @@ func Test_WithJitter(t *testing.T) { } } -func TestAllEqual(t *testing.T) { - t.Parallel() - - require.False(t, utils.AllEqual(1, 2, 3, 4, 5)) - require.True(t, utils.AllEqual(1, 1, 1, 1, 1)) - require.False(t, utils.AllEqual(1, 1, 1, 2, 1, 1, 1)) -} - func TestIsEmpty(t *testing.T) { t.Parallel() @@ -424,26 +223,6 @@ func TestBoxOutput(t *testing.T) { assert.Equal(t, expected, output) } -func TestUint256ToBytes(t *testing.T) { - t.Parallel() - - v := big.NewInt(0).Sub(utils.MaxUint256, big.NewInt(1)) - uint256, err := utils.Uint256ToBytes(v) - assert.NoError(t, err) - - b32 := utils.Uint256ToBytes32(v) - assert.Equal(t, uint256, b32) - - large := big.NewInt(0).Add(utils.MaxUint256, big.NewInt(1)) - _, err = utils.Uint256ToBytes(large) - assert.Error(t, err, "too large to convert to uint256") - - negative := big.NewInt(-1) - assert.Panics(t, func() { - _, _ = utils.Uint256ToBytes(negative) - }, "failed to round-trip uint256 back to source big.Int") -} - func TestISO8601UTC(t *testing.T) { t.Parallel() @@ -461,32 +240,6 @@ func TestFormatJSON(t *testing.T) { assert.Equal(t, "\"{\\\"foo\\\":123}\"", string(formatted)) } -func TestRetryWithBackoff(t *testing.T) { - t.Parallel() - - var counter atomic.Int32 - ctx, cancel := context.WithCancel(testutils.Context(t)) - - utils.RetryWithBackoff(ctx, func() bool { - return false - }) - - retry := func() bool { - return counter.Add(1) < 3 - } - - go utils.RetryWithBackoff(ctx, retry) - - assert.Eventually(t, func() bool { - return counter.Load() == 3 - }, testutils.WaitTimeout(t), testutils.TestInterval) - - cancel() - - utils.RetryWithBackoff(ctx, retry) - assert.Equal(t, int32(4), counter.Load()) -} - func TestMustUnmarshalToMap(t *testing.T) { t.Parallel() @@ -516,42 +269,6 @@ func TestSha256(t *testing.T) { assert.Len(t, hash, 32) } -func TestCheckUint256(t *testing.T) { - t.Parallel() - - large := big.NewInt(0).Add(utils.MaxUint256, big.NewInt(1)) - err := utils.CheckUint256(large) - assert.Error(t, err, "number out of range for uint256") - - negative := big.NewInt(-123) - err = utils.CheckUint256(negative) - assert.Error(t, err, "number out of range for uint256") - - err = utils.CheckUint256(big.NewInt(123)) - assert.NoError(t, err) -} - -func TestRandUint256(t *testing.T) { - t.Parallel() - - for i := 0; i < 1000; i++ { - uint256 := utils.RandUint256() - assert.NoError(t, utils.CheckUint256(uint256)) - } -} - -func TestHexToUint256(t *testing.T) { - t.Parallel() - - b, err := utils.HexToUint256("0x00") - assert.NoError(t, err) - assert.Zero(t, b.Cmp(big.NewInt(0))) - - b, err = utils.HexToUint256("0xFFFFFFFF") - assert.NoError(t, err) - assert.Zero(t, b.Cmp(big.NewInt(4294967295))) -} - func TestWithCloseChan(t *testing.T) { t.Parallel() @@ -772,40 +489,6 @@ func TestCronTicker(t *testing.T) { assert.Equal(t, c, counter.Load()) } -func TestTryParseHex(t *testing.T) { - t.Parallel() - - t.Run("0x prefix missing", func(t *testing.T) { - t.Parallel() - - _, err := utils.TryParseHex("abcd") - assert.Error(t, err) - }) - - t.Run("wrong hex characters", func(t *testing.T) { - t.Parallel() - - _, err := utils.TryParseHex("0xabcdzzz") - assert.Error(t, err) - }) - - t.Run("valid hex string", func(t *testing.T) { - t.Parallel() - - b, err := utils.TryParseHex("0x1234") - assert.NoError(t, err) - assert.Equal(t, []byte{0x12, 0x34}, b) - }) - - t.Run("prepend odd length with zero", func(t *testing.T) { - t.Parallel() - - b, err := utils.TryParseHex("0x123") - assert.NoError(t, err) - assert.Equal(t, []byte{0x1, 0x23}, b) - }) -} - func TestErrorBuffer(t *testing.T) { t.Parallel() diff --git a/core/web/assets/9f6d832ef97e8493764e.svg.gz b/core/web/assets/9f6d832ef97e8493764e.svg.gz index 44cd870b0bb..94a2aadef9f 100644 Binary files a/core/web/assets/9f6d832ef97e8493764e.svg.gz and b/core/web/assets/9f6d832ef97e8493764e.svg.gz differ diff --git a/core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz b/core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz index 7e4f235f1b9..36ce61e5116 100644 Binary files a/core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz and b/core/web/assets/ba8bbf16ebf8e1d05bef.svg.gz differ diff --git a/core/web/assets/index.html b/core/web/assets/index.html index 601453b4eac..77331861516 100644 --- a/core/web/assets/index.html +++ b/core/web/assets/index.html @@ -1 +1 @@ -Operator UIChainlink
\ No newline at end of file +Operator UIChainlink
\ No newline at end of file diff --git a/core/web/assets/index.html.gz b/core/web/assets/index.html.gz index 24cc3068f6e..afbd1b1a38b 100644 Binary files a/core/web/assets/index.html.gz and b/core/web/assets/index.html.gz differ diff --git a/core/web/assets/main.b0b6f79f7f4a94560e37.js b/core/web/assets/main.74b124ef5d2ef3614139.js similarity index 90% rename from core/web/assets/main.b0b6f79f7f4a94560e37.js rename to core/web/assets/main.74b124ef5d2ef3614139.js index 6c9f23d1cca..74cfe38a5bb 100644 --- a/core/web/assets/main.b0b6f79f7f4a94560e37.js +++ b/core/web/assets/main.74b124ef5d2ef3614139.js @@ -17,7 +17,7 @@ PERFORMANCE OF THIS SOFTWARE. * * Copyright (c) 2014-2017, Jon Schlinkert. * Released under the MIT License. - */ var r=n(47798);function i(e){return!0===r(e)&&"[object Object]"===Object.prototype.toString.call(e)}e.exports=function(e){var t,n;return!1!==i(e)&&"function"==typeof(t=e.constructor)&&!1!==i(n=t.prototype)&&!1!==n.hasOwnProperty("isPrototypeOf")}},72366(e,t,n){"use strict";var r=n(20862),i=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.MuiThemeProviderOld=void 0;var a=i(n(67154)),o=i(n(59713)),s=i(n(34575)),u=i(n(93913)),c=i(n(78585)),l=i(n(29754)),f=i(n(2205)),d=i(n(67294)),h=i(n(45697));i(n(42473));var p=i(n(43890)),b=n(55252),m=r(n(51067)),g=function(e){function t(e,n){var r;return(0,s.default)(this,t),(r=(0,c.default)(this,(0,l.default)(t).call(this))).broadcast=(0,p.default)(),r.outerTheme=m.default.initial(n),r.broadcast.setState(r.mergeOuterLocalTheme(e.theme)),r}return(0,f.default)(t,e),(0,u.default)(t,[{key:"getChildContext",value:function(){var e,t=this.props,n=t.disableStylesGeneration,r=t.sheetsCache,i=t.sheetsManager,a=this.context.muiThemeProviderOptions||{};return void 0!==n&&(a.disableStylesGeneration=n),void 0!==r&&(a.sheetsCache=r),void 0!==i&&(a.sheetsManager=i),e={},(0,o.default)(e,m.CHANNEL,this.broadcast),(0,o.default)(e,"muiThemeProviderOptions",a),e}},{key:"componentDidMount",value:function(){var e=this;this.unsubscribeId=m.default.subscribe(this.context,function(t){e.outerTheme=t,e.broadcast.setState(e.mergeOuterLocalTheme(e.props.theme))})}},{key:"componentDidUpdate",value:function(e){this.props.theme!==e.theme&&this.broadcast.setState(this.mergeOuterLocalTheme(this.props.theme))}},{key:"componentWillUnmount",value:function(){null!==this.unsubscribeId&&m.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"mergeOuterLocalTheme",value:function(e){return"function"==typeof e?e(this.outerTheme):this.outerTheme?(0,a.default)({},this.outerTheme,e):e}},{key:"render",value:function(){return this.props.children}}]),t}(d.default.Component);t.MuiThemeProviderOld=g,g.childContextTypes=(0,a.default)({},m.default.contextTypes,{muiThemeProviderOptions:h.default.object}),g.contextTypes=(0,a.default)({},m.default.contextTypes,{muiThemeProviderOptions:h.default.object}),b.ponyfillGlobal.__MUI_STYLES__||(b.ponyfillGlobal.__MUI_STYLES__={}),b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider||(b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider=g);var v=b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider;t.default=v},59114(e,t,n){"use strict";var r=n(95318);function i(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return en?n:e}function a(e){e=e.substr(1);var t=RegExp(".{1,".concat(e.length/3,"}"),"g"),n=e.match(t);return n&&1===n[0].length&&(n=n.map(function(e){return e+e})),n?"rgb(".concat(n.map(function(e){return parseInt(e,16)}).join(", "),")"):""}function o(e){if(0===e.indexOf("#"))return e;function t(e){var t=e.toString(16);return 1===t.length?"0".concat(t):t}var n=s(e).values;return n=n.map(function(e){return t(e)}),"#".concat(n.join(""))}function s(e){if("#"===e.charAt(0))return s(a(e));var t=e.indexOf("("),n=e.substring(0,t),r=e.substring(t+1,e.length-1).split(",");return r=r.map(function(e){return parseFloat(e)}),{type:n,values:r}}function u(e){var t=e.type,n=e.values;return -1!==t.indexOf("rgb")&&(n=n.map(function(e,t){return t<3?parseInt(e,10):e})),-1!==t.indexOf("hsl")&&(n[1]="".concat(n[1],"%"),n[2]="".concat(n[2],"%")),"".concat(e.type,"(").concat(n.join(", "),")")}function c(e,t){var n=l(e),r=l(t);return(Math.max(n,r)+.05)/(Math.min(n,r)+.05)}function l(e){var t=s(e);if(-1!==t.type.indexOf("rgb")){var n=t.values.map(function(e){return(e/=255)<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4)});return Number((.2126*n[0]+.7152*n[1]+.0722*n[2]).toFixed(3))}return t.values[2]/100}function f(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.15;return l(e)>.5?h(e,t):p(e,t)}function d(e,t){return e?(e=s(e),t=i(t),("rgb"===e.type||"hsl"===e.type)&&(e.type+="a"),e.values[3]=t,u(e)):e}function h(e,t){if(!e)return e;if(e=s(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]*=1-t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]*=1-t;return u(e)}function p(e,t){if(!e)return e;if(e=s(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]+=(100-e.values[2])*t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]+=(255-e.values[n])*t;return u(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.convertHexToRGB=a,t.rgbToHex=o,t.decomposeColor=s,t.recomposeColor=u,t.getContrastRatio=c,t.getLuminance=l,t.emphasize=f,t.fade=d,t.darken=h,t.lighten=p,r(n(42473))},94811(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=s,t.keys=void 0;var i=r(n(67154)),a=r(n(6479)),o=["xs","sm","md","lg","xl"];function s(e){var t=e.values,n=void 0===t?{xs:0,sm:600,md:960,lg:1280,xl:1920}:t,r=e.unit,s=void 0===r?"px":r,u=e.step,c=void 0===u?5:u,l=(0,a.default)(e,["values","unit","step"]);function f(e){var t="number"==typeof n[e]?n[e]:e;return"@media (min-width:".concat(t).concat(s,")")}function d(e){var t=o.indexOf(e)+1,r=n[o[t]];if(t===o.length)return f("xs");var i="number"==typeof r&&t>0?r:e;return"@media (max-width:".concat(i-c/100).concat(s,")")}function h(e,t){var r=o.indexOf(t)+1;return r===o.length?f(e):"@media (min-width:".concat(n[e]).concat(s,") and ")+"(max-width:".concat(n[o[r]]-c/100).concat(s,")")}function p(e){return h(e,e)}function b(e){return n[e]}return(0,i.default)({keys:o,values:n,up:f,down:d,between:h,only:p,width:b},l)}t.keys=o},20237(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=o,r(n(42473));var i=/([[\].#*$><+~=|^:(),"'`\s])/g;function a(e){var t;return String(e).replace(i,"-")}function o(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.dangerouslyUseGlobalCSS,n=void 0!==t&&t,r=e.productionPrefix,i=void 0===r?"jss":r,o=e.seed,s=void 0===o?"":o,u=0;return function(e,t){return(u+=1,n&&t&&t.options.name)?"".concat(a(t.options.name),"-").concat(e.key):"".concat(i).concat(s).concat(u)}}},40226(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=o;var i=r(n(59713)),a=r(n(67154));function o(e,t,n){var r;return(0,a.default)({gutters:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(0,a.default)({paddingLeft:2*t.unit,paddingRight:2*t.unit},n,(0,i.default)({},e.up("sm"),(0,a.default)({paddingLeft:3*t.unit,paddingRight:3*t.unit},n[e.up("sm")])))},toolbar:(r={minHeight:56},(0,i.default)(r,"".concat(e.up("xs")," and (orientation: landscape)"),{minHeight:48}),(0,i.default)(r,e.up("sm"),{minHeight:64}),r)},n)}},71615(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0,r(n(59713));var i=r(n(67154)),a=r(n(6479)),o=r(n(94863)),s=r(n(93078));r(n(42473));var u=r(n(94811)),c=r(n(40226)),l=r(n(21091)),f=r(n(45184)),d=r(n(80743)),h=r(n(59591)),p=r(n(5324)),b=r(n(15406)),m=r(n(88676));function g(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.breakpoints,r=void 0===n?{}:n,g=t.mixins,v=void 0===g?{}:g,y=t.palette,w=void 0===y?{}:y,_=t.shadows,E=t.spacing,S=void 0===E?{}:E,k=t.typography,x=void 0===k?{}:k,T=(0,a.default)(t,["breakpoints","mixins","palette","shadows","spacing","typography"]),M=(0,l.default)(w),O=(0,u.default)(r),A=(0,i.default)({},p.default,S);return(0,i.default)({breakpoints:O,direction:"ltr",mixins:(0,c.default)(O,A,v),overrides:{},palette:M,props:{},shadows:_||d.default,typography:(0,f.default)(M,x)},(0,o.default)({shape:h.default,spacing:A,transitions:b.default,zIndex:m.default},T,{isMergeableObject:s.default}))}var v=g;t.default=v},21091(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=m,t.dark=t.light=void 0;var i=r(n(67154)),a=r(n(6479));r(n(42473));var o=r(n(94863)),s=r(n(78768)),u=r(n(124)),c=r(n(70167)),l=r(n(83165)),f=r(n(515)),d=n(59114),h={text:{primary:"rgba(0, 0, 0, 0.87)",secondary:"rgba(0, 0, 0, 0.54)",disabled:"rgba(0, 0, 0, 0.38)",hint:"rgba(0, 0, 0, 0.38)"},divider:"rgba(0, 0, 0, 0.12)",background:{paper:f.default.white,default:c.default[50]},action:{active:"rgba(0, 0, 0, 0.54)",hover:"rgba(0, 0, 0, 0.08)",hoverOpacity:.08,selected:"rgba(0, 0, 0, 0.14)",disabled:"rgba(0, 0, 0, 0.26)",disabledBackground:"rgba(0, 0, 0, 0.12)"}};t.light=h;var p={text:{primary:f.default.white,secondary:"rgba(255, 255, 255, 0.7)",disabled:"rgba(255, 255, 255, 0.5)",hint:"rgba(255, 255, 255, 0.5)",icon:"rgba(255, 255, 255, 0.5)"},divider:"rgba(255, 255, 255, 0.12)",background:{paper:c.default[800],default:"#303030"},action:{active:f.default.white,hover:"rgba(255, 255, 255, 0.1)",hoverOpacity:.1,selected:"rgba(255, 255, 255, 0.2)",disabled:"rgba(255, 255, 255, 0.3)",disabledBackground:"rgba(255, 255, 255, 0.12)"}};function b(e,t,n,r){e[t]||(e.hasOwnProperty(n)?e[t]=e[n]:"light"===t?e.light=(0,d.lighten)(e.main,r):"dark"===t&&(e.dark=(0,d.darken)(e.main,1.5*r)))}function m(e){var t=e.primary,n=void 0===t?{light:s.default[300],main:s.default[500],dark:s.default[700]}:t,r=e.secondary,m=void 0===r?{light:u.default.A200,main:u.default.A400,dark:u.default.A700}:r,g=e.error,v=void 0===g?{light:l.default[300],main:l.default[500],dark:l.default[700]}:g,y=e.type,w=void 0===y?"light":y,_=e.contrastThreshold,E=void 0===_?3:_,S=e.tonalOffset,k=void 0===S?.2:S,x=(0,a.default)(e,["primary","secondary","error","type","contrastThreshold","tonalOffset"]);function T(e){var t;return(0,d.getContrastRatio)(e,p.text.primary)>=E?p.text.primary:h.text.primary}function M(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:500,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:300,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:700;return!e.main&&e[t]&&(e.main=e[t]),b(e,"light",n,k),b(e,"dark",r,k),e.contrastText||(e.contrastText=T(e.main)),e}M(n),M(m,"A400","A200","A700"),M(v);var O={dark:p,light:h};return(0,o.default)((0,i.default)({common:f.default,type:w,primary:n,secondary:m,error:v,grey:c.default,contrastThreshold:E,getContrastText:T,augmentColor:M,tonalOffset:k},O[w]),x,{clone:!1})}t.dark=p},16059(e,t){"use strict";function n(e){return e}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},45184(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=f;var i=r(n(67154)),a=r(n(6479)),o=r(n(94863));r(n(42473));var s=n(55252);function u(e){return Math.round(1e5*e)/1e5}var c={textTransform:"uppercase"},l='"Roboto", "Helvetica", "Arial", sans-serif';function f(e,t){var n="function"==typeof t?t(e):t,r=n.fontFamily,f=void 0===r?l:r,d=n.fontSize,h=void 0===d?14:d,p=n.fontWeightLight,b=void 0===p?300:p,m=n.fontWeightRegular,g=void 0===m?400:m,v=n.fontWeightMedium,y=void 0===v?500:v,w=n.htmlFontSize,_=void 0===w?16:w,E=n.useNextVariants,S=void 0===E?Boolean(s.ponyfillGlobal.__MUI_USE_NEXT_TYPOGRAPHY_VARIANTS__):E,k=(n.suppressWarning,n.allVariants),x=(0,a.default)(n,["fontFamily","fontSize","fontWeightLight","fontWeightRegular","fontWeightMedium","htmlFontSize","useNextVariants","suppressWarning","allVariants"]),T=h/14,M=function(e){return"".concat(e/_*T,"rem")},O=function(t,n,r,a,o){return(0,i.default)({color:e.text.primary,fontFamily:f,fontWeight:t,fontSize:M(n),lineHeight:r},f===l?{letterSpacing:"".concat(u(a/n),"em")}:{},o,k)},A={h1:O(b,96,1,-1.5),h2:O(b,60,1,-.5),h3:O(g,48,1.04,0),h4:O(g,34,1.17,.25),h5:O(g,24,1.33,0),h6:O(y,20,1.6,.15),subtitle1:O(g,16,1.75,.15),subtitle2:O(y,14,1.57,.1),body1Next:O(g,16,1.5,.15),body2Next:O(g,14,1.5,.15),buttonNext:O(y,14,1.75,.4,c),captionNext:O(g,12,1.66,.4),overline:O(g,12,2.66,1,c)},L={display4:(0,i.default)({fontSize:M(112),fontWeight:b,fontFamily:f,letterSpacing:"-.04em",lineHeight:"".concat(u(128/112),"em"),marginLeft:"-.04em",color:e.text.secondary},k),display3:(0,i.default)({fontSize:M(56),fontWeight:g,fontFamily:f,letterSpacing:"-.02em",lineHeight:"".concat(u(73/56),"em"),marginLeft:"-.02em",color:e.text.secondary},k),display2:(0,i.default)({fontSize:M(45),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(51/45),"em"),marginLeft:"-.02em",color:e.text.secondary},k),display1:(0,i.default)({fontSize:M(34),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(41/34),"em"),color:e.text.secondary},k),headline:(0,i.default)({fontSize:M(24),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(32.5/24),"em"),color:e.text.primary},k),title:(0,i.default)({fontSize:M(21),fontWeight:y,fontFamily:f,lineHeight:"".concat(u(24.5/21),"em"),color:e.text.primary},k),subheading:(0,i.default)({fontSize:M(16),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(1.5),"em"),color:e.text.primary},k),body2:(0,i.default)({fontSize:M(14),fontWeight:y,fontFamily:f,lineHeight:"".concat(u(24/14),"em"),color:e.text.primary},k),body1:(0,i.default)({fontSize:M(14),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(20.5/14),"em"),color:e.text.primary},k),caption:(0,i.default)({fontSize:M(12),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(1.375),"em"),color:e.text.secondary},k),button:(0,i.default)({fontSize:M(14),textTransform:"uppercase",fontWeight:y,fontFamily:f,color:e.text.primary},k)};return(0,o.default)((0,i.default)({pxToRem:M,round:u,fontFamily:f,fontSize:h,fontWeightLight:b,fontWeightRegular:g,fontWeightMedium:y},L,A,S?{body1:A.body1Next,body2:A.body2Next,button:A.buttonNext,caption:A.captionNext}:{},{useNextVariants:S}),x,{clone:!1})}},42458(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154));r(n(50008)),r(n(42473));var a=r(n(94863));function o(e,t){return t}function s(e){var t="function"==typeof e;function n(n,r){var s=t?e(n):e;if(!r||!n.overrides||!n.overrides[r])return s;var u=n.overrides[r],c=(0,i.default)({},s);return Object.keys(u).forEach(function(e){c[e]=(0,a.default)(c[e],u[e],{arrayMerge:o})}),c}return{create:n,options:{},themingEnabled:t}}var u=s;t.default=u},58057(e,t){"use strict";function n(e){var t,n=e.theme,r=e.name,i=e.props;if(!n.props||!r||!n.props[r])return i;var a=n.props[r];for(t in a)void 0===i[t]&&(i[t]=a[t]);return i}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},32316(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createGenerateClassName",{enumerable:!0,get:function(){return i.default}}),Object.defineProperty(t,"createMuiTheme",{enumerable:!0,get:function(){return a.default}}),Object.defineProperty(t,"jssPreset",{enumerable:!0,get:function(){return o.default}}),Object.defineProperty(t,"MuiThemeProvider",{enumerable:!0,get:function(){return s.default}}),Object.defineProperty(t,"createStyles",{enumerable:!0,get:function(){return u.default}}),Object.defineProperty(t,"withStyles",{enumerable:!0,get:function(){return c.default}}),Object.defineProperty(t,"withTheme",{enumerable:!0,get:function(){return l.default}});var i=r(n(20237)),a=r(n(71615)),o=r(n(9399)),s=r(n(72366)),u=r(n(16059)),c=r(n(78252)),l=r(n(82313))},9399(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(29059)),a=r(n(28752)),o=r(n(35828)),s=r(n(50462)),u=r(n(65926)),c=r(n(89347));function l(){return{plugins:[(0,i.default)(),(0,a.default)(),(0,o.default)(),(0,s.default)(),"undefined"==typeof window?null:(0,u.default)(),(0,c.default)()]}}var f=l;t.default=f},35199(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154));function a(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.baseClasses,n=e.newClasses;if(e.Component,!n)return t;var r=(0,i.default)({},t);return Object.keys(n).forEach(function(e){n[e]&&(r[e]="".concat(t[e]," ").concat(n[e]))}),r}r(n(42473)),n(55252);var o=a;t.default=o},88693(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={set:function(e,t,n,r){var i=e.get(t);i||(i=new Map,e.set(t,i)),i.set(n,r)},get:function(e,t,n){var r=e.get(t);return r?r.get(n):void 0},delete:function(e,t,n){e.get(t).delete(n)}};t.default=n},31898(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={jss:"64a55d578f856d258dc345b094a2a2b3",sheetsRegistry:"d4bd0baacbc52bbd48bbb9eb24344ecd",sheetOptions:"6fc570d6bd61383819d0f9e7407c452d"};t.default=n},80743(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=.2,r=.14,i=.12;function a(){return["".concat(arguments.length<=0?void 0:arguments[0],"px ").concat(arguments.length<=1?void 0:arguments[1],"px ").concat(arguments.length<=2?void 0:arguments[2],"px ").concat(arguments.length<=3?void 0:arguments[3],"px rgba(0,0,0,").concat(n,")"),"".concat(arguments.length<=4?void 0:arguments[4],"px ").concat(arguments.length<=5?void 0:arguments[5],"px ").concat(arguments.length<=6?void 0:arguments[6],"px ").concat(arguments.length<=7?void 0:arguments[7],"px rgba(0,0,0,").concat(r,")"),"".concat(arguments.length<=8?void 0:arguments[8],"px ").concat(arguments.length<=9?void 0:arguments[9],"px ").concat(arguments.length<=10?void 0:arguments[10],"px ").concat(arguments.length<=11?void 0:arguments[11],"px rgba(0,0,0,").concat(i,")")].join(",")}var o=["none",a(0,1,3,0,0,1,1,0,0,2,1,-1),a(0,1,5,0,0,2,2,0,0,3,1,-2),a(0,1,8,0,0,3,4,0,0,3,3,-2),a(0,2,4,-1,0,4,5,0,0,1,10,0),a(0,3,5,-1,0,5,8,0,0,1,14,0),a(0,3,5,-1,0,6,10,0,0,1,18,0),a(0,4,5,-2,0,7,10,1,0,2,16,1),a(0,5,5,-3,0,8,10,1,0,3,14,2),a(0,5,6,-3,0,9,12,1,0,3,16,2),a(0,6,6,-3,0,10,14,1,0,4,18,3),a(0,6,7,-4,0,11,15,1,0,4,20,3),a(0,7,8,-4,0,12,17,2,0,5,22,4),a(0,7,8,-4,0,13,19,2,0,5,24,4),a(0,7,9,-4,0,14,21,2,0,5,26,4),a(0,8,9,-5,0,15,22,2,0,6,28,5),a(0,8,10,-5,0,16,24,2,0,6,30,5),a(0,8,11,-5,0,17,26,2,0,6,32,5),a(0,9,11,-5,0,18,28,2,0,7,34,6),a(0,9,12,-6,0,19,29,2,0,7,36,6),a(0,10,13,-6,0,20,31,3,0,8,38,7),a(0,10,13,-6,0,21,33,3,0,8,40,7),a(0,10,14,-6,0,22,35,3,0,8,42,7),a(0,11,14,-7,0,23,36,3,0,9,44,8),a(0,11,15,-7,0,24,38,3,0,9,46,8)];t.default=o},59591(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={borderRadius:4};t.default=n},5324(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={unit:8};t.default=n},51067(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.CHANNEL=void 0;var i=r(n(59713)),a="__THEMING__";t.CHANNEL=a;var o={contextTypes:(0,i.default)({},a,function(){}),initial:function(e){return e[a]?e[a].getState():null},subscribe:function(e,t){return e[a]?e[a].subscribe(t):null},unsubscribe:function(e,t){e[a]&&e[a].unsubscribe(t)}};t.default=o},15406(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.isNumber=t.isString=t.formatMs=t.duration=t.easing=void 0;var i=r(n(6479));r(n(42473));var a={easeInOut:"cubic-bezier(0.4, 0, 0.2, 1)",easeOut:"cubic-bezier(0.0, 0, 0.2, 1)",easeIn:"cubic-bezier(0.4, 0, 1, 1)",sharp:"cubic-bezier(0.4, 0, 0.6, 1)"};t.easing=a;var o={shortest:150,shorter:200,short:250,standard:300,complex:375,enteringScreen:225,leavingScreen:195};t.duration=o;var s=function(e){return"".concat(Math.round(e),"ms")};t.formatMs=s;var u=function(e){return"string"==typeof e};t.isString=u;var c=function(e){return!isNaN(parseFloat(e))};t.isNumber=c;var l={easing:a,duration:o,create:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["all"],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.duration,r=void 0===n?o.standard:n,u=t.easing,c=void 0===u?a.easeInOut:u,l=t.delay,f=void 0===l?0:l;return(0,i.default)(t,["duration","easing","delay"]),(Array.isArray(e)?e:[e]).map(function(e){return"".concat(e," ").concat("string"==typeof r?r:s(r)," ").concat(c," ").concat("string"==typeof f?f:s(f))}).join(",")},getAutoHeightDuration:function(e){if(!e)return 0;var t=e/36;return Math.round((4+15*Math.pow(t,.25)+t/5)*10)}};t.default=l},78252(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.sheetsManager=void 0;var i=r(n(59713)),a=r(n(67154)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(6479)),d=r(n(67294)),h=r(n(45697));r(n(42473));var p=r(n(8679)),b=n(55252),m=n(55690),g=r(n(31898)),v=r(n(9399)),y=r(n(35199)),w=r(n(88693)),_=r(n(71615)),E=r(n(51067)),S=r(n(20237)),k=r(n(42458)),x=r(n(58057)),T=(0,m.create)((0,v.default)()),M=(0,S.default)(),O=-1e11,A=new Map;t.sheetsManager=A;var L={},C=(0,_.default)({typography:{suppressWarning:!0}}),I=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(n){var r,b=t.withTheme,m=void 0!==b&&b,v=t.flip,_=void 0===v?null:v,S=t.name,I=(0,f.default)(t,["withTheme","flip","name"]),D=(0,k.default)(e),N=D.themingEnabled||"string"==typeof S||m;O+=1,D.options.index=O;var P=function(e){function t(e,n){(0,o.default)(this,t),(r=(0,u.default)(this,(0,c.default)(t).call(this,e,n))).jss=n[g.default.jss]||T,r.sheetsManager=A,r.unsubscribeId=null;var r,i=n.muiThemeProviderOptions;return i&&(i.sheetsManager&&(r.sheetsManager=i.sheetsManager),r.sheetsCache=i.sheetsCache,r.disableStylesGeneration=i.disableStylesGeneration),r.stylesCreatorSaved=D,r.sheetOptions=(0,a.default)({generateClassName:M},n[g.default.sheetOptions]),r.theme=N?E.default.initial(n)||C:L,r.attach(r.theme),r.cacheClasses={value:null,lastProp:null,lastJSS:{}},r}return(0,l.default)(t,e),(0,s.default)(t,[{key:"componentDidMount",value:function(){var e=this;N&&(this.unsubscribeId=E.default.subscribe(this.context,function(t){var n=e.theme;e.theme=t,e.attach(e.theme),e.setState({},function(){e.detach(n)})}))}},{key:"componentDidUpdate",value:function(){this.stylesCreatorSaved}},{key:"componentWillUnmount",value:function(){this.detach(this.theme),null!==this.unsubscribeId&&E.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"getClasses",value:function(){if(this.disableStylesGeneration)return this.props.classes||{};var e=!1,t=w.default.get(this.sheetsManager,this.stylesCreatorSaved,this.theme);return t.sheet.classes!==this.cacheClasses.lastJSS&&(this.cacheClasses.lastJSS=t.sheet.classes,e=!0),this.props.classes!==this.cacheClasses.lastProp&&(this.cacheClasses.lastProp=this.props.classes,e=!0),e&&(this.cacheClasses.value=(0,y.default)({baseClasses:this.cacheClasses.lastJSS,newClasses:this.props.classes,Component:n})),this.cacheClasses.value}},{key:"attach",value:function(e){if(!this.disableStylesGeneration){var t=this.stylesCreatorSaved,n=w.default.get(this.sheetsManager,t,e);if(n||(n={refs:0,sheet:null},w.default.set(this.sheetsManager,t,e,n)),0===n.refs){this.sheetsCache&&(r=w.default.get(this.sheetsCache,t,e)),!r&&((r=this.createSheet(e)).attach(),this.sheetsCache&&w.default.set(this.sheetsCache,t,e,r)),n.sheet=r;var r,i=this.context[g.default.sheetsRegistry];i&&i.add(r)}n.refs+=1}}},{key:"createSheet",value:function(e){var t=this.stylesCreatorSaved.create(e,S),r=S;return this.jss.createStyleSheet(t,(0,a.default)({meta:r,classNamePrefix:r,flip:"boolean"==typeof _?_:"rtl"===e.direction,link:!1},this.sheetOptions,this.stylesCreatorSaved.options,{name:S||n.displayName},I))}},{key:"detach",value:function(e){if(!this.disableStylesGeneration){var t=w.default.get(this.sheetsManager,this.stylesCreatorSaved,e);if(t.refs-=1,0===t.refs){w.default.delete(this.sheetsManager,this.stylesCreatorSaved,e),this.jss.removeStyleSheet(t.sheet);var n=this.context[g.default.sheetsRegistry];n&&n.remove(t.sheet)}}}},{key:"render",value:function(){var e=this.props,t=(e.classes,e.innerRef),r=(0,f.default)(e,["classes","innerRef"]),i=(0,x.default)({theme:this.theme,name:S,props:r});return m&&!i.theme&&(i.theme=this.theme),d.default.createElement(n,(0,a.default)({},i,{classes:this.getClasses(),ref:t}))}}]),t}(d.default.Component);return P.contextTypes=(0,a.default)((r={muiThemeProviderOptions:h.default.object},(0,i.default)(r,g.default.jss,h.default.object),(0,i.default)(r,g.default.sheetOptions,h.default.object),(0,i.default)(r,g.default.sheetsRegistry,h.default.object),r),N?E.default.contextTypes:{}),(0,p.default)(P,n),P}};b.ponyfillGlobal.__MUI_STYLES__||(b.ponyfillGlobal.__MUI_STYLES__={}),b.ponyfillGlobal.__MUI_STYLES__.withStyles||(b.ponyfillGlobal.__MUI_STYLES__.withStyles=I);var D=function(e,t){return b.ponyfillGlobal.__MUI_STYLES__.withStyles(e,(0,a.default)({defaultTheme:C},t))};t.default=D},82313(e,t,n){"use strict";var r,i=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=i(n(67154)),o=i(n(6479)),s=i(n(34575)),u=i(n(93913)),c=i(n(78585)),l=i(n(29754)),f=i(n(2205)),d=i(n(67294));i(n(45697));var h=i(n(8679)),p=n(55252),b=i(n(71615)),m=i(n(51067));function g(){return r||(r=(0,b.default)({typography:{suppressWarning:!0}}))}var v=function(){return function(e){var t=function(t){function n(e,t){var r;return(0,s.default)(this,n),(r=(0,c.default)(this,(0,l.default)(n).call(this))).state={theme:m.default.initial(t)||g()},r}return(0,f.default)(n,t),(0,u.default)(n,[{key:"componentDidMount",value:function(){var e=this;this.unsubscribeId=m.default.subscribe(this.context,function(t){e.setState({theme:t})})}},{key:"componentWillUnmount",value:function(){null!==this.unsubscribeId&&m.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"render",value:function(){var t=this.props,n=t.innerRef,r=(0,o.default)(t,["innerRef"]);return d.default.createElement(e,(0,a.default)({theme:this.state.theme,ref:n},r))}}]),n}(d.default.Component);return t.contextTypes=m.default.contextTypes,(0,h.default)(t,e),t}};p.ponyfillGlobal.__MUI_STYLES__||(p.ponyfillGlobal.__MUI_STYLES__={}),p.ponyfillGlobal.__MUI_STYLES__.withTheme||(p.ponyfillGlobal.__MUI_STYLES__.withTheme=v);var y=p.ponyfillGlobal.__MUI_STYLES__.withTheme;t.default=y},88676(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={mobileStepper:1e3,appBar:1100,drawer:1200,modal:1300,snackbar:1400,tooltip:1500};t.default=n},41929(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getTransitionProps=r,t.reflow=void 0;var n=function(e){return e.scrollTop};function r(e,t){var n=e.timeout,r=e.style,i=void 0===r?{}:r;return{duration:i.transitionDuration||"number"==typeof n?n:n[t.mode],delay:i.transitionDelay}}t.reflow=n},346(e,t){"use strict";function n(e,t){return function(){return null}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},98741(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.capitalize=a,t.contains=o,t.findIndex=s,t.find=u,t.createChainedFunction=c;var i=r(n(50008));function a(e){return e.charAt(0).toUpperCase()+e.slice(1)}function o(e,t){return Object.keys(t).every(function(n){return e.hasOwnProperty(n)&&e[n]===t[n]})}function s(e,t){for(var n=(0,i.default)(t),r=0;r-1?e[n]:void 0}function c(){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:window,n=(0,i.default)(e);return n.defaultView||n.parentView||t}var o=a;t.default=o},44370(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.cloneElementWithClassName=o,t.cloneChildrenWithClassName=s,t.isMuiElement=u,t.setRef=c;var i=r(n(67294)),a=r(n(94184));function o(e,t){return i.default.cloneElement(e,{className:(0,a.default)(e.props.className,t)})}function s(e,t){return i.default.Children.map(e,function(e){return i.default.isValidElement(e)&&o(e,t)})}function u(e,t){return i.default.isValidElement(e)&&-1!==t.indexOf(e.type.muiName)}function c(e,t){"function"==typeof e?e(t):e&&(e.current=t)}},47348(e,t){"use strict";function n(e){return function(){return null}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},21677(e,t){"use strict";function n(e,t,n,r,i){return null}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},78290(e,t,n){"use strict";var r=n(20862);Object.defineProperty(t,"__esModule",{value:!0});var i={};Object.defineProperty(t,"default",{enumerable:!0,get:function(){return a.default}});var a=r(n(88446));Object.keys(a).forEach(function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(i,e)||Object.defineProperty(t,e,{enumerable:!0,get:function(){return a[e]}}))})},88446(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.isWidthDown=t.isWidthUp=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294));r(n(45697));var d=r(n(96421)),h=r(n(20296));n(55252);var p=r(n(8679)),b=r(n(82313)),m=n(94811),g=r(n(58057)),v=function(e,t){var n=!(arguments.length>2)||void 0===arguments[2]||arguments[2];return n?m.keys.indexOf(e)<=m.keys.indexOf(t):m.keys.indexOf(e)2)||void 0===arguments[2]||arguments[2];return n?m.keys.indexOf(t)<=m.keys.indexOf(e):m.keys.indexOf(t)0&&void 0!==arguments[0]?arguments[0]:{};return function(t){var n=e.withTheme,r=void 0!==n&&n,v=e.noSSR,y=void 0!==v&&v,w=e.initialWidth,_=e.resizeInterval,E=void 0===_?166:_,S=function(e){function n(e){var t;return(0,o.default)(this,n),(t=(0,u.default)(this,(0,c.default)(n).call(this,e))).state={width:y?t.getWidth():void 0},"undefined"!=typeof window&&(t.handleResize=(0,h.default)(function(){var e=t.getWidth();e!==t.state.width&&t.setState({width:e})},E)),t}return(0,l.default)(n,e),(0,s.default)(n,[{key:"componentDidMount",value:function(){var e=this.getWidth();e!==this.state.width&&this.setState({width:e})}},{key:"componentWillUnmount",value:function(){this.handleResize.clear()}},{key:"getWidth",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window.innerWidth,t=this.props.theme.breakpoints,n=null,r=1;null===n&&ri.Z,componentPropType:()=>r.Z,exactProp:()=>a.ZP,getDisplayName:()=>o.ZP,ponyfillGlobal:()=>s.Z});var r=n(78728),i=n(5477),a=n(43781),o=n(25189),s=n(34712);/** @license Material-UI v3.0.0-alpha.3 + */ var r=n(47798);function i(e){return!0===r(e)&&"[object Object]"===Object.prototype.toString.call(e)}e.exports=function(e){var t,n;return!1!==i(e)&&"function"==typeof(t=e.constructor)&&!1!==i(n=t.prototype)&&!1!==n.hasOwnProperty("isPrototypeOf")}},72366(e,t,n){"use strict";var r=n(20862),i=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.MuiThemeProviderOld=void 0;var a=i(n(67154)),o=i(n(59713)),s=i(n(34575)),u=i(n(93913)),c=i(n(78585)),l=i(n(29754)),f=i(n(2205)),d=i(n(67294)),h=i(n(45697));i(n(42473));var p=i(n(43890)),b=n(55252),m=r(n(51067)),g=function(e){function t(e,n){var r;return(0,s.default)(this,t),(r=(0,c.default)(this,(0,l.default)(t).call(this))).broadcast=(0,p.default)(),r.outerTheme=m.default.initial(n),r.broadcast.setState(r.mergeOuterLocalTheme(e.theme)),r}return(0,f.default)(t,e),(0,u.default)(t,[{key:"getChildContext",value:function(){var e,t=this.props,n=t.disableStylesGeneration,r=t.sheetsCache,i=t.sheetsManager,a=this.context.muiThemeProviderOptions||{};return void 0!==n&&(a.disableStylesGeneration=n),void 0!==r&&(a.sheetsCache=r),void 0!==i&&(a.sheetsManager=i),e={},(0,o.default)(e,m.CHANNEL,this.broadcast),(0,o.default)(e,"muiThemeProviderOptions",a),e}},{key:"componentDidMount",value:function(){var e=this;this.unsubscribeId=m.default.subscribe(this.context,function(t){e.outerTheme=t,e.broadcast.setState(e.mergeOuterLocalTheme(e.props.theme))})}},{key:"componentDidUpdate",value:function(e){this.props.theme!==e.theme&&this.broadcast.setState(this.mergeOuterLocalTheme(this.props.theme))}},{key:"componentWillUnmount",value:function(){null!==this.unsubscribeId&&m.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"mergeOuterLocalTheme",value:function(e){return"function"==typeof e?e(this.outerTheme):this.outerTheme?(0,a.default)({},this.outerTheme,e):e}},{key:"render",value:function(){return this.props.children}}]),t}(d.default.Component);t.MuiThemeProviderOld=g,g.childContextTypes=(0,a.default)({},m.default.contextTypes,{muiThemeProviderOptions:h.default.object}),g.contextTypes=(0,a.default)({},m.default.contextTypes,{muiThemeProviderOptions:h.default.object}),b.ponyfillGlobal.__MUI_STYLES__||(b.ponyfillGlobal.__MUI_STYLES__={}),b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider||(b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider=g);var v=b.ponyfillGlobal.__MUI_STYLES__.MuiThemeProvider;t.default=v},59114(e,t,n){"use strict";var r=n(95318);function i(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return en?n:e}function a(e){e=e.substr(1);var t=RegExp(".{1,".concat(e.length/3,"}"),"g"),n=e.match(t);return n&&1===n[0].length&&(n=n.map(function(e){return e+e})),n?"rgb(".concat(n.map(function(e){return parseInt(e,16)}).join(", "),")"):""}function o(e){if(0===e.indexOf("#"))return e;function t(e){var t=e.toString(16);return 1===t.length?"0".concat(t):t}var n=s(e).values;return n=n.map(function(e){return t(e)}),"#".concat(n.join(""))}function s(e){if("#"===e.charAt(0))return s(a(e));var t=e.indexOf("("),n=e.substring(0,t),r=e.substring(t+1,e.length-1).split(",");return r=r.map(function(e){return parseFloat(e)}),{type:n,values:r}}function u(e){var t=e.type,n=e.values;return -1!==t.indexOf("rgb")&&(n=n.map(function(e,t){return t<3?parseInt(e,10):e})),-1!==t.indexOf("hsl")&&(n[1]="".concat(n[1],"%"),n[2]="".concat(n[2],"%")),"".concat(e.type,"(").concat(n.join(", "),")")}function c(e,t){var n=l(e),r=l(t);return(Math.max(n,r)+.05)/(Math.min(n,r)+.05)}function l(e){var t=s(e);if(-1!==t.type.indexOf("rgb")){var n=t.values.map(function(e){return(e/=255)<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4)});return Number((.2126*n[0]+.7152*n[1]+.0722*n[2]).toFixed(3))}return t.values[2]/100}function f(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.15;return l(e)>.5?h(e,t):p(e,t)}function d(e,t){return e?(e=s(e),t=i(t),("rgb"===e.type||"hsl"===e.type)&&(e.type+="a"),e.values[3]=t,u(e)):e}function h(e,t){if(!e)return e;if(e=s(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]*=1-t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]*=1-t;return u(e)}function p(e,t){if(!e)return e;if(e=s(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]+=(100-e.values[2])*t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]+=(255-e.values[n])*t;return u(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.convertHexToRGB=a,t.rgbToHex=o,t.decomposeColor=s,t.recomposeColor=u,t.getContrastRatio=c,t.getLuminance=l,t.emphasize=f,t.fade=d,t.darken=h,t.lighten=p,r(n(42473))},94811(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=s,t.keys=void 0;var i=r(n(67154)),a=r(n(6479)),o=["xs","sm","md","lg","xl"];function s(e){var t=e.values,n=void 0===t?{xs:0,sm:600,md:960,lg:1280,xl:1920}:t,r=e.unit,s=void 0===r?"px":r,u=e.step,c=void 0===u?5:u,l=(0,a.default)(e,["values","unit","step"]);function f(e){var t="number"==typeof n[e]?n[e]:e;return"@media (min-width:".concat(t).concat(s,")")}function d(e){var t=o.indexOf(e)+1,r=n[o[t]];if(t===o.length)return f("xs");var i="number"==typeof r&&t>0?r:e;return"@media (max-width:".concat(i-c/100).concat(s,")")}function h(e,t){var r=o.indexOf(t)+1;return r===o.length?f(e):"@media (min-width:".concat(n[e]).concat(s,") and ")+"(max-width:".concat(n[o[r]]-c/100).concat(s,")")}function p(e){return h(e,e)}function b(e){return n[e]}return(0,i.default)({keys:o,values:n,up:f,down:d,between:h,only:p,width:b},l)}t.keys=o},20237(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=o,r(n(42473));var i=/([[\].#*$><+~=|^:(),"'`\s])/g;function a(e){var t;return String(e).replace(i,"-")}function o(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.dangerouslyUseGlobalCSS,n=void 0!==t&&t,r=e.productionPrefix,i=void 0===r?"jss":r,o=e.seed,s=void 0===o?"":o,u=0;return function(e,t){return(u+=1,n&&t&&t.options.name)?"".concat(a(t.options.name),"-").concat(e.key):"".concat(i).concat(s).concat(u)}}},40226(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=o;var i=r(n(59713)),a=r(n(67154));function o(e,t,n){var r;return(0,a.default)({gutters:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(0,a.default)({paddingLeft:2*t.unit,paddingRight:2*t.unit},n,(0,i.default)({},e.up("sm"),(0,a.default)({paddingLeft:3*t.unit,paddingRight:3*t.unit},n[e.up("sm")])))},toolbar:(r={minHeight:56},(0,i.default)(r,"".concat(e.up("xs")," and (orientation: landscape)"),{minHeight:48}),(0,i.default)(r,e.up("sm"),{minHeight:64}),r)},n)}},71615(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0,r(n(59713));var i=r(n(67154)),a=r(n(6479)),o=r(n(94863)),s=r(n(93078));r(n(42473));var u=r(n(94811)),c=r(n(40226)),l=r(n(21091)),f=r(n(45184)),d=r(n(80743)),h=r(n(59591)),p=r(n(5324)),b=r(n(15406)),m=r(n(88676));function g(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.breakpoints,r=void 0===n?{}:n,g=t.mixins,v=void 0===g?{}:g,y=t.palette,w=void 0===y?{}:y,_=t.shadows,E=t.spacing,S=void 0===E?{}:E,k=t.typography,x=void 0===k?{}:k,T=(0,a.default)(t,["breakpoints","mixins","palette","shadows","spacing","typography"]),M=(0,l.default)(w),O=(0,u.default)(r),A=(0,i.default)({},p.default,S);return(0,i.default)({breakpoints:O,direction:"ltr",mixins:(0,c.default)(O,A,v),overrides:{},palette:M,props:{},shadows:_||d.default,typography:(0,f.default)(M,x)},(0,o.default)({shape:h.default,spacing:A,transitions:b.default,zIndex:m.default},T,{isMergeableObject:s.default}))}var v=g;t.default=v},21091(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=m,t.dark=t.light=void 0;var i=r(n(67154)),a=r(n(6479));r(n(42473));var o=r(n(94863)),s=r(n(78768)),u=r(n(124)),c=r(n(70167)),l=r(n(83165)),f=r(n(515)),d=n(59114),h={text:{primary:"rgba(0, 0, 0, 0.87)",secondary:"rgba(0, 0, 0, 0.54)",disabled:"rgba(0, 0, 0, 0.38)",hint:"rgba(0, 0, 0, 0.38)"},divider:"rgba(0, 0, 0, 0.12)",background:{paper:f.default.white,default:c.default[50]},action:{active:"rgba(0, 0, 0, 0.54)",hover:"rgba(0, 0, 0, 0.08)",hoverOpacity:.08,selected:"rgba(0, 0, 0, 0.14)",disabled:"rgba(0, 0, 0, 0.26)",disabledBackground:"rgba(0, 0, 0, 0.12)"}};t.light=h;var p={text:{primary:f.default.white,secondary:"rgba(255, 255, 255, 0.7)",disabled:"rgba(255, 255, 255, 0.5)",hint:"rgba(255, 255, 255, 0.5)",icon:"rgba(255, 255, 255, 0.5)"},divider:"rgba(255, 255, 255, 0.12)",background:{paper:c.default[800],default:"#303030"},action:{active:f.default.white,hover:"rgba(255, 255, 255, 0.1)",hoverOpacity:.1,selected:"rgba(255, 255, 255, 0.2)",disabled:"rgba(255, 255, 255, 0.3)",disabledBackground:"rgba(255, 255, 255, 0.12)"}};function b(e,t,n,r){e[t]||(e.hasOwnProperty(n)?e[t]=e[n]:"light"===t?e.light=(0,d.lighten)(e.main,r):"dark"===t&&(e.dark=(0,d.darken)(e.main,1.5*r)))}function m(e){var t=e.primary,n=void 0===t?{light:s.default[300],main:s.default[500],dark:s.default[700]}:t,r=e.secondary,m=void 0===r?{light:u.default.A200,main:u.default.A400,dark:u.default.A700}:r,g=e.error,v=void 0===g?{light:l.default[300],main:l.default[500],dark:l.default[700]}:g,y=e.type,w=void 0===y?"light":y,_=e.contrastThreshold,E=void 0===_?3:_,S=e.tonalOffset,k=void 0===S?.2:S,x=(0,a.default)(e,["primary","secondary","error","type","contrastThreshold","tonalOffset"]);function T(e){var t;return(0,d.getContrastRatio)(e,p.text.primary)>=E?p.text.primary:h.text.primary}function M(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:500,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:300,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:700;return!e.main&&e[t]&&(e.main=e[t]),b(e,"light",n,k),b(e,"dark",r,k),e.contrastText||(e.contrastText=T(e.main)),e}M(n),M(m,"A400","A200","A700"),M(v);var O={dark:p,light:h};return(0,o.default)((0,i.default)({common:f.default,type:w,primary:n,secondary:m,error:v,grey:c.default,contrastThreshold:E,getContrastText:T,augmentColor:M,tonalOffset:k},O[w]),x,{clone:!1})}t.dark=p},16059(e,t){"use strict";function n(e){return e}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},45184(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=f;var i=r(n(67154)),a=r(n(6479)),o=r(n(94863));r(n(42473));var s=n(55252);function u(e){return Math.round(1e5*e)/1e5}var c={textTransform:"uppercase"},l='"Roboto", "Helvetica", "Arial", sans-serif';function f(e,t){var n="function"==typeof t?t(e):t,r=n.fontFamily,f=void 0===r?l:r,d=n.fontSize,h=void 0===d?14:d,p=n.fontWeightLight,b=void 0===p?300:p,m=n.fontWeightRegular,g=void 0===m?400:m,v=n.fontWeightMedium,y=void 0===v?500:v,w=n.htmlFontSize,_=void 0===w?16:w,E=n.useNextVariants,S=void 0===E?Boolean(s.ponyfillGlobal.__MUI_USE_NEXT_TYPOGRAPHY_VARIANTS__):E,k=(n.suppressWarning,n.allVariants),x=(0,a.default)(n,["fontFamily","fontSize","fontWeightLight","fontWeightRegular","fontWeightMedium","htmlFontSize","useNextVariants","suppressWarning","allVariants"]),T=h/14,M=function(e){return"".concat(e/_*T,"rem")},O=function(t,n,r,a,o){return(0,i.default)({color:e.text.primary,fontFamily:f,fontWeight:t,fontSize:M(n),lineHeight:r},f===l?{letterSpacing:"".concat(u(a/n),"em")}:{},o,k)},A={h1:O(b,96,1,-1.5),h2:O(b,60,1,-.5),h3:O(g,48,1.04,0),h4:O(g,34,1.17,.25),h5:O(g,24,1.33,0),h6:O(y,20,1.6,.15),subtitle1:O(g,16,1.75,.15),subtitle2:O(y,14,1.57,.1),body1Next:O(g,16,1.5,.15),body2Next:O(g,14,1.5,.15),buttonNext:O(y,14,1.75,.4,c),captionNext:O(g,12,1.66,.4),overline:O(g,12,2.66,1,c)},L={display4:(0,i.default)({fontSize:M(112),fontWeight:b,fontFamily:f,letterSpacing:"-.04em",lineHeight:"".concat(u(128/112),"em"),marginLeft:"-.04em",color:e.text.secondary},k),display3:(0,i.default)({fontSize:M(56),fontWeight:g,fontFamily:f,letterSpacing:"-.02em",lineHeight:"".concat(u(73/56),"em"),marginLeft:"-.02em",color:e.text.secondary},k),display2:(0,i.default)({fontSize:M(45),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(51/45),"em"),marginLeft:"-.02em",color:e.text.secondary},k),display1:(0,i.default)({fontSize:M(34),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(41/34),"em"),color:e.text.secondary},k),headline:(0,i.default)({fontSize:M(24),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(32.5/24),"em"),color:e.text.primary},k),title:(0,i.default)({fontSize:M(21),fontWeight:y,fontFamily:f,lineHeight:"".concat(u(24.5/21),"em"),color:e.text.primary},k),subheading:(0,i.default)({fontSize:M(16),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(1.5),"em"),color:e.text.primary},k),body2:(0,i.default)({fontSize:M(14),fontWeight:y,fontFamily:f,lineHeight:"".concat(u(24/14),"em"),color:e.text.primary},k),body1:(0,i.default)({fontSize:M(14),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(20.5/14),"em"),color:e.text.primary},k),caption:(0,i.default)({fontSize:M(12),fontWeight:g,fontFamily:f,lineHeight:"".concat(u(1.375),"em"),color:e.text.secondary},k),button:(0,i.default)({fontSize:M(14),textTransform:"uppercase",fontWeight:y,fontFamily:f,color:e.text.primary},k)};return(0,o.default)((0,i.default)({pxToRem:M,round:u,fontFamily:f,fontSize:h,fontWeightLight:b,fontWeightRegular:g,fontWeightMedium:y},L,A,S?{body1:A.body1Next,body2:A.body2Next,button:A.buttonNext,caption:A.captionNext}:{},{useNextVariants:S}),x,{clone:!1})}},42458(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154));r(n(50008)),r(n(42473));var a=r(n(94863));function o(e,t){return t}function s(e){var t="function"==typeof e;function n(n,r){var s=t?e(n):e;if(!r||!n.overrides||!n.overrides[r])return s;var u=n.overrides[r],c=(0,i.default)({},s);return Object.keys(u).forEach(function(e){c[e]=(0,a.default)(c[e],u[e],{arrayMerge:o})}),c}return{create:n,options:{},themingEnabled:t}}var u=s;t.default=u},58057(e,t){"use strict";function n(e){var t,n=e.theme,r=e.name,i=e.props;if(!n.props||!r||!n.props[r])return i;var a=n.props[r];for(t in a)void 0===i[t]&&(i[t]=a[t]);return i}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},32316(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"createGenerateClassName",{enumerable:!0,get:function(){return i.default}}),Object.defineProperty(t,"createMuiTheme",{enumerable:!0,get:function(){return a.default}}),Object.defineProperty(t,"jssPreset",{enumerable:!0,get:function(){return o.default}}),Object.defineProperty(t,"MuiThemeProvider",{enumerable:!0,get:function(){return s.default}}),Object.defineProperty(t,"createStyles",{enumerable:!0,get:function(){return u.default}}),Object.defineProperty(t,"withStyles",{enumerable:!0,get:function(){return c.default}}),Object.defineProperty(t,"withTheme",{enumerable:!0,get:function(){return l.default}});var i=r(n(20237)),a=r(n(71615)),o=r(n(9399)),s=r(n(72366)),u=r(n(16059)),c=r(n(78252)),l=r(n(82313))},9399(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(29059)),a=r(n(28752)),o=r(n(35828)),s=r(n(50462)),u=r(n(65926)),c=r(n(89347));function l(){return{plugins:[(0,i.default)(),(0,a.default)(),(0,o.default)(),(0,s.default)(),"undefined"==typeof window?null:(0,u.default)(),(0,c.default)()]}}var f=l;t.default=f},35199(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=r(n(67154));function a(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.baseClasses,n=e.newClasses;if(e.Component,!n)return t;var r=(0,i.default)({},t);return Object.keys(n).forEach(function(e){n[e]&&(r[e]="".concat(t[e]," ").concat(n[e]))}),r}r(n(42473)),n(55252);var o=a;t.default=o},88693(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={set:function(e,t,n,r){var i=e.get(t);i||(i=new Map,e.set(t,i)),i.set(n,r)},get:function(e,t,n){var r=e.get(t);return r?r.get(n):void 0},delete:function(e,t,n){e.get(t).delete(n)}};t.default=n},31898(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={jss:"64a55d578f856d258dc345b094a2a2b3",sheetsRegistry:"d4bd0baacbc52bbd48bbb9eb24344ecd",sheetOptions:"6fc570d6bd61383819d0f9e7407c452d"};t.default=n},80743(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=.2,r=.14,i=.12;function a(){return["".concat(arguments.length<=0?void 0:arguments[0],"px ").concat(arguments.length<=1?void 0:arguments[1],"px ").concat(arguments.length<=2?void 0:arguments[2],"px ").concat(arguments.length<=3?void 0:arguments[3],"px rgba(0,0,0,").concat(n,")"),"".concat(arguments.length<=4?void 0:arguments[4],"px ").concat(arguments.length<=5?void 0:arguments[5],"px ").concat(arguments.length<=6?void 0:arguments[6],"px ").concat(arguments.length<=7?void 0:arguments[7],"px rgba(0,0,0,").concat(r,")"),"".concat(arguments.length<=8?void 0:arguments[8],"px ").concat(arguments.length<=9?void 0:arguments[9],"px ").concat(arguments.length<=10?void 0:arguments[10],"px ").concat(arguments.length<=11?void 0:arguments[11],"px rgba(0,0,0,").concat(i,")")].join(",")}var o=["none",a(0,1,3,0,0,1,1,0,0,2,1,-1),a(0,1,5,0,0,2,2,0,0,3,1,-2),a(0,1,8,0,0,3,4,0,0,3,3,-2),a(0,2,4,-1,0,4,5,0,0,1,10,0),a(0,3,5,-1,0,5,8,0,0,1,14,0),a(0,3,5,-1,0,6,10,0,0,1,18,0),a(0,4,5,-2,0,7,10,1,0,2,16,1),a(0,5,5,-3,0,8,10,1,0,3,14,2),a(0,5,6,-3,0,9,12,1,0,3,16,2),a(0,6,6,-3,0,10,14,1,0,4,18,3),a(0,6,7,-4,0,11,15,1,0,4,20,3),a(0,7,8,-4,0,12,17,2,0,5,22,4),a(0,7,8,-4,0,13,19,2,0,5,24,4),a(0,7,9,-4,0,14,21,2,0,5,26,4),a(0,8,9,-5,0,15,22,2,0,6,28,5),a(0,8,10,-5,0,16,24,2,0,6,30,5),a(0,8,11,-5,0,17,26,2,0,6,32,5),a(0,9,11,-5,0,18,28,2,0,7,34,6),a(0,9,12,-6,0,19,29,2,0,7,36,6),a(0,10,13,-6,0,20,31,3,0,8,38,7),a(0,10,13,-6,0,21,33,3,0,8,40,7),a(0,10,14,-6,0,22,35,3,0,8,42,7),a(0,11,14,-7,0,23,36,3,0,9,44,8),a(0,11,15,-7,0,24,38,3,0,9,46,8)];t.default=o},59591(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={borderRadius:4};t.default=n},5324(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={unit:8};t.default=n},51067(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.CHANNEL=void 0;var i=r(n(59713)),a="__THEMING__";t.CHANNEL=a;var o={contextTypes:(0,i.default)({},a,function(){}),initial:function(e){return e[a]?e[a].getState():null},subscribe:function(e,t){return e[a]?e[a].subscribe(t):null},unsubscribe:function(e,t){e[a]&&e[a].unsubscribe(t)}};t.default=o},15406(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.isNumber=t.isString=t.formatMs=t.duration=t.easing=void 0;var i=r(n(6479));r(n(42473));var a={easeInOut:"cubic-bezier(0.4, 0, 0.2, 1)",easeOut:"cubic-bezier(0.0, 0, 0.2, 1)",easeIn:"cubic-bezier(0.4, 0, 1, 1)",sharp:"cubic-bezier(0.4, 0, 0.6, 1)"};t.easing=a;var o={shortest:150,shorter:200,short:250,standard:300,complex:375,enteringScreen:225,leavingScreen:195};t.duration=o;var s=function(e){return"".concat(Math.round(e),"ms")};t.formatMs=s;var u=function(e){return"string"==typeof e};t.isString=u;var c=function(e){return!isNaN(parseFloat(e))};t.isNumber=c;var l={easing:a,duration:o,create:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:["all"],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.duration,r=void 0===n?o.standard:n,u=t.easing,c=void 0===u?a.easeInOut:u,l=t.delay,f=void 0===l?0:l;return(0,i.default)(t,["duration","easing","delay"]),(Array.isArray(e)?e:[e]).map(function(e){return"".concat(e," ").concat("string"==typeof r?r:s(r)," ").concat(c," ").concat("string"==typeof f?f:s(f))}).join(",")},getAutoHeightDuration:function(e){if(!e)return 0;var t=e/36;return Math.round((4+15*Math.pow(t,.25)+t/5)*10)}};t.default=l},78252(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.sheetsManager=void 0;var i=r(n(59713)),a=r(n(67154)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(6479)),d=r(n(67294)),h=r(n(45697));r(n(42473));var p=r(n(8679)),b=n(55252),m=n(55690),g=r(n(31898)),v=r(n(9399)),y=r(n(35199)),w=r(n(88693)),_=r(n(71615)),E=r(n(51067)),S=r(n(20237)),k=r(n(42458)),x=r(n(58057)),T=(0,m.create)((0,v.default)()),M=(0,S.default)(),O=-1e11,A=new Map;t.sheetsManager=A;var L={},C=(0,_.default)({typography:{suppressWarning:!0}}),I=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return function(n){var r,b=t.withTheme,m=void 0!==b&&b,v=t.flip,_=void 0===v?null:v,S=t.name,I=(0,f.default)(t,["withTheme","flip","name"]),D=(0,k.default)(e),N=D.themingEnabled||"string"==typeof S||m;O+=1,D.options.index=O;var P=function(e){function t(e,n){(0,o.default)(this,t),(r=(0,u.default)(this,(0,c.default)(t).call(this,e,n))).jss=n[g.default.jss]||T,r.sheetsManager=A,r.unsubscribeId=null;var r,i=n.muiThemeProviderOptions;return i&&(i.sheetsManager&&(r.sheetsManager=i.sheetsManager),r.sheetsCache=i.sheetsCache,r.disableStylesGeneration=i.disableStylesGeneration),r.stylesCreatorSaved=D,r.sheetOptions=(0,a.default)({generateClassName:M},n[g.default.sheetOptions]),r.theme=N?E.default.initial(n)||C:L,r.attach(r.theme),r.cacheClasses={value:null,lastProp:null,lastJSS:{}},r}return(0,l.default)(t,e),(0,s.default)(t,[{key:"componentDidMount",value:function(){var e=this;N&&(this.unsubscribeId=E.default.subscribe(this.context,function(t){var n=e.theme;e.theme=t,e.attach(e.theme),e.setState({},function(){e.detach(n)})}))}},{key:"componentDidUpdate",value:function(){this.stylesCreatorSaved}},{key:"componentWillUnmount",value:function(){this.detach(this.theme),null!==this.unsubscribeId&&E.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"getClasses",value:function(){if(this.disableStylesGeneration)return this.props.classes||{};var e=!1,t=w.default.get(this.sheetsManager,this.stylesCreatorSaved,this.theme);return t.sheet.classes!==this.cacheClasses.lastJSS&&(this.cacheClasses.lastJSS=t.sheet.classes,e=!0),this.props.classes!==this.cacheClasses.lastProp&&(this.cacheClasses.lastProp=this.props.classes,e=!0),e&&(this.cacheClasses.value=(0,y.default)({baseClasses:this.cacheClasses.lastJSS,newClasses:this.props.classes,Component:n})),this.cacheClasses.value}},{key:"attach",value:function(e){if(!this.disableStylesGeneration){var t=this.stylesCreatorSaved,n=w.default.get(this.sheetsManager,t,e);if(n||(n={refs:0,sheet:null},w.default.set(this.sheetsManager,t,e,n)),0===n.refs){this.sheetsCache&&(r=w.default.get(this.sheetsCache,t,e)),!r&&((r=this.createSheet(e)).attach(),this.sheetsCache&&w.default.set(this.sheetsCache,t,e,r)),n.sheet=r;var r,i=this.context[g.default.sheetsRegistry];i&&i.add(r)}n.refs+=1}}},{key:"createSheet",value:function(e){var t=this.stylesCreatorSaved.create(e,S),r=S;return this.jss.createStyleSheet(t,(0,a.default)({meta:r,classNamePrefix:r,flip:"boolean"==typeof _?_:"rtl"===e.direction,link:!1},this.sheetOptions,this.stylesCreatorSaved.options,{name:S||n.displayName},I))}},{key:"detach",value:function(e){if(!this.disableStylesGeneration){var t=w.default.get(this.sheetsManager,this.stylesCreatorSaved,e);if(t.refs-=1,0===t.refs){w.default.delete(this.sheetsManager,this.stylesCreatorSaved,e),this.jss.removeStyleSheet(t.sheet);var n=this.context[g.default.sheetsRegistry];n&&n.remove(t.sheet)}}}},{key:"render",value:function(){var e=this.props,t=(e.classes,e.innerRef),r=(0,f.default)(e,["classes","innerRef"]),i=(0,x.default)({theme:this.theme,name:S,props:r});return m&&!i.theme&&(i.theme=this.theme),d.default.createElement(n,(0,a.default)({},i,{classes:this.getClasses(),ref:t}))}}]),t}(d.default.Component);return P.contextTypes=(0,a.default)((r={muiThemeProviderOptions:h.default.object},(0,i.default)(r,g.default.jss,h.default.object),(0,i.default)(r,g.default.sheetOptions,h.default.object),(0,i.default)(r,g.default.sheetsRegistry,h.default.object),r),N?E.default.contextTypes:{}),(0,p.default)(P,n),P}};b.ponyfillGlobal.__MUI_STYLES__||(b.ponyfillGlobal.__MUI_STYLES__={}),b.ponyfillGlobal.__MUI_STYLES__.withStyles||(b.ponyfillGlobal.__MUI_STYLES__.withStyles=I);var D=function(e,t){return b.ponyfillGlobal.__MUI_STYLES__.withStyles(e,(0,a.default)({defaultTheme:C},t))};t.default=D},82313(e,t,n){"use strict";var r,i=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=i(n(67154)),o=i(n(6479)),s=i(n(34575)),u=i(n(93913)),c=i(n(78585)),l=i(n(29754)),f=i(n(2205)),d=i(n(67294));i(n(45697));var h=i(n(8679)),p=n(55252),b=i(n(71615)),m=i(n(51067));function g(){return r||(r=(0,b.default)({typography:{suppressWarning:!0}}))}var v=function(){return function(e){var t=function(t){function n(e,t){var r;return(0,s.default)(this,n),(r=(0,c.default)(this,(0,l.default)(n).call(this))).state={theme:m.default.initial(t)||g()},r}return(0,f.default)(n,t),(0,u.default)(n,[{key:"componentDidMount",value:function(){var e=this;this.unsubscribeId=m.default.subscribe(this.context,function(t){e.setState({theme:t})})}},{key:"componentWillUnmount",value:function(){null!==this.unsubscribeId&&m.default.unsubscribe(this.context,this.unsubscribeId)}},{key:"render",value:function(){var t=this.props,n=t.innerRef,r=(0,o.default)(t,["innerRef"]);return d.default.createElement(e,(0,a.default)({theme:this.state.theme,ref:n},r))}}]),n}(d.default.Component);return t.contextTypes=m.default.contextTypes,(0,h.default)(t,e),t}};p.ponyfillGlobal.__MUI_STYLES__||(p.ponyfillGlobal.__MUI_STYLES__={}),p.ponyfillGlobal.__MUI_STYLES__.withTheme||(p.ponyfillGlobal.__MUI_STYLES__.withTheme=v);var y=p.ponyfillGlobal.__MUI_STYLES__.withTheme;t.default=y},88676(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n={mobileStepper:1e3,appBar:1100,drawer:1200,modal:1300,snackbar:1400,tooltip:1500};t.default=n},41929(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getTransitionProps=r,t.reflow=void 0;var n=function(e){return e.scrollTop};function r(e,t){var n=e.timeout,r=e.style,i=void 0===r?{}:r;return{duration:i.transitionDuration||"number"==typeof n?n:n[t.mode],delay:i.transitionDelay}}t.reflow=n},346(e,t){"use strict";function n(e,t){return function(){return null}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},98741(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.capitalize=a,t.contains=o,t.findIndex=s,t.find=u,t.createChainedFunction=c;var i=r(n(50008));function a(e){return e.charAt(0).toUpperCase()+e.slice(1)}function o(e,t){return Object.keys(t).every(function(n){return e.hasOwnProperty(n)&&e[n]===t[n]})}function s(e,t){for(var n=(0,i.default)(t),r=0;r-1?e[n]:void 0}function c(){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:window,n=(0,i.default)(e);return n.defaultView||n.parentView||t}var o=a;t.default=o},44370(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.cloneElementWithClassName=o,t.cloneChildrenWithClassName=s,t.isMuiElement=u,t.setRef=c;var i=r(n(67294)),a=r(n(94184));function o(e,t){return i.default.cloneElement(e,{className:(0,a.default)(e.props.className,t)})}function s(e,t){return i.default.Children.map(e,function(e){return i.default.isValidElement(e)&&o(e,t)})}function u(e,t){return i.default.isValidElement(e)&&-1!==t.indexOf(e.type.muiName)}function c(e,t){"function"==typeof e?e(t):e&&(e.current=t)}},47348(e,t){"use strict";function n(e){return function(){return null}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},21677(e,t){"use strict";function n(e,t,n,r,i){return null}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=n;t.default=r},78290(e,t,n){"use strict";var r=n(20862);Object.defineProperty(t,"__esModule",{value:!0});var i={};Object.defineProperty(t,"default",{enumerable:!0,get:function(){return a.default}});var a=r(n(88446));Object.keys(a).forEach(function(e){"default"!==e&&"__esModule"!==e&&(Object.prototype.hasOwnProperty.call(i,e)||Object.defineProperty(t,e,{enumerable:!0,get:function(){return a[e]}}))})},88446(e,t,n){"use strict";var r=n(95318);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.isWidthDown=t.isWidthUp=void 0;var i=r(n(67154)),a=r(n(6479)),o=r(n(34575)),s=r(n(93913)),u=r(n(78585)),c=r(n(29754)),l=r(n(2205)),f=r(n(67294));r(n(45697));var d=r(n(96421)),h=r(n(20296));n(55252);var p=r(n(8679)),b=r(n(82313)),m=n(94811),g=r(n(58057)),v=function(e,t){var n=!(arguments.length>2)||void 0===arguments[2]||arguments[2];return n?m.keys.indexOf(e)<=m.keys.indexOf(t):m.keys.indexOf(e)2)||void 0===arguments[2]||arguments[2];return n?m.keys.indexOf(t)<=m.keys.indexOf(e):m.keys.indexOf(t)0&&void 0!==arguments[0]?arguments[0]:{};return function(t){var n=e.withTheme,r=void 0!==n&&n,v=e.noSSR,y=void 0!==v&&v,w=e.initialWidth,_=e.resizeInterval,E=void 0===_?166:_,S=function(e){function n(e){var t;return(0,o.default)(this,n),(t=(0,u.default)(this,(0,c.default)(n).call(this,e))).state={width:y?t.getWidth():void 0},"undefined"!=typeof window&&(t.handleResize=(0,h.default)(function(){var e=t.getWidth();e!==t.state.width&&t.setState({width:e})},E)),t}return(0,l.default)(n,e),(0,s.default)(n,[{key:"componentDidMount",value:function(){var e=this.getWidth();e!==this.state.width&&this.setState({width:e})}},{key:"componentWillUnmount",value:function(){this.handleResize.clear()}},{key:"getWidth",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window.innerWidth,t=this.props.theme.breakpoints,n=null,r=1;null===n&&ri.Z,componentPropType:()=>r.Z,exactProp:()=>a.ZP,getDisplayName:()=>o.ZP,ponyfillGlobal:()=>s.Z});var r=n(78728),i=n(5477),a=n(43781),o=n(25189),s=n(34712);/** @license Material-UI v3.0.0-alpha.3 * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. @@ -181,7 +181,7 @@ object-assign * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */ Object.defineProperty(t,"__esModule",{value:!0}),"undefined"==typeof window||"function"!=typeof MessageChannel){var n,r,i,a,o,s=null,u=null,c=function(){if(null!==s)try{var e=t.unstable_now();s(!0,e),s=null}catch(n){throw setTimeout(c,0),n}},l=Date.now();t.unstable_now=function(){return Date.now()-l},n=function(e){null!==s?setTimeout(n,0,e):(s=e,setTimeout(c,0))},r=function(e,t){u=setTimeout(e,t)},i=function(){clearTimeout(u)},a=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var f=window.performance,d=window.Date,h=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var b=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!=typeof b&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if("object"==typeof f&&"function"==typeof f.now)t.unstable_now=function(){return f.now()};else{var m=d.now();t.unstable_now=function(){return d.now()-m}}var g=!1,v=null,y=-1,w=5,_=0;a=function(){return t.unstable_now()>=_},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125M(o,n))void 0!==u&&0>M(u,o)?(e[r]=u,e[s]=n,r=s):(e[r]=o,e[a]=n,r=a);else if(void 0!==u&&0>M(u,n))e[r]=u,e[s]=n,r=s;else break a}}return t}return null}function M(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var O=[],A=[],L=1,C=null,I=3,D=!1,N=!1,P=!1;function R(e){for(var t=x(A);null!==t;){if(null===t.callback)T(A);else if(t.startTime<=e)T(A),t.sortIndex=t.expirationTime,k(O,t);else break;t=x(A)}}function j(e){if(P=!1,R(e),!N){if(null!==x(O))N=!0,n(F);else{var t=x(A);null!==t&&r(j,t.startTime-e)}}}function F(e,n){N=!1,P&&(P=!1,i()),D=!0;var o=I;try{for(R(n),C=x(O);null!==C&&(!(C.expirationTime>n)||e&&!a());){var s=C.callback;if(null!==s){C.callback=null,I=C.priorityLevel;var u=s(C.expirationTime<=n);n=t.unstable_now(),"function"==typeof u?C.callback=u:C===x(O)&&T(O),R(n)}else T(O);C=x(O)}if(null!==C)var c=!0;else{var l=x(A);null!==l&&r(j,l.startTime-n),c=!1}return c}finally{C=null,I=o,D=!1}}function Y(e){switch(e){case 1:return -1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var B=o;t.unstable_ImmediatePriority=1,t.unstable_UserBlockingPriority=2,t.unstable_NormalPriority=3,t.unstable_IdlePriority=5,t.unstable_LowPriority=4,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_scheduleCallback=function(e,a,o){var s=t.unstable_now();if("object"==typeof o&&null!==o){var u=o.delay;u="number"==typeof u&&0s?(e.sortIndex=u,k(A,e),null===x(O)&&e===x(A)&&(P?i():P=!0,r(j,u-s))):(e.sortIndex=o,k(O,e),N||D||(N=!0,n(F))),e},t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_shouldYield=function(){var e=t.unstable_now();R(e);var n=x(O);return n!==C&&null!==C&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function c(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0}function l(e,t,n){if((192&t[0])!=128)return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if((192&t[1])!=128)return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&(192&t[2])!=128)return e.lastNeed=2,"�"}}function f(e){var t=this.lastTotal-this.lastNeed,n=l(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):void(e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length)}function d(e,t){var n=c(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function h(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�":t}function p(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function b(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function m(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function v(e){return e.toString(this.encoding)}function y(e){return e&&e.length?this.write(e):""}t.s=s,s.prototype.write=function(e){var t,n;if(0===e.length)return"";if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return nOB});var r,i,a,o,s,u,c,l=n(67294),f=n.t(l,2),d=n(97779),h=n(47886),p=n(57209),b=n(32316),m=n(95880),g=n(17051),v=n(71381),y=n(81701),w=n(3022),_=n(60323),E=n(87591),S=n(25649),k=n(28902),x=n(71426),T=n(48884),M=n(94184),O=n.n(M),A=n(55977),L=n(73935),C=function(){if("undefined"!=typeof Map)return Map;function e(e,t){var n=-1;return e.some(function(e,r){return e[0]===t&&(n=r,!0)}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(t){var n=e(this.__entries__,t),r=this.__entries__[n];return r&&r[1]},t.prototype.set=function(t,n){var r=e(this.__entries__,t);~r?this.__entries__[r][1]=n:this.__entries__.push([t,n])},t.prototype.delete=function(t){var n=this.__entries__,r=e(n,t);~r&&n.splice(r,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){void 0===t&&(t=null);for(var n=0,r=this.__entries__;n0},e.prototype.connect_=function(){I&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Y?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){I&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(e){var t=e.propertyName,n=void 0===t?"":t;F.some(function(e){return!!~n.indexOf(e)})&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),U=function(e,t){for(var n=0,r=Object.keys(t);n0},e}(),er="undefined"!=typeof WeakMap?new WeakMap:new C,ei=function(){function e(t){if(!(this instanceof e))throw TypeError("Cannot call a class as a function.");if(!arguments.length)throw TypeError("1 argument required, but only 0 present.");var n=B.getInstance(),r=new en(t,n,this);er.set(this,r)}return e}();["observe","unobserve","disconnect"].forEach(function(e){ei.prototype[e]=function(){var t;return(t=er.get(this))[e].apply(t,arguments)}});var ea=void 0!==D.ResizeObserver?D.ResizeObserver:ei;let eo=ea;var es=function(e){var t=[],n=null,r=function(){for(var r=arguments.length,i=Array(r),a=0;a=t||n<0||f&&r>=a}function g(){var e=eb();if(m(e))return v(e);s=setTimeout(g,b(e))}function v(e){return(s=void 0,d&&r)?h(e):(r=i=void 0,o)}function y(){void 0!==s&&clearTimeout(s),c=0,r=u=i=s=void 0}function w(){return void 0===s?o:v(eb())}function _(){var e=eb(),n=m(e);if(r=arguments,i=this,u=e,n){if(void 0===s)return p(u);if(f)return clearTimeout(s),s=setTimeout(g,t),h(u)}return void 0===s&&(s=setTimeout(g,t)),o}return t=ez(t)||0,ed(n)&&(l=!!n.leading,a=(f="maxWait"in n)?eW(ez(n.maxWait)||0,t):a,d="trailing"in n?!!n.trailing:d),_.cancel=y,_.flush=w,_}let eq=eV;var eZ="Expected a function";function eX(e,t,n){var r=!0,i=!0;if("function"!=typeof e)throw TypeError(eZ);return ed(n)&&(r="leading"in n?!!n.leading:r,i="trailing"in n?!!n.trailing:i),eq(e,t,{leading:r,maxWait:t,trailing:i})}let eJ=eX;var eQ={debounce:eq,throttle:eJ},e1=function(e){return eQ[e]},e0=function(e){return"function"==typeof e},e2=function(){return"undefined"==typeof window},e3=function(e){return e instanceof Element||e instanceof HTMLDocument};function e4(e){return(e4="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function e5(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function e6(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&l.createElement(tG.Z,{variant:"indeterminate",classes:r}))};tK.propTypes={fetchCount:el().number.isRequired};let tV=(0,b.withStyles)(tW)(tK);var tq=n(5536);let tZ=n.p+"ba8bbf16ebf8e1d05bef.svg";function tX(){return(tX=Object.assign||function(e){for(var t=1;t120){for(var d=Math.floor(u/80),h=u%80,p=[],b=0;b0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=s&&s.stack)?(Object.defineProperty(nf(b),"stack",{value:s.stack,writable:!0,configurable:!0}),nl(b)):(Error.captureStackTrace?Error.captureStackTrace(nf(b),n):Object.defineProperty(nf(b),"stack",{value:Error().stack,writable:!0,configurable:!0}),b)}return ns(n,[{key:"toString",value:function(){return nw(this)}},{key:t4.YF,get:function(){return"Object"}}]),n}(nd(Error));function ny(e){return void 0===e||0===e.length?void 0:e}function nw(e){var t=e.message;if(e.nodes)for(var n=0,r=e.nodes;n",EOF:"",BANG:"!",DOLLAR:"$",AMP:"&",PAREN_L:"(",PAREN_R:")",SPREAD:"...",COLON:":",EQUALS:"=",AT:"@",BRACKET_L:"[",BRACKET_R:"]",BRACE_L:"{",PIPE:"|",BRACE_R:"}",NAME:"Name",INT:"Int",FLOAT:"Float",STRING:"String",BLOCK_STRING:"BlockString",COMMENT:"Comment"}),nx=n(10143),nT=Object.freeze({QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",VARIABLE_DEFINITION:"VARIABLE_DEFINITION",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"}),nM=n(87392),nO=function(){function e(e){var t=new nS.WU(nk.SOF,0,0,0,0,null);this.source=e,this.lastToken=t,this.token=t,this.line=1,this.lineStart=0}var t=e.prototype;return t.advance=function(){return this.lastToken=this.token,this.token=this.lookahead()},t.lookahead=function(){var e,t=this.token;if(t.kind!==nk.EOF)do t=null!==(e=t.next)&&void 0!==e?e:t.next=nC(this,t);while(t.kind===nk.COMMENT)return t},e}();function nA(e){return e===nk.BANG||e===nk.DOLLAR||e===nk.AMP||e===nk.PAREN_L||e===nk.PAREN_R||e===nk.SPREAD||e===nk.COLON||e===nk.EQUALS||e===nk.AT||e===nk.BRACKET_L||e===nk.BRACKET_R||e===nk.BRACE_L||e===nk.PIPE||e===nk.BRACE_R}function nL(e){return isNaN(e)?nk.EOF:e<127?JSON.stringify(String.fromCharCode(e)):'"\\u'.concat(("00"+e.toString(16).toUpperCase()).slice(-4),'"')}function nC(e,t){for(var n=e.source,r=n.body,i=r.length,a=t.end;a31||9===a))return new nS.WU(nk.COMMENT,t,s,n,r,i,o.slice(t+1,s))}function nN(e,t,n,r,i,a){var o=e.body,s=n,u=t,c=!1;if(45===s&&(s=o.charCodeAt(++u)),48===s){if((s=o.charCodeAt(++u))>=48&&s<=57)throw n_(e,u,"Invalid number, unexpected digit after 0: ".concat(nL(s),"."))}else u=nP(e,u,s),s=o.charCodeAt(u);if(46===s&&(c=!0,s=o.charCodeAt(++u),u=nP(e,u,s),s=o.charCodeAt(u)),(69===s||101===s)&&(c=!0,(43===(s=o.charCodeAt(++u))||45===s)&&(s=o.charCodeAt(++u)),u=nP(e,u,s),s=o.charCodeAt(u)),46===s||nU(s))throw n_(e,u,"Invalid number, expected digit but got: ".concat(nL(s),"."));return new nS.WU(c?nk.FLOAT:nk.INT,t,u,r,i,a,o.slice(t,u))}function nP(e,t,n){var r=e.body,i=t,a=n;if(a>=48&&a<=57){do a=r.charCodeAt(++i);while(a>=48&&a<=57)return i}throw n_(e,i,"Invalid number, expected digit but got: ".concat(nL(a),"."))}function nR(e,t,n,r,i){for(var a=e.body,o=t+1,s=o,u=0,c="";o=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function nB(e,t,n,r,i){for(var a=e.body,o=a.length,s=t+1,u=0;s!==o&&!isNaN(u=a.charCodeAt(s))&&(95===u||u>=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122);)++s;return new nS.WU(nk.NAME,t,s,n,r,i,a.slice(t,s))}function nU(e){return 95===e||e>=65&&e<=90||e>=97&&e<=122}function nH(e,t){return new n$(e,t).parseDocument()}var n$=function(){function e(e,t){var n=(0,nx.T)(e)?e:new nx.H(e);this._lexer=new nO(n),this._options=t}var t=e.prototype;return t.parseName=function(){var e=this.expectToken(nk.NAME);return{kind:nE.h.NAME,value:e.value,loc:this.loc(e)}},t.parseDocument=function(){var e=this._lexer.token;return{kind:nE.h.DOCUMENT,definitions:this.many(nk.SOF,this.parseDefinition,nk.EOF),loc:this.loc(e)}},t.parseDefinition=function(){if(this.peek(nk.NAME))switch(this._lexer.token.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"schema":case"scalar":case"type":case"interface":case"union":case"enum":case"input":case"directive":return this.parseTypeSystemDefinition();case"extend":return this.parseTypeSystemExtension()}else if(this.peek(nk.BRACE_L))return this.parseOperationDefinition();else if(this.peekDescription())return this.parseTypeSystemDefinition();throw this.unexpected()},t.parseOperationDefinition=function(){var e,t=this._lexer.token;if(this.peek(nk.BRACE_L))return{kind:nE.h.OPERATION_DEFINITION,operation:"query",name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet(),loc:this.loc(t)};var n=this.parseOperationType();return this.peek(nk.NAME)&&(e=this.parseName()),{kind:nE.h.OPERATION_DEFINITION,operation:n,name:e,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseOperationType=function(){var e=this.expectToken(nk.NAME);switch(e.value){case"query":return"query";case"mutation":return"mutation";case"subscription":return"subscription"}throw this.unexpected(e)},t.parseVariableDefinitions=function(){return this.optionalMany(nk.PAREN_L,this.parseVariableDefinition,nk.PAREN_R)},t.parseVariableDefinition=function(){var e=this._lexer.token;return{kind:nE.h.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(nk.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(nk.EQUALS)?this.parseValueLiteral(!0):void 0,directives:this.parseDirectives(!0),loc:this.loc(e)}},t.parseVariable=function(){var e=this._lexer.token;return this.expectToken(nk.DOLLAR),{kind:nE.h.VARIABLE,name:this.parseName(),loc:this.loc(e)}},t.parseSelectionSet=function(){var e=this._lexer.token;return{kind:nE.h.SELECTION_SET,selections:this.many(nk.BRACE_L,this.parseSelection,nk.BRACE_R),loc:this.loc(e)}},t.parseSelection=function(){return this.peek(nk.SPREAD)?this.parseFragment():this.parseField()},t.parseField=function(){var e,t,n=this._lexer.token,r=this.parseName();return this.expectOptionalToken(nk.COLON)?(e=r,t=this.parseName()):t=r,{kind:nE.h.FIELD,alias:e,name:t,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(nk.BRACE_L)?this.parseSelectionSet():void 0,loc:this.loc(n)}},t.parseArguments=function(e){var t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(nk.PAREN_L,t,nk.PAREN_R)},t.parseArgument=function(){var e=this._lexer.token,t=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.ARGUMENT,name:t,value:this.parseValueLiteral(!1),loc:this.loc(e)}},t.parseConstArgument=function(){var e=this._lexer.token;return{kind:nE.h.ARGUMENT,name:this.parseName(),value:(this.expectToken(nk.COLON),this.parseValueLiteral(!0)),loc:this.loc(e)}},t.parseFragment=function(){var e=this._lexer.token;this.expectToken(nk.SPREAD);var t=this.expectOptionalKeyword("on");return!t&&this.peek(nk.NAME)?{kind:nE.h.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1),loc:this.loc(e)}:{kind:nE.h.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}},t.parseFragmentDefinition=function(){var e,t=this._lexer.token;return(this.expectKeyword("fragment"),(null===(e=this._options)||void 0===e?void 0:e.experimentalFragmentVariables)===!0)?{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}:{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseFragmentName=function(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()},t.parseValueLiteral=function(e){var t=this._lexer.token;switch(t.kind){case nk.BRACKET_L:return this.parseList(e);case nk.BRACE_L:return this.parseObject(e);case nk.INT:return this._lexer.advance(),{kind:nE.h.INT,value:t.value,loc:this.loc(t)};case nk.FLOAT:return this._lexer.advance(),{kind:nE.h.FLOAT,value:t.value,loc:this.loc(t)};case nk.STRING:case nk.BLOCK_STRING:return this.parseStringLiteral();case nk.NAME:switch(this._lexer.advance(),t.value){case"true":return{kind:nE.h.BOOLEAN,value:!0,loc:this.loc(t)};case"false":return{kind:nE.h.BOOLEAN,value:!1,loc:this.loc(t)};case"null":return{kind:nE.h.NULL,loc:this.loc(t)};default:return{kind:nE.h.ENUM,value:t.value,loc:this.loc(t)}}case nk.DOLLAR:if(!e)return this.parseVariable()}throw this.unexpected()},t.parseStringLiteral=function(){var e=this._lexer.token;return this._lexer.advance(),{kind:nE.h.STRING,value:e.value,block:e.kind===nk.BLOCK_STRING,loc:this.loc(e)}},t.parseList=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseValueLiteral(e)};return{kind:nE.h.LIST,values:this.any(nk.BRACKET_L,r,nk.BRACKET_R),loc:this.loc(n)}},t.parseObject=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseObjectField(e)};return{kind:nE.h.OBJECT,fields:this.any(nk.BRACE_L,r,nk.BRACE_R),loc:this.loc(n)}},t.parseObjectField=function(e){var t=this._lexer.token,n=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e),loc:this.loc(t)}},t.parseDirectives=function(e){for(var t=[];this.peek(nk.AT);)t.push(this.parseDirective(e));return t},t.parseDirective=function(e){var t=this._lexer.token;return this.expectToken(nk.AT),{kind:nE.h.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e),loc:this.loc(t)}},t.parseTypeReference=function(){var e,t=this._lexer.token;return(this.expectOptionalToken(nk.BRACKET_L)?(e=this.parseTypeReference(),this.expectToken(nk.BRACKET_R),e={kind:nE.h.LIST_TYPE,type:e,loc:this.loc(t)}):e=this.parseNamedType(),this.expectOptionalToken(nk.BANG))?{kind:nE.h.NON_NULL_TYPE,type:e,loc:this.loc(t)}:e},t.parseNamedType=function(){var e=this._lexer.token;return{kind:nE.h.NAMED_TYPE,name:this.parseName(),loc:this.loc(e)}},t.parseTypeSystemDefinition=function(){var e=this.peekDescription()?this._lexer.lookahead():this._lexer.token;if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}throw this.unexpected(e)},t.peekDescription=function(){return this.peek(nk.STRING)||this.peek(nk.BLOCK_STRING)},t.parseDescription=function(){if(this.peekDescription())return this.parseStringLiteral()},t.parseSchemaDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");var n=this.parseDirectives(!0),r=this.many(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);return{kind:nE.h.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r,loc:this.loc(e)}},t.parseOperationTypeDefinition=function(){var e=this._lexer.token,t=this.parseOperationType();this.expectToken(nk.COLON);var n=this.parseNamedType();return{kind:nE.h.OPERATION_TYPE_DEFINITION,operation:t,type:n,loc:this.loc(e)}},t.parseScalarTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");var n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseImplementsInterfaces=function(){var e;if(!this.expectOptionalKeyword("implements"))return[];if((null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLImplementsInterfaces)===!0){var t=[];this.expectOptionalToken(nk.AMP);do t.push(this.parseNamedType());while(this.expectOptionalToken(nk.AMP)||this.peek(nk.NAME))return t}return this.delimitedMany(nk.AMP,this.parseNamedType)},t.parseFieldsDefinition=function(){var e;return(null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLEmptyFields)===!0&&this.peek(nk.BRACE_L)&&this._lexer.lookahead().kind===nk.BRACE_R?(this._lexer.advance(),this._lexer.advance(),[]):this.optionalMany(nk.BRACE_L,this.parseFieldDefinition,nk.BRACE_R)},t.parseFieldDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(nk.COLON);var i=this.parseTypeReference(),a=this.parseDirectives(!0);return{kind:nE.h.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:a,loc:this.loc(e)}},t.parseArgumentDefs=function(){return this.optionalMany(nk.PAREN_L,this.parseInputValueDef,nk.PAREN_R)},t.parseInputValueDef=function(){var e,t=this._lexer.token,n=this.parseDescription(),r=this.parseName();this.expectToken(nk.COLON);var i=this.parseTypeReference();this.expectOptionalToken(nk.EQUALS)&&(e=this.parseValueLiteral(!0));var a=this.parseDirectives(!0);return{kind:nE.h.INPUT_VALUE_DEFINITION,description:n,name:r,type:i,defaultValue:e,directives:a,loc:this.loc(t)}},t.parseInterfaceTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseUnionTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseUnionMemberTypes();return{kind:nE.h.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i,loc:this.loc(e)}},t.parseUnionMemberTypes=function(){return this.expectOptionalToken(nk.EQUALS)?this.delimitedMany(nk.PIPE,this.parseNamedType):[]},t.parseEnumTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseEnumValuesDefinition();return{kind:nE.h.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i,loc:this.loc(e)}},t.parseEnumValuesDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseEnumValueDefinition,nk.BRACE_R)},t.parseEnumValueDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseInputObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseInputFieldsDefinition();return{kind:nE.h.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInputFieldsDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseInputValueDef,nk.BRACE_R)},t.parseTypeSystemExtension=function(){var e=this._lexer.lookahead();if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)},t.parseSchemaExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");var t=this.parseDirectives(!0),n=this.optionalMany(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return{kind:nE.h.SCHEMA_EXTENSION,directives:t,operationTypes:n,loc:this.loc(e)}},t.parseScalarTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");var t=this.parseName(),n=this.parseDirectives(!0);if(0===n.length)throw this.unexpected();return{kind:nE.h.SCALAR_TYPE_EXTENSION,name:t,directives:n,loc:this.loc(e)}},t.parseObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInterfaceTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseUnionTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.UNION_TYPE_EXTENSION,name:t,directives:n,types:r,loc:this.loc(e)}},t.parseEnumTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r,loc:this.loc(e)}},t.parseInputObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r,loc:this.loc(e)}},t.parseDirectiveDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(nk.AT);var n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");var a=this.parseDirectiveLocations();return{kind:nE.h.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:a,loc:this.loc(e)}},t.parseDirectiveLocations=function(){return this.delimitedMany(nk.PIPE,this.parseDirectiveLocation)},t.parseDirectiveLocation=function(){var e=this._lexer.token,t=this.parseName();if(void 0!==nT[t.value])return t;throw this.unexpected(e)},t.loc=function(e){var t;if((null===(t=this._options)||void 0===t?void 0:t.noLocation)!==!0)return new nS.Ye(e,this._lexer.lastToken,this._lexer.source)},t.peek=function(e){return this._lexer.token.kind===e},t.expectToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw n_(this._lexer.source,t.start,"Expected ".concat(nG(e),", found ").concat(nz(t),"."))},t.expectOptionalToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t},t.expectKeyword=function(e){var t=this._lexer.token;if(t.kind===nk.NAME&&t.value===e)this._lexer.advance();else throw n_(this._lexer.source,t.start,'Expected "'.concat(e,'", found ').concat(nz(t),"."))},t.expectOptionalKeyword=function(e){var t=this._lexer.token;return t.kind===nk.NAME&&t.value===e&&(this._lexer.advance(),!0)},t.unexpected=function(e){var t=null!=e?e:this._lexer.token;return n_(this._lexer.source,t.start,"Unexpected ".concat(nz(t),"."))},t.any=function(e,t,n){this.expectToken(e);for(var r=[];!this.expectOptionalToken(n);)r.push(t.call(this));return r},t.optionalMany=function(e,t,n){if(this.expectOptionalToken(e)){var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r}return[]},t.many=function(e,t,n){this.expectToken(e);var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r},t.delimitedMany=function(e,t){this.expectOptionalToken(e);var n=[];do n.push(t.call(this));while(this.expectOptionalToken(e))return n},e}();function nz(e){var t=e.value;return nG(e.kind)+(null!=t?' "'.concat(t,'"'):"")}function nG(e){return nA(e)?'"'.concat(e,'"'):e}var nW=new Map,nK=new Map,nV=!0,nq=!1;function nZ(e){return e.replace(/[\s,]+/g," ").trim()}function nX(e){return nZ(e.source.body.substring(e.start,e.end))}function nJ(e){var t=new Set,n=[];return e.definitions.forEach(function(e){if("FragmentDefinition"===e.kind){var r=e.name.value,i=nX(e.loc),a=nK.get(r);a&&!a.has(i)?nV&&console.warn("Warning: fragment with name "+r+" already exists.\ngraphql-tag enforces all fragment names across your application to be unique; read more about\nthis in the docs: http://dev.apollodata.com/core/fragments.html#unique-names"):a||nK.set(r,a=new Set),a.add(i),t.has(i)||(t.add(i),n.push(e))}else n.push(e)}),(0,t0.pi)((0,t0.pi)({},e),{definitions:n})}function nQ(e){var t=new Set(e.definitions);t.forEach(function(e){e.loc&&delete e.loc,Object.keys(e).forEach(function(n){var r=e[n];r&&"object"==typeof r&&t.add(r)})});var n=e.loc;return n&&(delete n.startToken,delete n.endToken),e}function n1(e){var t=nZ(e);if(!nW.has(t)){var n=nH(e,{experimentalFragmentVariables:nq,allowLegacyFragmentVariables:nq});if(!n||"Document"!==n.kind)throw Error("Not a valid GraphQL document.");nW.set(t,nQ(nJ(n)))}return nW.get(t)}function n0(e){for(var t=[],n=1;n, or pass an ApolloClient instance in via options.'):(0,n7.kG)(!!n,32),n}var rb=n(10542),rm=n(53712),rg=n(21436),rv=Object.prototype.hasOwnProperty;function ry(e,t){return void 0===t&&(t=Object.create(null)),rw(rp(t.client),e).useQuery(t)}function rw(e,t){var n=(0,l.useRef)();n.current&&e===n.current.client&&t===n.current.query||(n.current=new r_(e,t,n.current));var r=n.current,i=(0,l.useState)(0),a=(i[0],i[1]);return r.forceUpdate=function(){a(function(e){return e+1})},r}var r_=function(){function e(e,t,n){this.client=e,this.query=t,this.ssrDisabledResult=(0,rb.J)({loading:!0,data:void 0,error:void 0,networkStatus:rc.I.loading}),this.skipStandbyResult=(0,rb.J)({loading:!1,data:void 0,error:void 0,networkStatus:rc.I.ready}),this.toQueryResultCache=new(re.mr?WeakMap:Map),rh(t,r.Query);var i=n&&n.result,a=i&&i.data;a&&(this.previousData=a)}return e.prototype.forceUpdate=function(){__DEV__&&n7.kG.warn("Calling default no-op implementation of InternalState#forceUpdate")},e.prototype.executeQuery=function(e){var t,n=this;e.query&&Object.assign(this,{query:e.query}),this.watchQueryOptions=this.createWatchQueryOptions(this.queryHookOptions=e);var r=this.observable.reobserveAsConcast(this.getObsQueryOptions());return this.previousData=(null===(t=this.result)||void 0===t?void 0:t.data)||this.previousData,this.result=void 0,this.forceUpdate(),new Promise(function(e){var t;r.subscribe({next:function(e){t=e},error:function(){e(n.toQueryResult(n.observable.getCurrentResult()))},complete:function(){e(n.toQueryResult(t))}})})},e.prototype.useQuery=function(e){var t=this;this.renderPromises=(0,l.useContext)((0,rs.K)()).renderPromises,this.useOptions(e);var n=this.useObservableQuery(),r=rn((0,l.useCallback)(function(){if(t.renderPromises)return function(){};var e=function(){var e=t.result,r=n.getCurrentResult();!(e&&e.loading===r.loading&&e.networkStatus===r.networkStatus&&(0,ra.D)(e.data,r.data))&&t.setResult(r)},r=function(a){var o=n.last;i.unsubscribe();try{n.resetLastResults(),i=n.subscribe(e,r)}finally{n.last=o}if(!rv.call(a,"graphQLErrors"))throw a;var s=t.result;(!s||s&&s.loading||!(0,ra.D)(a,s.error))&&t.setResult({data:s&&s.data,error:a,loading:!1,networkStatus:rc.I.error})},i=n.subscribe(e,r);return function(){return setTimeout(function(){return i.unsubscribe()})}},[n,this.renderPromises,this.client.disableNetworkFetches,]),function(){return t.getCurrentResult()},function(){return t.getCurrentResult()});return this.unsafeHandlePartialRefetch(r),this.toQueryResult(r)},e.prototype.useOptions=function(t){var n,r=this.createWatchQueryOptions(this.queryHookOptions=t),i=this.watchQueryOptions;!(0,ra.D)(r,i)&&(this.watchQueryOptions=r,i&&this.observable&&(this.observable.reobserve(this.getObsQueryOptions()),this.previousData=(null===(n=this.result)||void 0===n?void 0:n.data)||this.previousData,this.result=void 0)),this.onCompleted=t.onCompleted||e.prototype.onCompleted,this.onError=t.onError||e.prototype.onError,(this.renderPromises||this.client.disableNetworkFetches)&&!1===this.queryHookOptions.ssr&&!this.queryHookOptions.skip?this.result=this.ssrDisabledResult:this.queryHookOptions.skip||"standby"===this.watchQueryOptions.fetchPolicy?this.result=this.skipStandbyResult:(this.result===this.ssrDisabledResult||this.result===this.skipStandbyResult)&&(this.result=void 0)},e.prototype.getObsQueryOptions=function(){var e=[],t=this.client.defaultOptions.watchQuery;return t&&e.push(t),this.queryHookOptions.defaultOptions&&e.push(this.queryHookOptions.defaultOptions),e.push((0,rm.o)(this.observable&&this.observable.options,this.watchQueryOptions)),e.reduce(ro.J)},e.prototype.createWatchQueryOptions=function(e){void 0===e&&(e={});var t,n=e.skip,r=Object.assign((e.ssr,e.onCompleted,e.onError,e.defaultOptions,(0,n8._T)(e,["skip","ssr","onCompleted","onError","defaultOptions"])),{query:this.query});if(this.renderPromises&&("network-only"===r.fetchPolicy||"cache-and-network"===r.fetchPolicy)&&(r.fetchPolicy="cache-first"),r.variables||(r.variables={}),n){var i=r.fetchPolicy,a=void 0===i?this.getDefaultFetchPolicy():i,o=r.initialFetchPolicy;Object.assign(r,{initialFetchPolicy:void 0===o?a:o,fetchPolicy:"standby"})}else r.fetchPolicy||(r.fetchPolicy=(null===(t=this.observable)||void 0===t?void 0:t.options.initialFetchPolicy)||this.getDefaultFetchPolicy());return r},e.prototype.getDefaultFetchPolicy=function(){var e,t;return(null===(e=this.queryHookOptions.defaultOptions)||void 0===e?void 0:e.fetchPolicy)||(null===(t=this.client.defaultOptions.watchQuery)||void 0===t?void 0:t.fetchPolicy)||"cache-first"},e.prototype.onCompleted=function(e){},e.prototype.onError=function(e){},e.prototype.useObservableQuery=function(){var e=this.observable=this.renderPromises&&this.renderPromises.getSSRObservable(this.watchQueryOptions)||this.observable||this.client.watchQuery(this.getObsQueryOptions());this.obsQueryFields=(0,l.useMemo)(function(){return{refetch:e.refetch.bind(e),reobserve:e.reobserve.bind(e),fetchMore:e.fetchMore.bind(e),updateQuery:e.updateQuery.bind(e),startPolling:e.startPolling.bind(e),stopPolling:e.stopPolling.bind(e),subscribeToMore:e.subscribeToMore.bind(e)}},[e]);var t=!(!1===this.queryHookOptions.ssr||this.queryHookOptions.skip);return this.renderPromises&&t&&(this.renderPromises.registerSSRObservable(e),e.getCurrentResult().loading&&this.renderPromises.addObservableQueryPromise(e)),e},e.prototype.setResult=function(e){var t=this.result;t&&t.data&&(this.previousData=t.data),this.result=e,this.forceUpdate(),this.handleErrorOrCompleted(e)},e.prototype.handleErrorOrCompleted=function(e){var t=this;if(!e.loading){var n=this.toApolloError(e);Promise.resolve().then(function(){n?t.onError(n):e.data&&t.onCompleted(e.data)}).catch(function(e){__DEV__&&n7.kG.warn(e)})}},e.prototype.toApolloError=function(e){return(0,rg.O)(e.errors)?new ru.cA({graphQLErrors:e.errors}):e.error},e.prototype.getCurrentResult=function(){return this.result||this.handleErrorOrCompleted(this.result=this.observable.getCurrentResult()),this.result},e.prototype.toQueryResult=function(e){var t=this.toQueryResultCache.get(e);if(t)return t;var n=e.data,r=(e.partial,(0,n8._T)(e,["data","partial"]));return this.toQueryResultCache.set(e,t=(0,n8.pi)((0,n8.pi)((0,n8.pi)({data:n},r),this.obsQueryFields),{client:this.client,observable:this.observable,variables:this.observable.variables,called:!this.queryHookOptions.skip,previousData:this.previousData})),!t.error&&(0,rg.O)(e.errors)&&(t.error=new ru.cA({graphQLErrors:e.errors})),t},e.prototype.unsafeHandlePartialRefetch=function(e){e.partial&&this.queryHookOptions.partialRefetch&&!e.loading&&(!e.data||0===Object.keys(e.data).length)&&"cache-only"!==this.observable.options.fetchPolicy&&(Object.assign(e,{loading:!0,networkStatus:rc.I.refetch}),this.observable.refetch())},e}();function rE(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:{};return ry(i$,e)},iG=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"50",10),r=iz({variables:{offset:(t-1)*n,limit:n},fetchPolicy:"network-only"}),i=r.data,a=r.loading,o=r.error;return a?l.createElement(ij,null):o?l.createElement(iN,{error:o}):i?l.createElement(iD,{chains:i.chains.results,page:t,pageSize:n,total:i.chains.metadata.total}):null},iW=n(67932),iK=n(8126),iV="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function iq(e){if(iZ())return Intl.DateTimeFormat.supportedLocalesOf(e)[0]}function iZ(){return("undefined"==typeof Intl?"undefined":iV(Intl))==="object"&&"function"==typeof Intl.DateTimeFormat}var iX="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},iJ=function(){function e(e,t){for(var n=0;n=i.length)break;s=i[o++]}else{if((o=i.next()).done)break;s=o.value}var s,u=s;if((void 0===e?"undefined":iX(e))!=="object")return;e=e[u]}return e}},{key:"put",value:function(){for(var e=arguments.length,t=Array(e),n=0;n=o.length)break;c=o[u++]}else{if((u=o.next()).done)break;c=u.value}var c,l=c;"object"!==iX(a[l])&&(a[l]={}),a=a[l]}return a[i]=r}}]),e}();let i0=i1;var i2=new i0;function i3(e,t){if(!iZ())return function(e){return e.toString()};var n=i5(e),r=JSON.stringify(t),i=i2.get(String(n),r)||i2.put(String(n),r,new Intl.DateTimeFormat(n,t));return function(e){return i.format(e)}}var i4={};function i5(e){var t=e.toString();return i4[t]?i4[t]:i4[t]=iq(e)}var i6="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function i9(e){return i8(e)?e:new Date(e)}function i8(e){return e instanceof Date||i7(e)}function i7(e){return(void 0===e?"undefined":i6(e))==="object"&&"function"==typeof e.getTime}var ae=n(54087),at=n.n(ae);function an(e,t){if(0===e.length)return 0;for(var n=0,r=e.length-1,i=void 0;n<=r;){var a=t(e[i=Math.floor((r+n)/2)]);if(0===a)return i;if(a<0){if((n=i+1)>r)return n}else if((r=i-1)=t.nextUpdateTime)ao(t,this.instances);else break}},scheduleNextTick:function(){var e=this;this.scheduledTick=at()(function(){e.tick(),e.scheduleNextTick()})},start:function(){this.scheduleNextTick()},stop:function(){at().cancel(this.scheduledTick)}};function aa(e){var t=ar(e.getNextValue(),2),n=t[0],r=t[1];e.setValue(n),e.nextUpdateTime=r}function ao(e,t){aa(e),au(t,e),as(t,e)}function as(e,t){var n=ac(e,t);e.splice(n,0,t)}function au(e,t){var n=e.indexOf(t);e.splice(n,1)}function ac(e,t){var n=t.nextUpdateTime;return an(e,function(e){return e.nextUpdateTime===n?0:e.nextUpdateTime>n?1:-1})}var al=(0,ec.oneOfType)([(0,ec.shape)({minTime:ec.number,formatAs:ec.string.isRequired}),(0,ec.shape)({test:ec.func,formatAs:ec.string.isRequired}),(0,ec.shape)({minTime:ec.number,format:ec.func.isRequired}),(0,ec.shape)({test:ec.func,format:ec.func.isRequired})]),af=(0,ec.oneOfType)([ec.string,(0,ec.shape)({steps:(0,ec.arrayOf)(al).isRequired,labels:(0,ec.oneOfType)([ec.string,(0,ec.arrayOf)(ec.string)]).isRequired,round:ec.string})]),ad=Object.assign||function(e){for(var t=1;t=0)&&Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function ab(e){var t=e.date,n=e.future,r=e.timeStyle,i=e.round,a=e.minTimeLeft,o=e.tooltip,s=e.component,u=e.container,c=e.wrapperComponent,f=e.wrapperProps,d=e.locale,h=e.locales,p=e.formatVerboseDate,b=e.verboseDateFormat,m=e.updateInterval,g=e.tick,v=ap(e,["date","future","timeStyle","round","minTimeLeft","tooltip","component","container","wrapperComponent","wrapperProps","locale","locales","formatVerboseDate","verboseDateFormat","updateInterval","tick"]),y=(0,l.useMemo)(function(){return d&&(h=[d]),h.concat(iK.Z.getDefaultLocale())},[d,h]),w=(0,l.useMemo)(function(){return new iK.Z(y)},[y]);t=(0,l.useMemo)(function(){return i9(t)},[t]);var _=(0,l.useCallback)(function(){var e=Date.now(),o=void 0;if(n&&e>=t.getTime()&&(e=t.getTime(),o=!0),void 0!==a){var s=t.getTime()-1e3*a;e>s&&(e=s,o=!0)}var u=w.format(t,r,{getTimeToNextUpdate:!0,now:e,future:n,round:i}),c=ah(u,2),l=c[0],f=c[1];return f=o?av:m||f||6e4,[l,e+f]},[t,n,r,m,i,a,w]),E=(0,l.useRef)();E.current=_;var S=(0,l.useMemo)(_,[]),k=ah(S,2),x=k[0],T=k[1],M=(0,l.useState)(x),O=ah(M,2),A=O[0],L=O[1],C=ah((0,l.useState)(),2),I=C[0],D=C[1],N=(0,l.useRef)();(0,l.useEffect)(function(){if(g)return N.current=ai.add({getNextValue:function(){return E.current()},setValue:L,nextUpdateTime:T}),function(){return N.current.stop()}},[g]),(0,l.useEffect)(function(){if(N.current)N.current.forceUpdate();else{var e=_(),t=ah(e,1)[0];L(t)}},[_]),(0,l.useEffect)(function(){D(!0)},[]);var P=(0,l.useMemo)(function(){if("undefined"!=typeof window)return i3(y,b)},[y,b]),R=(0,l.useMemo)(function(){if("undefined"!=typeof window)return p?p(t):P(t)},[t,p,P]),j=l.createElement(s,ad({date:t,verboseDate:I?R:void 0,tooltip:o},v),A),F=c||u;return F?l.createElement(F,ad({},f,{verboseDate:I?R:void 0}),j):j}ab.propTypes={date:el().oneOfType([el().instanceOf(Date),el().number]).isRequired,locale:el().string,locales:el().arrayOf(el().string),future:el().bool,timeStyle:af,round:el().string,minTimeLeft:el().number,component:el().elementType.isRequired,tooltip:el().bool.isRequired,formatVerboseDate:el().func,verboseDateFormat:el().object,updateInterval:el().oneOfType([el().number,el().arrayOf(el().shape({threshold:el().number,interval:el().number.isRequired}))]),tick:el().bool,wrapperComponent:el().func,wrapperProps:el().object},ab.defaultProps={locales:[],component:ay,tooltip:!0,verboseDateFormat:{weekday:"long",day:"numeric",month:"long",year:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit"},tick:!0},ab=l.memo(ab);let am=ab;var ag,av=31536e9;function ay(e){var t=e.date,n=e.verboseDate,r=e.tooltip,i=e.children,a=ap(e,["date","verboseDate","tooltip","children"]),o=(0,l.useMemo)(function(){return t.toISOString()},[t]);return l.createElement("time",ad({},a,{dateTime:o,title:r?n:void 0}),i)}ay.propTypes={date:el().instanceOf(Date).isRequired,verboseDate:el().string,tooltip:el().bool.isRequired,children:el().string.isRequired};var aw=n(30381),a_=n.n(aw),aE=n(31657);function aS(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ak(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0?new ru.cA({graphQLErrors:i}):void 0;if(u===s.current.mutationId&&!c.ignoreResults){var f={called:!0,loading:!1,data:r,error:l,client:a};s.current.isMounted&&!(0,ra.D)(s.current.result,f)&&o(s.current.result=f)}var d=e.onCompleted||(null===(n=s.current.options)||void 0===n?void 0:n.onCompleted);return null==d||d(t.data,c),t}).catch(function(t){if(u===s.current.mutationId&&s.current.isMounted){var n,r={loading:!1,error:t,data:void 0,called:!0,client:a};(0,ra.D)(s.current.result,r)||o(s.current.result=r)}var i=e.onError||(null===(n=s.current.options)||void 0===n?void 0:n.onError);if(i)return i(t,c),{data:void 0,errors:t};throw t})},[]),c=(0,l.useCallback)(function(){s.current.isMounted&&o({called:!1,loading:!1,client:n})},[]);return(0,l.useEffect)(function(){return s.current.isMounted=!0,function(){s.current.isMounted=!1}},[]),[u,(0,n8.pi)({reset:c},a)]}var ou=n(59067),oc=n(28428),ol=n(11186),of=n(78513);function od(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var oh=function(e){return(0,b.createStyles)({paper:{display:"flex",margin:"".concat(2.5*e.spacing.unit,"px 0"),padding:"".concat(3*e.spacing.unit,"px ").concat(3.5*e.spacing.unit,"px")},content:{flex:1,width:"100%"},actions:od({marginTop:-(1.5*e.spacing.unit),marginLeft:-(4*e.spacing.unit)},e.breakpoints.up("sm"),{marginLeft:0,marginRight:-(1.5*e.spacing.unit)}),itemBlock:{border:"1px solid rgba(224, 224, 224, 1)",borderRadius:e.shape.borderRadius,padding:2*e.spacing.unit,marginTop:e.spacing.unit},itemBlockText:{overflowWrap:"anywhere"}})},op=(0,b.withStyles)(oh)(function(e){var t=e.actions,n=e.children,r=e.classes;return l.createElement(ia.default,{className:r.paper},l.createElement("div",{className:r.content},n),t&&l.createElement("div",{className:r.actions},t))}),ob=function(e){var t=e.title;return l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},t)},om=function(e){var t=e.children,n=e.value;return l.createElement(x.default,{variant:"body1",noWrap:!0},t||n)},og=(0,b.withStyles)(oh)(function(e){var t=e.children,n=e.classes,r=e.value;return l.createElement("div",{className:n.itemBlock},l.createElement(x.default,{variant:"body1",className:n.itemBlockText},t||r))});function ov(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]-1}let sZ=sq;function sX(e,t){var n=this.__data__,r=s$(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this}let sJ=sX;function sQ(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e-1&&e%1==0&&e<=cI}let cN=cD;var cP="[object Arguments]",cR="[object Array]",cj="[object Boolean]",cF="[object Date]",cY="[object Error]",cB="[object Function]",cU="[object Map]",cH="[object Number]",c$="[object Object]",cz="[object RegExp]",cG="[object Set]",cW="[object String]",cK="[object WeakMap]",cV="[object ArrayBuffer]",cq="[object DataView]",cZ="[object Float64Array]",cX="[object Int8Array]",cJ="[object Int16Array]",cQ="[object Int32Array]",c1="[object Uint8Array]",c0="[object Uint8ClampedArray]",c2="[object Uint16Array]",c3="[object Uint32Array]",c4={};function c5(e){return eD(e)&&cN(e.length)&&!!c4[eC(e)]}c4["[object Float32Array]"]=c4[cZ]=c4[cX]=c4[cJ]=c4[cQ]=c4[c1]=c4[c0]=c4[c2]=c4[c3]=!0,c4[cP]=c4[cR]=c4[cV]=c4[cj]=c4[cq]=c4[cF]=c4[cY]=c4[cB]=c4[cU]=c4[cH]=c4[c$]=c4[cz]=c4[cG]=c4[cW]=c4[cK]=!1;let c6=c5;function c9(e){return function(t){return e(t)}}let c8=c9;var c7=n(79730),le=c7.Z&&c7.Z.isTypedArray,lt=le?c8(le):c6;let ln=lt;var lr=Object.prototype.hasOwnProperty;function li(e,t){var n=cT(e),r=!n&&ck(e),i=!n&&!r&&(0,cM.Z)(e),a=!n&&!r&&!i&&ln(e),o=n||r||i||a,s=o?cm(e.length,String):[],u=s.length;for(var c in e)(t||lr.call(e,c))&&!(o&&("length"==c||i&&("offset"==c||"parent"==c)||a&&("buffer"==c||"byteLength"==c||"byteOffset"==c)||cC(c,u)))&&s.push(c);return s}let la=li;var lo=Object.prototype;function ls(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||lo)}let lu=ls;var lc=sM(Object.keys,Object);let ll=lc;var lf=Object.prototype.hasOwnProperty;function ld(e){if(!lu(e))return ll(e);var t=[];for(var n in Object(e))lf.call(e,n)&&"constructor"!=n&&t.push(n);return t}let lh=ld;function lp(e){return null!=e&&cN(e.length)&&!ui(e)}let lb=lp;function lm(e){return lb(e)?la(e):lh(e)}let lg=lm;function lv(e,t){return e&&cp(t,lg(t),e)}let ly=lv;function lw(e){var t=[];if(null!=e)for(var n in Object(e))t.push(n);return t}let l_=lw;var lE=Object.prototype.hasOwnProperty;function lS(e){if(!ed(e))return l_(e);var t=lu(e),n=[];for(var r in e)"constructor"==r&&(t||!lE.call(e,r))||n.push(r);return n}let lk=lS;function lx(e){return lb(e)?la(e,!0):lk(e)}let lT=lx;function lM(e,t){return e&&cp(t,lT(t),e)}let lO=lM;var lA=n(42896);function lL(e,t){var n=-1,r=e.length;for(t||(t=Array(r));++n=0||(i[n]=e[n]);return i}function hc(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}var hl=function(e){return Array.isArray(e)&&0===e.length},hf=function(e){return"function"==typeof e},hd=function(e){return null!==e&&"object"==typeof e},hh=function(e){return String(Math.floor(Number(e)))===e},hp=function(e){return"[object String]"===Object.prototype.toString.call(e)},hb=function(e){return 0===l.Children.count(e)},hm=function(e){return hd(e)&&hf(e.then)};function hg(e,t,n,r){void 0===r&&(r=0);for(var i=d8(t);e&&r=0?[]:{}}}return(0===a?e:i)[o[a]]===n?e:(void 0===n?delete i[o[a]]:i[o[a]]=n,0===a&&void 0===n&&delete r[o[a]],r)}function hy(e,t,n,r){void 0===n&&(n=new WeakMap),void 0===r&&(r={});for(var i=0,a=Object.keys(e);i0?t.map(function(t){return x(t,hg(e,t))}):[Promise.resolve("DO_NOT_DELETE_YOU_WILL_BE_FIRED")]).then(function(e){return e.reduce(function(e,n,r){return"DO_NOT_DELETE_YOU_WILL_BE_FIRED"===n||n&&(e=hv(e,t[r],n)),e},{})})},[x]),M=(0,l.useCallback)(function(e){return Promise.all([T(e),h.validationSchema?k(e):{},h.validate?S(e):{}]).then(function(e){var t=e[0],n=e[1],r=e[2];return sx.all([t,n,r],{arrayMerge:hC})})},[h.validate,h.validationSchema,T,S,k]),O=hP(function(e){return void 0===e&&(e=_.values),E({type:"SET_ISVALIDATING",payload:!0}),M(e).then(function(e){return v.current&&(E({type:"SET_ISVALIDATING",payload:!1}),sh()(_.errors,e)||E({type:"SET_ERRORS",payload:e})),e})});(0,l.useEffect)(function(){o&&!0===v.current&&sh()(p.current,h.initialValues)&&O(p.current)},[o,O]);var A=(0,l.useCallback)(function(e){var t=e&&e.values?e.values:p.current,n=e&&e.errors?e.errors:b.current?b.current:h.initialErrors||{},r=e&&e.touched?e.touched:m.current?m.current:h.initialTouched||{},i=e&&e.status?e.status:g.current?g.current:h.initialStatus;p.current=t,b.current=n,m.current=r,g.current=i;var a=function(){E({type:"RESET_FORM",payload:{isSubmitting:!!e&&!!e.isSubmitting,errors:n,touched:r,status:i,values:t,isValidating:!!e&&!!e.isValidating,submitCount:e&&e.submitCount&&"number"==typeof e.submitCount?e.submitCount:0}})};if(h.onReset){var o=h.onReset(_.values,V);hm(o)?o.then(a):a()}else a()},[h.initialErrors,h.initialStatus,h.initialTouched]);(0,l.useEffect)(function(){!0===v.current&&!sh()(p.current,h.initialValues)&&(c&&(p.current=h.initialValues,A()),o&&O(p.current))},[c,h.initialValues,A,o,O]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(b.current,h.initialErrors)&&(b.current=h.initialErrors||hk,E({type:"SET_ERRORS",payload:h.initialErrors||hk}))},[c,h.initialErrors]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(m.current,h.initialTouched)&&(m.current=h.initialTouched||hx,E({type:"SET_TOUCHED",payload:h.initialTouched||hx}))},[c,h.initialTouched]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(g.current,h.initialStatus)&&(g.current=h.initialStatus,E({type:"SET_STATUS",payload:h.initialStatus}))},[c,h.initialStatus,h.initialTouched]);var L=hP(function(e){if(y.current[e]&&hf(y.current[e].validate)){var t=hg(_.values,e),n=y.current[e].validate(t);return hm(n)?(E({type:"SET_ISVALIDATING",payload:!0}),n.then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}}),E({type:"SET_ISVALIDATING",payload:!1})})):(E({type:"SET_FIELD_ERROR",payload:{field:e,value:n}}),Promise.resolve(n))}return h.validationSchema?(E({type:"SET_ISVALIDATING",payload:!0}),k(_.values,e).then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t[e]}}),E({type:"SET_ISVALIDATING",payload:!1})})):Promise.resolve()}),C=(0,l.useCallback)(function(e,t){var n=t.validate;y.current[e]={validate:n}},[]),I=(0,l.useCallback)(function(e){delete y.current[e]},[]),D=hP(function(e,t){return E({type:"SET_TOUCHED",payload:e}),(void 0===t?i:t)?O(_.values):Promise.resolve()}),N=(0,l.useCallback)(function(e){E({type:"SET_ERRORS",payload:e})},[]),P=hP(function(e,t){var r=hf(e)?e(_.values):e;return E({type:"SET_VALUES",payload:r}),(void 0===t?n:t)?O(r):Promise.resolve()}),R=(0,l.useCallback)(function(e,t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}})},[]),j=hP(function(e,t,r){return E({type:"SET_FIELD_VALUE",payload:{field:e,value:t}}),(void 0===r?n:r)?O(hv(_.values,e,t)):Promise.resolve()}),F=(0,l.useCallback)(function(e,t){var n,r=t,i=e;if(!hp(e)){e.persist&&e.persist();var a=e.target?e.target:e.currentTarget,o=a.type,s=a.name,u=a.id,c=a.value,l=a.checked,f=(a.outerHTML,a.options),d=a.multiple;r=t||s||u,i=/number|range/.test(o)?(n=parseFloat(c),isNaN(n)?"":n):/checkbox/.test(o)?hD(hg(_.values,r),l,c):d?hI(f):c}r&&j(r,i)},[j,_.values]),Y=hP(function(e){if(hp(e))return function(t){return F(t,e)};F(e)}),B=hP(function(e,t,n){return void 0===t&&(t=!0),E({type:"SET_FIELD_TOUCHED",payload:{field:e,value:t}}),(void 0===n?i:n)?O(_.values):Promise.resolve()}),U=(0,l.useCallback)(function(e,t){e.persist&&e.persist();var n,r=e.target,i=r.name,a=r.id;r.outerHTML,B(t||i||a,!0)},[B]),H=hP(function(e){if(hp(e))return function(t){return U(t,e)};U(e)}),$=(0,l.useCallback)(function(e){hf(e)?E({type:"SET_FORMIK_STATE",payload:e}):E({type:"SET_FORMIK_STATE",payload:function(){return e}})},[]),z=(0,l.useCallback)(function(e){E({type:"SET_STATUS",payload:e})},[]),G=(0,l.useCallback)(function(e){E({type:"SET_ISSUBMITTING",payload:e})},[]),W=hP(function(){return E({type:"SUBMIT_ATTEMPT"}),O().then(function(e){var t,n=e instanceof Error;if(!n&&0===Object.keys(e).length){try{if(void 0===(t=q()))return}catch(r){throw r}return Promise.resolve(t).then(function(e){return v.current&&E({type:"SUBMIT_SUCCESS"}),e}).catch(function(e){if(v.current)throw E({type:"SUBMIT_FAILURE"}),e})}if(v.current&&(E({type:"SUBMIT_FAILURE"}),n))throw e})}),K=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),W().catch(function(e){console.warn("Warning: An unhandled error was caught from submitForm()",e)})}),V={resetForm:A,validateForm:O,validateField:L,setErrors:N,setFieldError:R,setFieldTouched:B,setFieldValue:j,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,setFormikState:$,submitForm:W},q=hP(function(){return f(_.values,V)}),Z=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),A()}),X=(0,l.useCallback)(function(e){return{value:hg(_.values,e),error:hg(_.errors,e),touched:!!hg(_.touched,e),initialValue:hg(p.current,e),initialTouched:!!hg(m.current,e),initialError:hg(b.current,e)}},[_.errors,_.touched,_.values]),J=(0,l.useCallback)(function(e){return{setValue:function(t,n){return j(e,t,n)},setTouched:function(t,n){return B(e,t,n)},setError:function(t){return R(e,t)}}},[j,B,R]),Q=(0,l.useCallback)(function(e){var t=hd(e),n=t?e.name:e,r=hg(_.values,n),i={name:n,value:r,onChange:Y,onBlur:H};if(t){var a=e.type,o=e.value,s=e.as,u=e.multiple;"checkbox"===a?void 0===o?i.checked=!!r:(i.checked=!!(Array.isArray(r)&&~r.indexOf(o)),i.value=o):"radio"===a?(i.checked=r===o,i.value=o):"select"===s&&u&&(i.value=i.value||[],i.multiple=!0)}return i},[H,Y,_.values]),ee=(0,l.useMemo)(function(){return!sh()(p.current,_.values)},[p.current,_.values]),et=(0,l.useMemo)(function(){return void 0!==s?ee?_.errors&&0===Object.keys(_.errors).length:!1!==s&&hf(s)?s(h):s:_.errors&&0===Object.keys(_.errors).length},[s,ee,_.errors,h]);return ho({},_,{initialValues:p.current,initialErrors:b.current,initialTouched:m.current,initialStatus:g.current,handleBlur:H,handleChange:Y,handleReset:Z,handleSubmit:K,resetForm:A,setErrors:N,setFormikState:$,setFieldTouched:B,setFieldValue:j,setFieldError:R,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,submitForm:W,validateForm:O,validateField:L,isValid:et,dirty:ee,unregisterField:I,registerField:C,getFieldProps:Q,getFieldMeta:X,getFieldHelpers:J,validateOnBlur:i,validateOnChange:n,validateOnMount:o})}function hM(e){var t=hT(e),n=e.component,r=e.children,i=e.render,a=e.innerRef;return(0,l.useImperativeHandle)(a,function(){return t}),(0,l.createElement)(h_,{value:t},n?(0,l.createElement)(n,t):i?i(t):r?hf(r)?r(t):hb(r)?null:l.Children.only(r):null)}function hO(e){var t={};if(e.inner){if(0===e.inner.length)return hv(t,e.path,e.message);for(var n=e.inner,r=Array.isArray(n),i=0,n=r?n:n[Symbol.iterator]();;){if(r){if(i>=n.length)break;a=n[i++]}else{if((i=n.next()).done)break;a=i.value}var a,o=a;hg(t,o.path)||(t=hv(t,o.path,o.message))}}return t}function hA(e,t,n,r){void 0===n&&(n=!1),void 0===r&&(r={});var i=hL(e);return t[n?"validateSync":"validate"](i,{abortEarly:!1,context:r})}function hL(e){var t=Array.isArray(e)?[]:{};for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n)){var r=String(n);!0===Array.isArray(e[r])?t[r]=e[r].map(function(e){return!0===Array.isArray(e)||sj(e)?hL(e):""!==e?e:void 0}):sj(e[r])?t[r]=hL(e[r]):t[r]=""!==e[r]?e[r]:void 0}return t}function hC(e,t,n){var r=e.slice();return t.forEach(function(t,i){if(void 0===r[i]){var a=!1!==n.clone&&n.isMergeableObject(t);r[i]=a?sx(Array.isArray(t)?[]:{},t,n):t}else n.isMergeableObject(t)?r[i]=sx(e[i],t,n):-1===e.indexOf(t)&&r.push(t)}),r}function hI(e){return Array.from(e).filter(function(e){return e.selected}).map(function(e){return e.value})}function hD(e,t,n){if("boolean"==typeof e)return Boolean(t);var r=[],i=!1,a=-1;if(Array.isArray(e))r=e,i=(a=e.indexOf(n))>=0;else if(!n||"true"==n||"false"==n)return Boolean(t);return t&&n&&!i?r.concat(n):i?r.slice(0,a).concat(r.slice(a+1)):r}var hN="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?l.useLayoutEffect:l.useEffect;function hP(e){var t=(0,l.useRef)(e);return hN(function(){t.current=e}),(0,l.useCallback)(function(){for(var e=arguments.length,n=Array(e),r=0;re?t:e},0);return Array.from(ho({},e,{length:t+1}))};(function(e){function t(t){var n;return(n=e.call(this,t)||this).updateArrayField=function(e,t,r){var i=n.props,a=i.name;(0,i.formik.setFormikState)(function(n){var i="function"==typeof r?r:e,o="function"==typeof t?t:e,s=hv(n.values,a,e(hg(n.values,a))),u=r?i(hg(n.errors,a)):void 0,c=t?o(hg(n.touched,a)):void 0;return hl(u)&&(u=void 0),hl(c)&&(c=void 0),ho({},n,{values:s,errors:r?hv(n.errors,a,u):n.errors,touched:t?hv(n.touched,a,c):n.touched})})},n.push=function(e){return n.updateArrayField(function(t){return[].concat(hH(t),[ha(e)])},!1,!1)},n.handlePush=function(e){return function(){return n.push(e)}},n.swap=function(e,t){return n.updateArrayField(function(n){return hY(n,e,t)},!0,!0)},n.handleSwap=function(e,t){return function(){return n.swap(e,t)}},n.move=function(e,t){return n.updateArrayField(function(n){return hF(n,e,t)},!0,!0)},n.handleMove=function(e,t){return function(){return n.move(e,t)}},n.insert=function(e,t){return n.updateArrayField(function(n){return hB(n,e,t)},function(t){return hB(t,e,null)},function(t){return hB(t,e,null)})},n.handleInsert=function(e,t){return function(){return n.insert(e,t)}},n.replace=function(e,t){return n.updateArrayField(function(n){return hU(n,e,t)},!1,!1)},n.handleReplace=function(e,t){return function(){return n.replace(e,t)}},n.unshift=function(e){var t=-1;return n.updateArrayField(function(n){var r=n?[e].concat(n):[e];return t<0&&(t=r.length),r},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n}),t},n.handleUnshift=function(e){return function(){return n.unshift(e)}},n.handleRemove=function(e){return function(){return n.remove(e)}},n.handlePop=function(){return function(){return n.pop()}},n.remove=n.remove.bind(hc(n)),n.pop=n.pop.bind(hc(n)),n}hs(t,e);var n=t.prototype;return n.componentDidUpdate=function(e){this.props.validateOnChange&&this.props.formik.validateOnChange&&!sh()(hg(e.formik.values,e.name),hg(this.props.formik.values,this.props.name))&&this.props.formik.validateForm(this.props.formik.values)},n.remove=function(e){var t;return this.updateArrayField(function(n){var r=n?hH(n):[];return t||(t=r[e]),hf(r.splice)&&r.splice(e,1),r},!0,!0),t},n.pop=function(){var e;return this.updateArrayField(function(t){var n=t;return e||(e=n&&n.pop&&n.pop()),n},!0,!0),e},n.render=function(){var e={push:this.push,pop:this.pop,swap:this.swap,move:this.move,insert:this.insert,replace:this.replace,unshift:this.unshift,remove:this.remove,handlePush:this.handlePush,handlePop:this.handlePop,handleSwap:this.handleSwap,handleMove:this.handleMove,handleInsert:this.handleInsert,handleReplace:this.handleReplace,handleUnshift:this.handleUnshift,handleRemove:this.handleRemove},t=this.props,n=t.component,r=t.render,i=t.children,a=t.name,o=hu(t.formik,["validate","validationSchema"]),s=ho({},e,{form:o,name:a});return n?(0,l.createElement)(n,s):r?r(s):i?"function"==typeof i?i(s):hb(i)?null:l.Children.only(i):null},t})(l.Component).defaultProps={validateOnChange:!0},l.Component,l.Component;var h$=n(24802),hz=n(71209),hG=n(91750),hW=n(11970),hK=n(4689),hV=n(67598),hq=function(){return(hq=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&(n[r[i]]=e[r[i]]);return n}function hX(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form,o=a.isSubmitting,s=a.touched,u=a.errors,c=e.onBlur,l=e.helperText,f=hZ(e,["disabled","field","form","onBlur","helperText"]),d=hg(u,i.name),h=hg(s,i.name)&&!!d;return hq(hq({variant:f.variant,error:h,helperText:h?d:l,disabled:null!=t?t:o,onBlur:null!=c?c:function(e){r(null!=e?e:i.name)}},i),f)}function hJ(e){var t=e.children,n=hZ(e,["children"]);return(0,l.createElement)(i_.Z,hq({},hX(n)),t)}function hQ(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=(e.type,e.onBlur),s=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h1(e){return(0,l.createElement)(h$.Z,hq({},hQ(e)))}function h0(e){var t,n=e.disabled,r=e.field,i=r.onBlur,a=hZ(r,["onBlur"]),o=e.form.isSubmitting,s=(e.type,e.onBlur),u=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=n?n:o,indeterminate:!Array.isArray(a.value)&&null==a.value,onBlur:null!=s?s:function(e){i(null!=e?e:a.name)}},a),u)}function h2(e){return(0,l.createElement)(hz.Z,hq({},h0(e)))}function h3(e){var t=e.Label,n=hZ(e,["Label"]);return(0,l.createElement)(hG.Z,hq({control:(0,l.createElement)(hz.Z,hq({},h0(n)))},t))}function h4(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h5(e){return(0,l.createElement)(hW.default,hq({},h4(e)))}function h6(e){var t=e.field,n=t.onBlur,r=hZ(t,["onBlur"]),i=(e.form,e.onBlur),a=hZ(e,["field","form","onBlur"]);return hq(hq({onBlur:null!=i?i:function(e){n(null!=e?e:r.name)}},r),a)}function h9(e){return(0,l.createElement)(hK.Z,hq({},h6(e)))}function h8(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h7(e){return(0,l.createElement)(hV.default,hq({},h8(e)))}hJ.displayName="FormikMaterialUITextField",h1.displayName="FormikMaterialUISwitch",h2.displayName="FormikMaterialUICheckbox",h3.displayName="FormikMaterialUICheckboxWithLabel",h5.displayName="FormikMaterialUISelect",h9.displayName="FormikMaterialUIRadioGroup",h7.displayName="FormikMaterialUIInputBase";try{a=Map}catch(pe){}try{o=Set}catch(pt){}function pn(e,t,n){if(!e||"object"!=typeof e||"function"==typeof e)return e;if(e.nodeType&&"cloneNode"in e)return e.cloneNode(!0);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return RegExp(e);if(Array.isArray(e))return e.map(pr);if(a&&e instanceof a)return new Map(Array.from(e.entries()));if(o&&e instanceof o)return new Set(Array.from(e.values()));if(e instanceof Object){t.push(e);var r=Object.create(e);for(var i in n.push(r),e){var s=t.findIndex(function(t){return t===e[i]});r[i]=s>-1?n[s]:pn(e[i],t,n)}return r}return e}function pr(e){return pn(e,[],[])}let pi=Object.prototype.toString,pa=Error.prototype.toString,po=RegExp.prototype.toString,ps="undefined"!=typeof Symbol?Symbol.prototype.toString:()=>"",pu=/^Symbol\((.*)\)(.*)$/;function pc(e){if(e!=+e)return"NaN";let t=0===e&&1/e<0;return t?"-0":""+e}function pl(e,t=!1){if(null==e||!0===e||!1===e)return""+e;let n=typeof e;if("number"===n)return pc(e);if("string"===n)return t?`"${e}"`:e;if("function"===n)return"[Function "+(e.name||"anonymous")+"]";if("symbol"===n)return ps.call(e).replace(pu,"Symbol($1)");let r=pi.call(e).slice(8,-1);return"Date"===r?isNaN(e.getTime())?""+e:e.toISOString(e):"Error"===r||e instanceof Error?"["+pa.call(e)+"]":"RegExp"===r?po.call(e):null}function pf(e,t){let n=pl(e,t);return null!==n?n:JSON.stringify(e,function(e,n){let r=pl(this[e],t);return null!==r?r:n},2)}let pd={default:"${path} is invalid",required:"${path} is a required field",oneOf:"${path} must be one of the following values: ${values}",notOneOf:"${path} must not be one of the following values: ${values}",notType({path:e,type:t,value:n,originalValue:r}){let i=null!=r&&r!==n,a=`${e} must be a \`${t}\` type, but the final value was: \`${pf(n,!0)}\``+(i?` (cast from the value \`${pf(r,!0)}\`).`:".");return null===n&&(a+='\n If "null" is intended as an empty value be sure to mark the schema as `.nullable()`'),a},defined:"${path} must be defined"},ph={length:"${path} must be exactly ${length} characters",min:"${path} must be at least ${min} characters",max:"${path} must be at most ${max} characters",matches:'${path} must match the following: "${regex}"',email:"${path} must be a valid email",url:"${path} must be a valid URL",uuid:"${path} must be a valid UUID",trim:"${path} must be a trimmed string",lowercase:"${path} must be a lowercase string",uppercase:"${path} must be a upper case string"},pp={min:"${path} must be greater than or equal to ${min}",max:"${path} must be less than or equal to ${max}",lessThan:"${path} must be less than ${less}",moreThan:"${path} must be greater than ${more}",positive:"${path} must be a positive number",negative:"${path} must be a negative number",integer:"${path} must be an integer"},pb={min:"${path} field must be later than ${min}",max:"${path} field must be at earlier than ${max}"},pm={isValue:"${path} field must be ${value}"},pg={noUnknown:"${path} field has unspecified keys: ${unknown}"},pv={min:"${path} field must have at least ${min} items",max:"${path} field must have less than or equal to ${max} items",length:"${path} must be have ${length} items"};Object.assign(Object.create(null),{mixed:pd,string:ph,number:pp,date:pb,object:pg,array:pv,boolean:pm});var py=n(18721),pw=n.n(py);let p_=e=>e&&e.__isYupSchema__;class pE{constructor(e,t){if(this.refs=e,this.refs=e,"function"==typeof t){this.fn=t;return}if(!pw()(t,"is"))throw TypeError("`is:` is required for `when()` conditions");if(!t.then&&!t.otherwise)throw TypeError("either `then:` or `otherwise:` is required for `when()` conditions");let{is:n,then:r,otherwise:i}=t,a="function"==typeof n?n:(...e)=>e.every(e=>e===n);this.fn=function(...e){let t=e.pop(),n=e.pop(),o=a(...e)?r:i;if(o)return"function"==typeof o?o(n):n.concat(o.resolve(t))}}resolve(e,t){let n=this.refs.map(e=>e.getValue(null==t?void 0:t.value,null==t?void 0:t.parent,null==t?void 0:t.context)),r=this.fn.apply(e,n.concat(e,t));if(void 0===r||r===e)return e;if(!p_(r))throw TypeError("conditions must return a schema object");return r.resolve(t)}}let pS=pE;function pk(e){return null==e?[]:[].concat(e)}function px(){return(px=Object.assign||function(e){for(var t=1;tpf(t[n])):"function"==typeof e?e(t):e}static isError(e){return e&&"ValidationError"===e.name}constructor(e,t,n,r){super(),this.name="ValidationError",this.value=t,this.path=n,this.type=r,this.errors=[],this.inner=[],pk(e).forEach(e=>{pM.isError(e)?(this.errors.push(...e.errors),this.inner=this.inner.concat(e.inner.length?e.inner:e)):this.errors.push(e)}),this.message=this.errors.length>1?`${this.errors.length} errors occurred`:this.errors[0],Error.captureStackTrace&&Error.captureStackTrace(this,pM)}}let pO=e=>{let t=!1;return(...n)=>{t||(t=!0,e(...n))}};function pA(e,t){let{endEarly:n,tests:r,args:i,value:a,errors:o,sort:s,path:u}=e,c=pO(t),l=r.length,f=[];if(o=o||[],!l)return o.length?c(new pM(o,a,u)):c(null,a);for(let d=0;d=0||(i[n]=e[n]);return i}function pj(e){function t(t,n){let{value:r,path:i="",label:a,options:o,originalValue:s,sync:u}=t,c=pR(t,["value","path","label","options","originalValue","sync"]),{name:l,test:f,params:d,message:h}=e,{parent:p,context:b}=o;function m(e){return pN.isRef(e)?e.getValue(r,p,b):e}function g(e={}){let t=pC()(pP({value:r,originalValue:s,label:a,path:e.path||i},d,e.params),m),n=new pM(pM.formatError(e.message||h,t),r,t.path,e.type||l);return n.params=t,n}let v=pP({path:i,parent:p,type:l,createError:g,resolve:m,options:o,originalValue:s},c);if(!u){try{Promise.resolve(f.call(v,r,v)).then(e=>{pM.isError(e)?n(e):e?n(null,e):n(g())})}catch(y){n(y)}return}let w;try{var _;if(w=f.call(v,r,v),"function"==typeof(null==(_=w)?void 0:_.then))throw Error(`Validation test of type: "${v.type}" returned a Promise during a synchronous validate. This test will finish after the validate call has returned`)}catch(E){n(E);return}pM.isError(w)?n(w):w?n(null,w):n(g())}return t.OPTIONS=e,t}pN.prototype.__isYupRef=!0;let pF=e=>e.substr(0,e.length-1).substr(1);function pY(e,t,n,r=n){let i,a,o;return t?((0,pI.forEach)(t,(s,u,c)=>{let l=u?pF(s):s;if((e=e.resolve({context:r,parent:i,value:n})).innerType){let f=c?parseInt(l,10):0;if(n&&f>=n.length)throw Error(`Yup.reach cannot resolve an array item at index: ${s}, in the path: ${t}. because there is no value at that index. `);i=n,n=n&&n[f],e=e.innerType}if(!c){if(!e.fields||!e.fields[l])throw Error(`The schema does not contain the path: ${t}. (failed at: ${o} which is a type: "${e._type}")`);i=n,n=n&&n[l],e=e.fields[l]}a=l,o=u?"["+s+"]":"."+s}),{schema:e,parent:i,parentPath:a}):{parent:i,parentPath:t,schema:e}}class pB{constructor(){this.list=new Set,this.refs=new Map}get size(){return this.list.size+this.refs.size}describe(){let e=[];for(let t of this.list)e.push(t);for(let[,n]of this.refs)e.push(n.describe());return e}toArray(){return Array.from(this.list).concat(Array.from(this.refs.values()))}add(e){pN.isRef(e)?this.refs.set(e.key,e):this.list.add(e)}delete(e){pN.isRef(e)?this.refs.delete(e.key):this.list.delete(e)}has(e,t){if(this.list.has(e))return!0;let n,r=this.refs.values();for(;!(n=r.next()).done;)if(t(n.value)===e)return!0;return!1}clone(){let e=new pB;return e.list=new Set(this.list),e.refs=new Map(this.refs),e}merge(e,t){let n=this.clone();return e.list.forEach(e=>n.add(e)),e.refs.forEach(e=>n.add(e)),t.list.forEach(e=>n.delete(e)),t.refs.forEach(e=>n.delete(e)),n}}function pU(){return(pU=Object.assign||function(e){for(var t=1;t{this.typeError(pd.notType)}),this.type=(null==e?void 0:e.type)||"mixed",this.spec=pU({strip:!1,strict:!1,abortEarly:!0,recursive:!0,nullable:!1,presence:"optional"},null==e?void 0:e.spec)}get _type(){return this.type}_typeCheck(e){return!0}clone(e){if(this._mutate)return e&&Object.assign(this.spec,e),this;let t=Object.create(Object.getPrototypeOf(this));return t.type=this.type,t._typeError=this._typeError,t._whitelistError=this._whitelistError,t._blacklistError=this._blacklistError,t._whitelist=this._whitelist.clone(),t._blacklist=this._blacklist.clone(),t.exclusiveTests=pU({},this.exclusiveTests),t.deps=[...this.deps],t.conditions=[...this.conditions],t.tests=[...this.tests],t.transforms=[...this.transforms],t.spec=pr(pU({},this.spec,e)),t}label(e){var t=this.clone();return t.spec.label=e,t}meta(...e){if(0===e.length)return this.spec.meta;let t=this.clone();return t.spec.meta=Object.assign(t.spec.meta||{},e[0]),t}withMutation(e){let t=this._mutate;this._mutate=!0;let n=e(this);return this._mutate=t,n}concat(e){if(!e||e===this)return this;if(e.type!==this.type&&"mixed"!==this.type)throw TypeError(`You cannot \`concat()\` schema's of different types: ${this.type} and ${e.type}`);let t=this,n=e.clone(),r=pU({},t.spec,n.spec);return n.spec=r,n._typeError||(n._typeError=t._typeError),n._whitelistError||(n._whitelistError=t._whitelistError),n._blacklistError||(n._blacklistError=t._blacklistError),n._whitelist=t._whitelist.merge(e._whitelist,e._blacklist),n._blacklist=t._blacklist.merge(e._blacklist,e._whitelist),n.tests=t.tests,n.exclusiveTests=t.exclusiveTests,n.withMutation(t=>{e.tests.forEach(e=>{t.test(e.OPTIONS)})}),n}isType(e){return!!this.spec.nullable&&null===e||this._typeCheck(e)}resolve(e){let t=this;if(t.conditions.length){let n=t.conditions;(t=t.clone()).conditions=[],t=(t=n.reduce((t,n)=>n.resolve(t,e),t)).resolve(e)}return t}cast(e,t={}){let n=this.resolve(pU({value:e},t)),r=n._cast(e,t);if(void 0!==e&&!1!==t.assert&&!0!==n.isType(r)){let i=pf(e),a=pf(r);throw TypeError(`The value of ${t.path||"field"} could not be cast to a value that satisfies the schema type: "${n._type}". + */ Object.defineProperty(t,"__esModule",{value:!0}),"undefined"==typeof window||"function"!=typeof MessageChannel){var n,r,i,a,o,s=null,u=null,c=function(){if(null!==s)try{var e=t.unstable_now();s(!0,e),s=null}catch(n){throw setTimeout(c,0),n}},l=Date.now();t.unstable_now=function(){return Date.now()-l},n=function(e){null!==s?setTimeout(n,0,e):(s=e,setTimeout(c,0))},r=function(e,t){u=setTimeout(e,t)},i=function(){clearTimeout(u)},a=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var f=window.performance,d=window.Date,h=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var b=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!=typeof b&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills")}if("object"==typeof f&&"function"==typeof f.now)t.unstable_now=function(){return f.now()};else{var m=d.now();t.unstable_now=function(){return d.now()-m}}var g=!1,v=null,y=-1,w=5,_=0;a=function(){return t.unstable_now()>=_},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125M(o,n))void 0!==u&&0>M(u,o)?(e[r]=u,e[s]=n,r=s):(e[r]=o,e[a]=n,r=a);else if(void 0!==u&&0>M(u,n))e[r]=u,e[s]=n,r=s;else break a}}return t}return null}function M(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var O=[],A=[],L=1,C=null,I=3,D=!1,N=!1,P=!1;function R(e){for(var t=x(A);null!==t;){if(null===t.callback)T(A);else if(t.startTime<=e)T(A),t.sortIndex=t.expirationTime,k(O,t);else break;t=x(A)}}function j(e){if(P=!1,R(e),!N){if(null!==x(O))N=!0,n(F);else{var t=x(A);null!==t&&r(j,t.startTime-e)}}}function F(e,n){N=!1,P&&(P=!1,i()),D=!0;var o=I;try{for(R(n),C=x(O);null!==C&&(!(C.expirationTime>n)||e&&!a());){var s=C.callback;if(null!==s){C.callback=null,I=C.priorityLevel;var u=s(C.expirationTime<=n);n=t.unstable_now(),"function"==typeof u?C.callback=u:C===x(O)&&T(O),R(n)}else T(O);C=x(O)}if(null!==C)var c=!0;else{var l=x(A);null!==l&&r(j,l.startTime-n),c=!1}return c}finally{C=null,I=o,D=!1}}function Y(e){switch(e){case 1:return -1;case 2:return 250;case 5:return 1073741823;case 4:return 1e4;default:return 5e3}}var B=o;t.unstable_ImmediatePriority=1,t.unstable_UserBlockingPriority=2,t.unstable_NormalPriority=3,t.unstable_IdlePriority=5,t.unstable_LowPriority=4,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=I;I=e;try{return t()}finally{I=n}},t.unstable_next=function(e){switch(I){case 1:case 2:case 3:var t=3;break;default:t=I}var n=I;I=t;try{return e()}finally{I=n}},t.unstable_scheduleCallback=function(e,a,o){var s=t.unstable_now();if("object"==typeof o&&null!==o){var u=o.delay;u="number"==typeof u&&0s?(e.sortIndex=u,k(A,e),null===x(O)&&e===x(A)&&(P?i():P=!0,r(j,u-s))):(e.sortIndex=o,k(O,e),N||D||(N=!0,n(F))),e},t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_wrapCallback=function(e){var t=I;return function(){var n=I;I=t;try{return e.apply(this,arguments)}finally{I=n}}},t.unstable_getCurrentPriorityLevel=function(){return I},t.unstable_shouldYield=function(){var e=t.unstable_now();R(e);var n=x(O);return n!==C&&null!==C&&null!==n&&null!==n.callback&&n.startTime<=e&&n.expirationTime>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function c(e,t,n){var r=t.length-1;if(r=0?(i>0&&(e.lastNeed=i-1),i):--r=0?(i>0&&(e.lastNeed=i-2),i):--r=0?(i>0&&(2===i?i=0:e.lastNeed=i-3),i):0}function l(e,t,n){if((192&t[0])!=128)return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if((192&t[1])!=128)return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&(192&t[2])!=128)return e.lastNeed=2,"�"}}function f(e){var t=this.lastTotal-this.lastNeed,n=l(this,e,t);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):void(e.copy(this.lastChar,t,0,e.length),this.lastNeed-=e.length)}function d(e,t){var n=c(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)}function h(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+"�":t}function p(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function b(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function m(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function g(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function v(e){return e.toString(this.encoding)}function y(e){return e&&e.length?this.write(e):""}t.s=s,s.prototype.write=function(e){var t,n;if(0===e.length)return"";if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return nOF});var r,i,a,o,s,u,c,l=n(67294),f=n.t(l,2),d=n(97779),h=n(47886),p=n(57209),b=n(32316),m=n(95880),g=n(17051),v=n(71381),y=n(81701),w=n(3022),_=n(60323),E=n(87591),S=n(25649),k=n(28902),x=n(71426),T=n(48884),M=n(94184),O=n.n(M),A=n(55977),L=n(73935),C=function(){if("undefined"!=typeof Map)return Map;function e(e,t){var n=-1;return e.some(function(e,r){return e[0]===t&&(n=r,!0)}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(t){var n=e(this.__entries__,t),r=this.__entries__[n];return r&&r[1]},t.prototype.set=function(t,n){var r=e(this.__entries__,t);~r?this.__entries__[r][1]=n:this.__entries__.push([t,n])},t.prototype.delete=function(t){var n=this.__entries__,r=e(n,t);~r&&n.splice(r,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){void 0===t&&(t=null);for(var n=0,r=this.__entries__;n0},e.prototype.connect_=function(){I&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Y?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){I&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(e){var t=e.propertyName,n=void 0===t?"":t;F.some(function(e){return!!~n.indexOf(e)})&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),U=function(e,t){for(var n=0,r=Object.keys(t);n0},e}(),er="undefined"!=typeof WeakMap?new WeakMap:new C,ei=function(){function e(t){if(!(this instanceof e))throw TypeError("Cannot call a class as a function.");if(!arguments.length)throw TypeError("1 argument required, but only 0 present.");var n=B.getInstance(),r=new en(t,n,this);er.set(this,r)}return e}();["observe","unobserve","disconnect"].forEach(function(e){ei.prototype[e]=function(){var t;return(t=er.get(this))[e].apply(t,arguments)}});var ea=void 0!==D.ResizeObserver?D.ResizeObserver:ei;let eo=ea;var es=function(e){var t=[],n=null,r=function(){for(var r=arguments.length,i=Array(r),a=0;a=t||n<0||f&&r>=a}function g(){var e=eb();if(m(e))return v(e);s=setTimeout(g,b(e))}function v(e){return(s=void 0,d&&r)?h(e):(r=i=void 0,o)}function y(){void 0!==s&&clearTimeout(s),c=0,r=u=i=s=void 0}function w(){return void 0===s?o:v(eb())}function _(){var e=eb(),n=m(e);if(r=arguments,i=this,u=e,n){if(void 0===s)return p(u);if(f)return clearTimeout(s),s=setTimeout(g,t),h(u)}return void 0===s&&(s=setTimeout(g,t)),o}return t=ez(t)||0,ed(n)&&(l=!!n.leading,a=(f="maxWait"in n)?eW(ez(n.maxWait)||0,t):a,d="trailing"in n?!!n.trailing:d),_.cancel=y,_.flush=w,_}let eq=eV;var eZ="Expected a function";function eX(e,t,n){var r=!0,i=!0;if("function"!=typeof e)throw TypeError(eZ);return ed(n)&&(r="leading"in n?!!n.leading:r,i="trailing"in n?!!n.trailing:i),eq(e,t,{leading:r,maxWait:t,trailing:i})}let eJ=eX;var eQ={debounce:eq,throttle:eJ},e1=function(e){return eQ[e]},e0=function(e){return"function"==typeof e},e2=function(){return"undefined"==typeof window},e3=function(e){return e instanceof Element||e instanceof HTMLDocument};function e4(e){return(e4="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function e5(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function e6(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&l.createElement(tG.Z,{variant:"indeterminate",classes:r}))};tK.propTypes={fetchCount:el().number.isRequired};let tV=(0,b.withStyles)(tW)(tK);var tq=n(5536);let tZ=n.p+"ba8bbf16ebf8e1d05bef.svg";function tX(){return(tX=Object.assign||function(e){for(var t=1;t120){for(var d=Math.floor(u/80),h=u%80,p=[],b=0;b0},name:{enumerable:!1},nodes:{enumerable:!1},source:{enumerable:!1},positions:{enumerable:!1},originalError:{enumerable:!1}}),null!=s&&s.stack)?(Object.defineProperty(nf(b),"stack",{value:s.stack,writable:!0,configurable:!0}),nl(b)):(Error.captureStackTrace?Error.captureStackTrace(nf(b),n):Object.defineProperty(nf(b),"stack",{value:Error().stack,writable:!0,configurable:!0}),b)}return ns(n,[{key:"toString",value:function(){return nw(this)}},{key:t4.YF,get:function(){return"Object"}}]),n}(nd(Error));function ny(e){return void 0===e||0===e.length?void 0:e}function nw(e){var t=e.message;if(e.nodes)for(var n=0,r=e.nodes;n",EOF:"",BANG:"!",DOLLAR:"$",AMP:"&",PAREN_L:"(",PAREN_R:")",SPREAD:"...",COLON:":",EQUALS:"=",AT:"@",BRACKET_L:"[",BRACKET_R:"]",BRACE_L:"{",PIPE:"|",BRACE_R:"}",NAME:"Name",INT:"Int",FLOAT:"Float",STRING:"String",BLOCK_STRING:"BlockString",COMMENT:"Comment"}),nx=n(10143),nT=Object.freeze({QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",VARIABLE_DEFINITION:"VARIABLE_DEFINITION",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"}),nM=n(87392),nO=function(){function e(e){var t=new nS.WU(nk.SOF,0,0,0,0,null);this.source=e,this.lastToken=t,this.token=t,this.line=1,this.lineStart=0}var t=e.prototype;return t.advance=function(){return this.lastToken=this.token,this.token=this.lookahead()},t.lookahead=function(){var e,t=this.token;if(t.kind!==nk.EOF)do t=null!==(e=t.next)&&void 0!==e?e:t.next=nC(this,t);while(t.kind===nk.COMMENT)return t},e}();function nA(e){return e===nk.BANG||e===nk.DOLLAR||e===nk.AMP||e===nk.PAREN_L||e===nk.PAREN_R||e===nk.SPREAD||e===nk.COLON||e===nk.EQUALS||e===nk.AT||e===nk.BRACKET_L||e===nk.BRACKET_R||e===nk.BRACE_L||e===nk.PIPE||e===nk.BRACE_R}function nL(e){return isNaN(e)?nk.EOF:e<127?JSON.stringify(String.fromCharCode(e)):'"\\u'.concat(("00"+e.toString(16).toUpperCase()).slice(-4),'"')}function nC(e,t){for(var n=e.source,r=n.body,i=r.length,a=t.end;a31||9===a))return new nS.WU(nk.COMMENT,t,s,n,r,i,o.slice(t+1,s))}function nN(e,t,n,r,i,a){var o=e.body,s=n,u=t,c=!1;if(45===s&&(s=o.charCodeAt(++u)),48===s){if((s=o.charCodeAt(++u))>=48&&s<=57)throw n_(e,u,"Invalid number, unexpected digit after 0: ".concat(nL(s),"."))}else u=nP(e,u,s),s=o.charCodeAt(u);if(46===s&&(c=!0,s=o.charCodeAt(++u),u=nP(e,u,s),s=o.charCodeAt(u)),(69===s||101===s)&&(c=!0,(43===(s=o.charCodeAt(++u))||45===s)&&(s=o.charCodeAt(++u)),u=nP(e,u,s),s=o.charCodeAt(u)),46===s||nU(s))throw n_(e,u,"Invalid number, expected digit but got: ".concat(nL(s),"."));return new nS.WU(c?nk.FLOAT:nk.INT,t,u,r,i,a,o.slice(t,u))}function nP(e,t,n){var r=e.body,i=t,a=n;if(a>=48&&a<=57){do a=r.charCodeAt(++i);while(a>=48&&a<=57)return i}throw n_(e,i,"Invalid number, expected digit but got: ".concat(nL(a),"."))}function nR(e,t,n,r,i){for(var a=e.body,o=t+1,s=o,u=0,c="";o=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}function nB(e,t,n,r,i){for(var a=e.body,o=a.length,s=t+1,u=0;s!==o&&!isNaN(u=a.charCodeAt(s))&&(95===u||u>=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122);)++s;return new nS.WU(nk.NAME,t,s,n,r,i,a.slice(t,s))}function nU(e){return 95===e||e>=65&&e<=90||e>=97&&e<=122}function nH(e,t){return new n$(e,t).parseDocument()}var n$=function(){function e(e,t){var n=(0,nx.T)(e)?e:new nx.H(e);this._lexer=new nO(n),this._options=t}var t=e.prototype;return t.parseName=function(){var e=this.expectToken(nk.NAME);return{kind:nE.h.NAME,value:e.value,loc:this.loc(e)}},t.parseDocument=function(){var e=this._lexer.token;return{kind:nE.h.DOCUMENT,definitions:this.many(nk.SOF,this.parseDefinition,nk.EOF),loc:this.loc(e)}},t.parseDefinition=function(){if(this.peek(nk.NAME))switch(this._lexer.token.value){case"query":case"mutation":case"subscription":return this.parseOperationDefinition();case"fragment":return this.parseFragmentDefinition();case"schema":case"scalar":case"type":case"interface":case"union":case"enum":case"input":case"directive":return this.parseTypeSystemDefinition();case"extend":return this.parseTypeSystemExtension()}else if(this.peek(nk.BRACE_L))return this.parseOperationDefinition();else if(this.peekDescription())return this.parseTypeSystemDefinition();throw this.unexpected()},t.parseOperationDefinition=function(){var e,t=this._lexer.token;if(this.peek(nk.BRACE_L))return{kind:nE.h.OPERATION_DEFINITION,operation:"query",name:void 0,variableDefinitions:[],directives:[],selectionSet:this.parseSelectionSet(),loc:this.loc(t)};var n=this.parseOperationType();return this.peek(nk.NAME)&&(e=this.parseName()),{kind:nE.h.OPERATION_DEFINITION,operation:n,name:e,variableDefinitions:this.parseVariableDefinitions(),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseOperationType=function(){var e=this.expectToken(nk.NAME);switch(e.value){case"query":return"query";case"mutation":return"mutation";case"subscription":return"subscription"}throw this.unexpected(e)},t.parseVariableDefinitions=function(){return this.optionalMany(nk.PAREN_L,this.parseVariableDefinition,nk.PAREN_R)},t.parseVariableDefinition=function(){var e=this._lexer.token;return{kind:nE.h.VARIABLE_DEFINITION,variable:this.parseVariable(),type:(this.expectToken(nk.COLON),this.parseTypeReference()),defaultValue:this.expectOptionalToken(nk.EQUALS)?this.parseValueLiteral(!0):void 0,directives:this.parseDirectives(!0),loc:this.loc(e)}},t.parseVariable=function(){var e=this._lexer.token;return this.expectToken(nk.DOLLAR),{kind:nE.h.VARIABLE,name:this.parseName(),loc:this.loc(e)}},t.parseSelectionSet=function(){var e=this._lexer.token;return{kind:nE.h.SELECTION_SET,selections:this.many(nk.BRACE_L,this.parseSelection,nk.BRACE_R),loc:this.loc(e)}},t.parseSelection=function(){return this.peek(nk.SPREAD)?this.parseFragment():this.parseField()},t.parseField=function(){var e,t,n=this._lexer.token,r=this.parseName();return this.expectOptionalToken(nk.COLON)?(e=r,t=this.parseName()):t=r,{kind:nE.h.FIELD,alias:e,name:t,arguments:this.parseArguments(!1),directives:this.parseDirectives(!1),selectionSet:this.peek(nk.BRACE_L)?this.parseSelectionSet():void 0,loc:this.loc(n)}},t.parseArguments=function(e){var t=e?this.parseConstArgument:this.parseArgument;return this.optionalMany(nk.PAREN_L,t,nk.PAREN_R)},t.parseArgument=function(){var e=this._lexer.token,t=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.ARGUMENT,name:t,value:this.parseValueLiteral(!1),loc:this.loc(e)}},t.parseConstArgument=function(){var e=this._lexer.token;return{kind:nE.h.ARGUMENT,name:this.parseName(),value:(this.expectToken(nk.COLON),this.parseValueLiteral(!0)),loc:this.loc(e)}},t.parseFragment=function(){var e=this._lexer.token;this.expectToken(nk.SPREAD);var t=this.expectOptionalKeyword("on");return!t&&this.peek(nk.NAME)?{kind:nE.h.FRAGMENT_SPREAD,name:this.parseFragmentName(),directives:this.parseDirectives(!1),loc:this.loc(e)}:{kind:nE.h.INLINE_FRAGMENT,typeCondition:t?this.parseNamedType():void 0,directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(e)}},t.parseFragmentDefinition=function(){var e,t=this._lexer.token;return(this.expectKeyword("fragment"),(null===(e=this._options)||void 0===e?void 0:e.experimentalFragmentVariables)===!0)?{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),variableDefinitions:this.parseVariableDefinitions(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}:{kind:nE.h.FRAGMENT_DEFINITION,name:this.parseFragmentName(),typeCondition:(this.expectKeyword("on"),this.parseNamedType()),directives:this.parseDirectives(!1),selectionSet:this.parseSelectionSet(),loc:this.loc(t)}},t.parseFragmentName=function(){if("on"===this._lexer.token.value)throw this.unexpected();return this.parseName()},t.parseValueLiteral=function(e){var t=this._lexer.token;switch(t.kind){case nk.BRACKET_L:return this.parseList(e);case nk.BRACE_L:return this.parseObject(e);case nk.INT:return this._lexer.advance(),{kind:nE.h.INT,value:t.value,loc:this.loc(t)};case nk.FLOAT:return this._lexer.advance(),{kind:nE.h.FLOAT,value:t.value,loc:this.loc(t)};case nk.STRING:case nk.BLOCK_STRING:return this.parseStringLiteral();case nk.NAME:switch(this._lexer.advance(),t.value){case"true":return{kind:nE.h.BOOLEAN,value:!0,loc:this.loc(t)};case"false":return{kind:nE.h.BOOLEAN,value:!1,loc:this.loc(t)};case"null":return{kind:nE.h.NULL,loc:this.loc(t)};default:return{kind:nE.h.ENUM,value:t.value,loc:this.loc(t)}}case nk.DOLLAR:if(!e)return this.parseVariable()}throw this.unexpected()},t.parseStringLiteral=function(){var e=this._lexer.token;return this._lexer.advance(),{kind:nE.h.STRING,value:e.value,block:e.kind===nk.BLOCK_STRING,loc:this.loc(e)}},t.parseList=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseValueLiteral(e)};return{kind:nE.h.LIST,values:this.any(nk.BRACKET_L,r,nk.BRACKET_R),loc:this.loc(n)}},t.parseObject=function(e){var t=this,n=this._lexer.token,r=function(){return t.parseObjectField(e)};return{kind:nE.h.OBJECT,fields:this.any(nk.BRACE_L,r,nk.BRACE_R),loc:this.loc(n)}},t.parseObjectField=function(e){var t=this._lexer.token,n=this.parseName();return this.expectToken(nk.COLON),{kind:nE.h.OBJECT_FIELD,name:n,value:this.parseValueLiteral(e),loc:this.loc(t)}},t.parseDirectives=function(e){for(var t=[];this.peek(nk.AT);)t.push(this.parseDirective(e));return t},t.parseDirective=function(e){var t=this._lexer.token;return this.expectToken(nk.AT),{kind:nE.h.DIRECTIVE,name:this.parseName(),arguments:this.parseArguments(e),loc:this.loc(t)}},t.parseTypeReference=function(){var e,t=this._lexer.token;return(this.expectOptionalToken(nk.BRACKET_L)?(e=this.parseTypeReference(),this.expectToken(nk.BRACKET_R),e={kind:nE.h.LIST_TYPE,type:e,loc:this.loc(t)}):e=this.parseNamedType(),this.expectOptionalToken(nk.BANG))?{kind:nE.h.NON_NULL_TYPE,type:e,loc:this.loc(t)}:e},t.parseNamedType=function(){var e=this._lexer.token;return{kind:nE.h.NAMED_TYPE,name:this.parseName(),loc:this.loc(e)}},t.parseTypeSystemDefinition=function(){var e=this.peekDescription()?this._lexer.lookahead():this._lexer.token;if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaDefinition();case"scalar":return this.parseScalarTypeDefinition();case"type":return this.parseObjectTypeDefinition();case"interface":return this.parseInterfaceTypeDefinition();case"union":return this.parseUnionTypeDefinition();case"enum":return this.parseEnumTypeDefinition();case"input":return this.parseInputObjectTypeDefinition();case"directive":return this.parseDirectiveDefinition()}throw this.unexpected(e)},t.peekDescription=function(){return this.peek(nk.STRING)||this.peek(nk.BLOCK_STRING)},t.parseDescription=function(){if(this.peekDescription())return this.parseStringLiteral()},t.parseSchemaDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("schema");var n=this.parseDirectives(!0),r=this.many(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);return{kind:nE.h.SCHEMA_DEFINITION,description:t,directives:n,operationTypes:r,loc:this.loc(e)}},t.parseOperationTypeDefinition=function(){var e=this._lexer.token,t=this.parseOperationType();this.expectToken(nk.COLON);var n=this.parseNamedType();return{kind:nE.h.OPERATION_TYPE_DEFINITION,operation:t,type:n,loc:this.loc(e)}},t.parseScalarTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("scalar");var n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.SCALAR_TYPE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("type");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.OBJECT_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseImplementsInterfaces=function(){var e;if(!this.expectOptionalKeyword("implements"))return[];if((null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLImplementsInterfaces)===!0){var t=[];this.expectOptionalToken(nk.AMP);do t.push(this.parseNamedType());while(this.expectOptionalToken(nk.AMP)||this.peek(nk.NAME))return t}return this.delimitedMany(nk.AMP,this.parseNamedType)},t.parseFieldsDefinition=function(){var e;return(null===(e=this._options)||void 0===e?void 0:e.allowLegacySDLEmptyFields)===!0&&this.peek(nk.BRACE_L)&&this._lexer.lookahead().kind===nk.BRACE_R?(this._lexer.advance(),this._lexer.advance(),[]):this.optionalMany(nk.BRACE_L,this.parseFieldDefinition,nk.BRACE_R)},t.parseFieldDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseArgumentDefs();this.expectToken(nk.COLON);var i=this.parseTypeReference(),a=this.parseDirectives(!0);return{kind:nE.h.FIELD_DEFINITION,description:t,name:n,arguments:r,type:i,directives:a,loc:this.loc(e)}},t.parseArgumentDefs=function(){return this.optionalMany(nk.PAREN_L,this.parseInputValueDef,nk.PAREN_R)},t.parseInputValueDef=function(){var e,t=this._lexer.token,n=this.parseDescription(),r=this.parseName();this.expectToken(nk.COLON);var i=this.parseTypeReference();this.expectOptionalToken(nk.EQUALS)&&(e=this.parseValueLiteral(!0));var a=this.parseDirectives(!0);return{kind:nE.h.INPUT_VALUE_DEFINITION,description:n,name:r,type:i,defaultValue:e,directives:a,loc:this.loc(t)}},t.parseInterfaceTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("interface");var n=this.parseName(),r=this.parseImplementsInterfaces(),i=this.parseDirectives(!0),a=this.parseFieldsDefinition();return{kind:nE.h.INTERFACE_TYPE_DEFINITION,description:t,name:n,interfaces:r,directives:i,fields:a,loc:this.loc(e)}},t.parseUnionTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("union");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseUnionMemberTypes();return{kind:nE.h.UNION_TYPE_DEFINITION,description:t,name:n,directives:r,types:i,loc:this.loc(e)}},t.parseUnionMemberTypes=function(){return this.expectOptionalToken(nk.EQUALS)?this.delimitedMany(nk.PIPE,this.parseNamedType):[]},t.parseEnumTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("enum");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseEnumValuesDefinition();return{kind:nE.h.ENUM_TYPE_DEFINITION,description:t,name:n,directives:r,values:i,loc:this.loc(e)}},t.parseEnumValuesDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseEnumValueDefinition,nk.BRACE_R)},t.parseEnumValueDefinition=function(){var e=this._lexer.token,t=this.parseDescription(),n=this.parseName(),r=this.parseDirectives(!0);return{kind:nE.h.ENUM_VALUE_DEFINITION,description:t,name:n,directives:r,loc:this.loc(e)}},t.parseInputObjectTypeDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("input");var n=this.parseName(),r=this.parseDirectives(!0),i=this.parseInputFieldsDefinition();return{kind:nE.h.INPUT_OBJECT_TYPE_DEFINITION,description:t,name:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInputFieldsDefinition=function(){return this.optionalMany(nk.BRACE_L,this.parseInputValueDef,nk.BRACE_R)},t.parseTypeSystemExtension=function(){var e=this._lexer.lookahead();if(e.kind===nk.NAME)switch(e.value){case"schema":return this.parseSchemaExtension();case"scalar":return this.parseScalarTypeExtension();case"type":return this.parseObjectTypeExtension();case"interface":return this.parseInterfaceTypeExtension();case"union":return this.parseUnionTypeExtension();case"enum":return this.parseEnumTypeExtension();case"input":return this.parseInputObjectTypeExtension()}throw this.unexpected(e)},t.parseSchemaExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("schema");var t=this.parseDirectives(!0),n=this.optionalMany(nk.BRACE_L,this.parseOperationTypeDefinition,nk.BRACE_R);if(0===t.length&&0===n.length)throw this.unexpected();return{kind:nE.h.SCHEMA_EXTENSION,directives:t,operationTypes:n,loc:this.loc(e)}},t.parseScalarTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("scalar");var t=this.parseName(),n=this.parseDirectives(!0);if(0===n.length)throw this.unexpected();return{kind:nE.h.SCALAR_TYPE_EXTENSION,name:t,directives:n,loc:this.loc(e)}},t.parseObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("type");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.OBJECT_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseInterfaceTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("interface");var t=this.parseName(),n=this.parseImplementsInterfaces(),r=this.parseDirectives(!0),i=this.parseFieldsDefinition();if(0===n.length&&0===r.length&&0===i.length)throw this.unexpected();return{kind:nE.h.INTERFACE_TYPE_EXTENSION,name:t,interfaces:n,directives:r,fields:i,loc:this.loc(e)}},t.parseUnionTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("union");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseUnionMemberTypes();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.UNION_TYPE_EXTENSION,name:t,directives:n,types:r,loc:this.loc(e)}},t.parseEnumTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("enum");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseEnumValuesDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.ENUM_TYPE_EXTENSION,name:t,directives:n,values:r,loc:this.loc(e)}},t.parseInputObjectTypeExtension=function(){var e=this._lexer.token;this.expectKeyword("extend"),this.expectKeyword("input");var t=this.parseName(),n=this.parseDirectives(!0),r=this.parseInputFieldsDefinition();if(0===n.length&&0===r.length)throw this.unexpected();return{kind:nE.h.INPUT_OBJECT_TYPE_EXTENSION,name:t,directives:n,fields:r,loc:this.loc(e)}},t.parseDirectiveDefinition=function(){var e=this._lexer.token,t=this.parseDescription();this.expectKeyword("directive"),this.expectToken(nk.AT);var n=this.parseName(),r=this.parseArgumentDefs(),i=this.expectOptionalKeyword("repeatable");this.expectKeyword("on");var a=this.parseDirectiveLocations();return{kind:nE.h.DIRECTIVE_DEFINITION,description:t,name:n,arguments:r,repeatable:i,locations:a,loc:this.loc(e)}},t.parseDirectiveLocations=function(){return this.delimitedMany(nk.PIPE,this.parseDirectiveLocation)},t.parseDirectiveLocation=function(){var e=this._lexer.token,t=this.parseName();if(void 0!==nT[t.value])return t;throw this.unexpected(e)},t.loc=function(e){var t;if((null===(t=this._options)||void 0===t?void 0:t.noLocation)!==!0)return new nS.Ye(e,this._lexer.lastToken,this._lexer.source)},t.peek=function(e){return this._lexer.token.kind===e},t.expectToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t;throw n_(this._lexer.source,t.start,"Expected ".concat(nG(e),", found ").concat(nz(t),"."))},t.expectOptionalToken=function(e){var t=this._lexer.token;if(t.kind===e)return this._lexer.advance(),t},t.expectKeyword=function(e){var t=this._lexer.token;if(t.kind===nk.NAME&&t.value===e)this._lexer.advance();else throw n_(this._lexer.source,t.start,'Expected "'.concat(e,'", found ').concat(nz(t),"."))},t.expectOptionalKeyword=function(e){var t=this._lexer.token;return t.kind===nk.NAME&&t.value===e&&(this._lexer.advance(),!0)},t.unexpected=function(e){var t=null!=e?e:this._lexer.token;return n_(this._lexer.source,t.start,"Unexpected ".concat(nz(t),"."))},t.any=function(e,t,n){this.expectToken(e);for(var r=[];!this.expectOptionalToken(n);)r.push(t.call(this));return r},t.optionalMany=function(e,t,n){if(this.expectOptionalToken(e)){var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r}return[]},t.many=function(e,t,n){this.expectToken(e);var r=[];do r.push(t.call(this));while(!this.expectOptionalToken(n))return r},t.delimitedMany=function(e,t){this.expectOptionalToken(e);var n=[];do n.push(t.call(this));while(this.expectOptionalToken(e))return n},e}();function nz(e){var t=e.value;return nG(e.kind)+(null!=t?' "'.concat(t,'"'):"")}function nG(e){return nA(e)?'"'.concat(e,'"'):e}var nW=new Map,nK=new Map,nV=!0,nq=!1;function nZ(e){return e.replace(/[\s,]+/g," ").trim()}function nX(e){return nZ(e.source.body.substring(e.start,e.end))}function nJ(e){var t=new Set,n=[];return e.definitions.forEach(function(e){if("FragmentDefinition"===e.kind){var r=e.name.value,i=nX(e.loc),a=nK.get(r);a&&!a.has(i)?nV&&console.warn("Warning: fragment with name "+r+" already exists.\ngraphql-tag enforces all fragment names across your application to be unique; read more about\nthis in the docs: http://dev.apollodata.com/core/fragments.html#unique-names"):a||nK.set(r,a=new Set),a.add(i),t.has(i)||(t.add(i),n.push(e))}else n.push(e)}),(0,t0.pi)((0,t0.pi)({},e),{definitions:n})}function nQ(e){var t=new Set(e.definitions);t.forEach(function(e){e.loc&&delete e.loc,Object.keys(e).forEach(function(n){var r=e[n];r&&"object"==typeof r&&t.add(r)})});var n=e.loc;return n&&(delete n.startToken,delete n.endToken),e}function n1(e){var t=nZ(e);if(!nW.has(t)){var n=nH(e,{experimentalFragmentVariables:nq,allowLegacyFragmentVariables:nq});if(!n||"Document"!==n.kind)throw Error("Not a valid GraphQL document.");nW.set(t,nQ(nJ(n)))}return nW.get(t)}function n0(e){for(var t=[],n=1;n, or pass an ApolloClient instance in via options.'):(0,n7.kG)(!!n,32),n}var rb=n(10542),rm=n(53712),rg=n(21436),rv=Object.prototype.hasOwnProperty;function ry(e,t){return void 0===t&&(t=Object.create(null)),rw(rp(t.client),e).useQuery(t)}function rw(e,t){var n=(0,l.useRef)();n.current&&e===n.current.client&&t===n.current.query||(n.current=new r_(e,t,n.current));var r=n.current,i=(0,l.useState)(0),a=(i[0],i[1]);return r.forceUpdate=function(){a(function(e){return e+1})},r}var r_=function(){function e(e,t,n){this.client=e,this.query=t,this.ssrDisabledResult=(0,rb.J)({loading:!0,data:void 0,error:void 0,networkStatus:rc.I.loading}),this.skipStandbyResult=(0,rb.J)({loading:!1,data:void 0,error:void 0,networkStatus:rc.I.ready}),this.toQueryResultCache=new(re.mr?WeakMap:Map),rh(t,r.Query);var i=n&&n.result,a=i&&i.data;a&&(this.previousData=a)}return e.prototype.forceUpdate=function(){__DEV__&&n7.kG.warn("Calling default no-op implementation of InternalState#forceUpdate")},e.prototype.executeQuery=function(e){var t,n=this;e.query&&Object.assign(this,{query:e.query}),this.watchQueryOptions=this.createWatchQueryOptions(this.queryHookOptions=e);var r=this.observable.reobserveAsConcast(this.getObsQueryOptions());return this.previousData=(null===(t=this.result)||void 0===t?void 0:t.data)||this.previousData,this.result=void 0,this.forceUpdate(),new Promise(function(e){var t;r.subscribe({next:function(e){t=e},error:function(){e(n.toQueryResult(n.observable.getCurrentResult()))},complete:function(){e(n.toQueryResult(t))}})})},e.prototype.useQuery=function(e){var t=this;this.renderPromises=(0,l.useContext)((0,rs.K)()).renderPromises,this.useOptions(e);var n=this.useObservableQuery(),r=rn((0,l.useCallback)(function(){if(t.renderPromises)return function(){};var e=function(){var e=t.result,r=n.getCurrentResult();!(e&&e.loading===r.loading&&e.networkStatus===r.networkStatus&&(0,ra.D)(e.data,r.data))&&t.setResult(r)},r=function(a){var o=n.last;i.unsubscribe();try{n.resetLastResults(),i=n.subscribe(e,r)}finally{n.last=o}if(!rv.call(a,"graphQLErrors"))throw a;var s=t.result;(!s||s&&s.loading||!(0,ra.D)(a,s.error))&&t.setResult({data:s&&s.data,error:a,loading:!1,networkStatus:rc.I.error})},i=n.subscribe(e,r);return function(){return setTimeout(function(){return i.unsubscribe()})}},[n,this.renderPromises,this.client.disableNetworkFetches,]),function(){return t.getCurrentResult()},function(){return t.getCurrentResult()});return this.unsafeHandlePartialRefetch(r),this.toQueryResult(r)},e.prototype.useOptions=function(t){var n,r=this.createWatchQueryOptions(this.queryHookOptions=t),i=this.watchQueryOptions;!(0,ra.D)(r,i)&&(this.watchQueryOptions=r,i&&this.observable&&(this.observable.reobserve(this.getObsQueryOptions()),this.previousData=(null===(n=this.result)||void 0===n?void 0:n.data)||this.previousData,this.result=void 0)),this.onCompleted=t.onCompleted||e.prototype.onCompleted,this.onError=t.onError||e.prototype.onError,(this.renderPromises||this.client.disableNetworkFetches)&&!1===this.queryHookOptions.ssr&&!this.queryHookOptions.skip?this.result=this.ssrDisabledResult:this.queryHookOptions.skip||"standby"===this.watchQueryOptions.fetchPolicy?this.result=this.skipStandbyResult:(this.result===this.ssrDisabledResult||this.result===this.skipStandbyResult)&&(this.result=void 0)},e.prototype.getObsQueryOptions=function(){var e=[],t=this.client.defaultOptions.watchQuery;return t&&e.push(t),this.queryHookOptions.defaultOptions&&e.push(this.queryHookOptions.defaultOptions),e.push((0,rm.o)(this.observable&&this.observable.options,this.watchQueryOptions)),e.reduce(ro.J)},e.prototype.createWatchQueryOptions=function(e){void 0===e&&(e={});var t,n=e.skip,r=Object.assign((e.ssr,e.onCompleted,e.onError,e.defaultOptions,(0,n8._T)(e,["skip","ssr","onCompleted","onError","defaultOptions"])),{query:this.query});if(this.renderPromises&&("network-only"===r.fetchPolicy||"cache-and-network"===r.fetchPolicy)&&(r.fetchPolicy="cache-first"),r.variables||(r.variables={}),n){var i=r.fetchPolicy,a=void 0===i?this.getDefaultFetchPolicy():i,o=r.initialFetchPolicy;Object.assign(r,{initialFetchPolicy:void 0===o?a:o,fetchPolicy:"standby"})}else r.fetchPolicy||(r.fetchPolicy=(null===(t=this.observable)||void 0===t?void 0:t.options.initialFetchPolicy)||this.getDefaultFetchPolicy());return r},e.prototype.getDefaultFetchPolicy=function(){var e,t;return(null===(e=this.queryHookOptions.defaultOptions)||void 0===e?void 0:e.fetchPolicy)||(null===(t=this.client.defaultOptions.watchQuery)||void 0===t?void 0:t.fetchPolicy)||"cache-first"},e.prototype.onCompleted=function(e){},e.prototype.onError=function(e){},e.prototype.useObservableQuery=function(){var e=this.observable=this.renderPromises&&this.renderPromises.getSSRObservable(this.watchQueryOptions)||this.observable||this.client.watchQuery(this.getObsQueryOptions());this.obsQueryFields=(0,l.useMemo)(function(){return{refetch:e.refetch.bind(e),reobserve:e.reobserve.bind(e),fetchMore:e.fetchMore.bind(e),updateQuery:e.updateQuery.bind(e),startPolling:e.startPolling.bind(e),stopPolling:e.stopPolling.bind(e),subscribeToMore:e.subscribeToMore.bind(e)}},[e]);var t=!(!1===this.queryHookOptions.ssr||this.queryHookOptions.skip);return this.renderPromises&&t&&(this.renderPromises.registerSSRObservable(e),e.getCurrentResult().loading&&this.renderPromises.addObservableQueryPromise(e)),e},e.prototype.setResult=function(e){var t=this.result;t&&t.data&&(this.previousData=t.data),this.result=e,this.forceUpdate(),this.handleErrorOrCompleted(e)},e.prototype.handleErrorOrCompleted=function(e){var t=this;if(!e.loading){var n=this.toApolloError(e);Promise.resolve().then(function(){n?t.onError(n):e.data&&t.onCompleted(e.data)}).catch(function(e){__DEV__&&n7.kG.warn(e)})}},e.prototype.toApolloError=function(e){return(0,rg.O)(e.errors)?new ru.cA({graphQLErrors:e.errors}):e.error},e.prototype.getCurrentResult=function(){return this.result||this.handleErrorOrCompleted(this.result=this.observable.getCurrentResult()),this.result},e.prototype.toQueryResult=function(e){var t=this.toQueryResultCache.get(e);if(t)return t;var n=e.data,r=(e.partial,(0,n8._T)(e,["data","partial"]));return this.toQueryResultCache.set(e,t=(0,n8.pi)((0,n8.pi)((0,n8.pi)({data:n},r),this.obsQueryFields),{client:this.client,observable:this.observable,variables:this.observable.variables,called:!this.queryHookOptions.skip,previousData:this.previousData})),!t.error&&(0,rg.O)(e.errors)&&(t.error=new ru.cA({graphQLErrors:e.errors})),t},e.prototype.unsafeHandlePartialRefetch=function(e){e.partial&&this.queryHookOptions.partialRefetch&&!e.loading&&(!e.data||0===Object.keys(e.data).length)&&"cache-only"!==this.observable.options.fetchPolicy&&(Object.assign(e,{loading:!0,networkStatus:rc.I.refetch}),this.observable.refetch())},e}();function rE(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:{};return ry(i$,e)},iG=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"50",10),r=iz({variables:{offset:(t-1)*n,limit:n},fetchPolicy:"network-only"}),i=r.data,a=r.loading,o=r.error;return a?l.createElement(ij,null):o?l.createElement(iN,{error:o}):i?l.createElement(iD,{chains:i.chains.results,page:t,pageSize:n,total:i.chains.metadata.total}):null},iW=n(67932),iK=n(8126),iV="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function iq(e){if(iZ())return Intl.DateTimeFormat.supportedLocalesOf(e)[0]}function iZ(){return("undefined"==typeof Intl?"undefined":iV(Intl))==="object"&&"function"==typeof Intl.DateTimeFormat}var iX="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},iJ=function(){function e(e,t){for(var n=0;n=i.length)break;s=i[o++]}else{if((o=i.next()).done)break;s=o.value}var s,u=s;if((void 0===e?"undefined":iX(e))!=="object")return;e=e[u]}return e}},{key:"put",value:function(){for(var e=arguments.length,t=Array(e),n=0;n=o.length)break;c=o[u++]}else{if((u=o.next()).done)break;c=u.value}var c,l=c;"object"!==iX(a[l])&&(a[l]={}),a=a[l]}return a[i]=r}}]),e}();let i0=i1;var i2=new i0;function i3(e,t){if(!iZ())return function(e){return e.toString()};var n=i5(e),r=JSON.stringify(t),i=i2.get(String(n),r)||i2.put(String(n),r,new Intl.DateTimeFormat(n,t));return function(e){return i.format(e)}}var i4={};function i5(e){var t=e.toString();return i4[t]?i4[t]:i4[t]=iq(e)}var i6="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};function i9(e){return i8(e)?e:new Date(e)}function i8(e){return e instanceof Date||i7(e)}function i7(e){return(void 0===e?"undefined":i6(e))==="object"&&"function"==typeof e.getTime}var ae=n(54087),at=n.n(ae);function an(e,t){if(0===e.length)return 0;for(var n=0,r=e.length-1,i=void 0;n<=r;){var a=t(e[i=Math.floor((r+n)/2)]);if(0===a)return i;if(a<0){if((n=i+1)>r)return n}else if((r=i-1)=t.nextUpdateTime)ao(t,this.instances);else break}},scheduleNextTick:function(){var e=this;this.scheduledTick=at()(function(){e.tick(),e.scheduleNextTick()})},start:function(){this.scheduleNextTick()},stop:function(){at().cancel(this.scheduledTick)}};function aa(e){var t=ar(e.getNextValue(),2),n=t[0],r=t[1];e.setValue(n),e.nextUpdateTime=r}function ao(e,t){aa(e),au(t,e),as(t,e)}function as(e,t){var n=ac(e,t);e.splice(n,0,t)}function au(e,t){var n=e.indexOf(t);e.splice(n,1)}function ac(e,t){var n=t.nextUpdateTime;return an(e,function(e){return e.nextUpdateTime===n?0:e.nextUpdateTime>n?1:-1})}var al=(0,ec.oneOfType)([(0,ec.shape)({minTime:ec.number,formatAs:ec.string.isRequired}),(0,ec.shape)({test:ec.func,formatAs:ec.string.isRequired}),(0,ec.shape)({minTime:ec.number,format:ec.func.isRequired}),(0,ec.shape)({test:ec.func,format:ec.func.isRequired})]),af=(0,ec.oneOfType)([ec.string,(0,ec.shape)({steps:(0,ec.arrayOf)(al).isRequired,labels:(0,ec.oneOfType)([ec.string,(0,ec.arrayOf)(ec.string)]).isRequired,round:ec.string})]),ad=Object.assign||function(e){for(var t=1;t=0)&&Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function ab(e){var t=e.date,n=e.future,r=e.timeStyle,i=e.round,a=e.minTimeLeft,o=e.tooltip,s=e.component,u=e.container,c=e.wrapperComponent,f=e.wrapperProps,d=e.locale,h=e.locales,p=e.formatVerboseDate,b=e.verboseDateFormat,m=e.updateInterval,g=e.tick,v=ap(e,["date","future","timeStyle","round","minTimeLeft","tooltip","component","container","wrapperComponent","wrapperProps","locale","locales","formatVerboseDate","verboseDateFormat","updateInterval","tick"]),y=(0,l.useMemo)(function(){return d&&(h=[d]),h.concat(iK.Z.getDefaultLocale())},[d,h]),w=(0,l.useMemo)(function(){return new iK.Z(y)},[y]);t=(0,l.useMemo)(function(){return i9(t)},[t]);var _=(0,l.useCallback)(function(){var e=Date.now(),o=void 0;if(n&&e>=t.getTime()&&(e=t.getTime(),o=!0),void 0!==a){var s=t.getTime()-1e3*a;e>s&&(e=s,o=!0)}var u=w.format(t,r,{getTimeToNextUpdate:!0,now:e,future:n,round:i}),c=ah(u,2),l=c[0],f=c[1];return f=o?av:m||f||6e4,[l,e+f]},[t,n,r,m,i,a,w]),E=(0,l.useRef)();E.current=_;var S=(0,l.useMemo)(_,[]),k=ah(S,2),x=k[0],T=k[1],M=(0,l.useState)(x),O=ah(M,2),A=O[0],L=O[1],C=ah((0,l.useState)(),2),I=C[0],D=C[1],N=(0,l.useRef)();(0,l.useEffect)(function(){if(g)return N.current=ai.add({getNextValue:function(){return E.current()},setValue:L,nextUpdateTime:T}),function(){return N.current.stop()}},[g]),(0,l.useEffect)(function(){if(N.current)N.current.forceUpdate();else{var e=_(),t=ah(e,1)[0];L(t)}},[_]),(0,l.useEffect)(function(){D(!0)},[]);var P=(0,l.useMemo)(function(){if("undefined"!=typeof window)return i3(y,b)},[y,b]),R=(0,l.useMemo)(function(){if("undefined"!=typeof window)return p?p(t):P(t)},[t,p,P]),j=l.createElement(s,ad({date:t,verboseDate:I?R:void 0,tooltip:o},v),A),F=c||u;return F?l.createElement(F,ad({},f,{verboseDate:I?R:void 0}),j):j}ab.propTypes={date:el().oneOfType([el().instanceOf(Date),el().number]).isRequired,locale:el().string,locales:el().arrayOf(el().string),future:el().bool,timeStyle:af,round:el().string,minTimeLeft:el().number,component:el().elementType.isRequired,tooltip:el().bool.isRequired,formatVerboseDate:el().func,verboseDateFormat:el().object,updateInterval:el().oneOfType([el().number,el().arrayOf(el().shape({threshold:el().number,interval:el().number.isRequired}))]),tick:el().bool,wrapperComponent:el().func,wrapperProps:el().object},ab.defaultProps={locales:[],component:ay,tooltip:!0,verboseDateFormat:{weekday:"long",day:"numeric",month:"long",year:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit"},tick:!0},ab=l.memo(ab);let am=ab;var ag,av=31536e9;function ay(e){var t=e.date,n=e.verboseDate,r=e.tooltip,i=e.children,a=ap(e,["date","verboseDate","tooltip","children"]),o=(0,l.useMemo)(function(){return t.toISOString()},[t]);return l.createElement("time",ad({},a,{dateTime:o,title:r?n:void 0}),i)}ay.propTypes={date:el().instanceOf(Date).isRequired,verboseDate:el().string,tooltip:el().bool.isRequired,children:el().string.isRequired};var aw=n(30381),a_=n.n(aw),aE=n(31657);function aS(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ak(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0?new ru.cA({graphQLErrors:i}):void 0;if(u===s.current.mutationId&&!c.ignoreResults){var f={called:!0,loading:!1,data:r,error:l,client:a};s.current.isMounted&&!(0,ra.D)(s.current.result,f)&&o(s.current.result=f)}var d=e.onCompleted||(null===(n=s.current.options)||void 0===n?void 0:n.onCompleted);return null==d||d(t.data,c),t}).catch(function(t){if(u===s.current.mutationId&&s.current.isMounted){var n,r={loading:!1,error:t,data:void 0,called:!0,client:a};(0,ra.D)(s.current.result,r)||o(s.current.result=r)}var i=e.onError||(null===(n=s.current.options)||void 0===n?void 0:n.onError);if(i)return i(t,c),{data:void 0,errors:t};throw t})},[]),c=(0,l.useCallback)(function(){s.current.isMounted&&o({called:!1,loading:!1,client:n})},[]);return(0,l.useEffect)(function(){return s.current.isMounted=!0,function(){s.current.isMounted=!1}},[]),[u,(0,n8.pi)({reset:c},a)]}var ou=n(59067),oc=n(28428),ol=n(11186),of=n(78513);function od(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var oh=function(e){return(0,b.createStyles)({paper:{display:"flex",margin:"".concat(2.5*e.spacing.unit,"px 0"),padding:"".concat(3*e.spacing.unit,"px ").concat(3.5*e.spacing.unit,"px")},content:{flex:1,width:"100%"},actions:od({marginTop:-(1.5*e.spacing.unit),marginLeft:-(4*e.spacing.unit)},e.breakpoints.up("sm"),{marginLeft:0,marginRight:-(1.5*e.spacing.unit)}),itemBlock:{border:"1px solid rgba(224, 224, 224, 1)",borderRadius:e.shape.borderRadius,padding:2*e.spacing.unit,marginTop:e.spacing.unit},itemBlockText:{overflowWrap:"anywhere"}})},op=(0,b.withStyles)(oh)(function(e){var t=e.actions,n=e.children,r=e.classes;return l.createElement(ia.default,{className:r.paper},l.createElement("div",{className:r.content},n),t&&l.createElement("div",{className:r.actions},t))}),ob=function(e){var t=e.title;return l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},t)},om=function(e){var t=e.children,n=e.value;return l.createElement(x.default,{variant:"body1",noWrap:!0},t||n)},og=(0,b.withStyles)(oh)(function(e){var t=e.children,n=e.classes,r=e.value;return l.createElement("div",{className:n.itemBlock},l.createElement(x.default,{variant:"body1",className:n.itemBlockText},t||r))});function ov(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]-1}let sZ=sq;function sX(e,t){var n=this.__data__,r=s$(n,e);return r<0?(++this.size,n.push([e,t])):n[r][1]=t,this}let sJ=sX;function sQ(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e-1&&e%1==0&&e<=cI}let cN=cD;var cP="[object Arguments]",cR="[object Array]",cj="[object Boolean]",cF="[object Date]",cY="[object Error]",cB="[object Function]",cU="[object Map]",cH="[object Number]",c$="[object Object]",cz="[object RegExp]",cG="[object Set]",cW="[object String]",cK="[object WeakMap]",cV="[object ArrayBuffer]",cq="[object DataView]",cZ="[object Float64Array]",cX="[object Int8Array]",cJ="[object Int16Array]",cQ="[object Int32Array]",c1="[object Uint8Array]",c0="[object Uint8ClampedArray]",c2="[object Uint16Array]",c3="[object Uint32Array]",c4={};function c5(e){return eD(e)&&cN(e.length)&&!!c4[eC(e)]}c4["[object Float32Array]"]=c4[cZ]=c4[cX]=c4[cJ]=c4[cQ]=c4[c1]=c4[c0]=c4[c2]=c4[c3]=!0,c4[cP]=c4[cR]=c4[cV]=c4[cj]=c4[cq]=c4[cF]=c4[cY]=c4[cB]=c4[cU]=c4[cH]=c4[c$]=c4[cz]=c4[cG]=c4[cW]=c4[cK]=!1;let c6=c5;function c9(e){return function(t){return e(t)}}let c8=c9;var c7=n(79730),le=c7.Z&&c7.Z.isTypedArray,lt=le?c8(le):c6;let ln=lt;var lr=Object.prototype.hasOwnProperty;function li(e,t){var n=cT(e),r=!n&&ck(e),i=!n&&!r&&(0,cM.Z)(e),a=!n&&!r&&!i&&ln(e),o=n||r||i||a,s=o?cm(e.length,String):[],u=s.length;for(var c in e)(t||lr.call(e,c))&&!(o&&("length"==c||i&&("offset"==c||"parent"==c)||a&&("buffer"==c||"byteLength"==c||"byteOffset"==c)||cC(c,u)))&&s.push(c);return s}let la=li;var lo=Object.prototype;function ls(e){var t=e&&e.constructor;return e===("function"==typeof t&&t.prototype||lo)}let lu=ls;var lc=sM(Object.keys,Object);let ll=lc;var lf=Object.prototype.hasOwnProperty;function ld(e){if(!lu(e))return ll(e);var t=[];for(var n in Object(e))lf.call(e,n)&&"constructor"!=n&&t.push(n);return t}let lh=ld;function lp(e){return null!=e&&cN(e.length)&&!ui(e)}let lb=lp;function lm(e){return lb(e)?la(e):lh(e)}let lg=lm;function lv(e,t){return e&&cp(t,lg(t),e)}let ly=lv;function lw(e){var t=[];if(null!=e)for(var n in Object(e))t.push(n);return t}let l_=lw;var lE=Object.prototype.hasOwnProperty;function lS(e){if(!ed(e))return l_(e);var t=lu(e),n=[];for(var r in e)"constructor"==r&&(t||!lE.call(e,r))||n.push(r);return n}let lk=lS;function lx(e){return lb(e)?la(e,!0):lk(e)}let lT=lx;function lM(e,t){return e&&cp(t,lT(t),e)}let lO=lM;var lA=n(42896);function lL(e,t){var n=-1,r=e.length;for(t||(t=Array(r));++n=0||(i[n]=e[n]);return i}function hc(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}var hl=function(e){return Array.isArray(e)&&0===e.length},hf=function(e){return"function"==typeof e},hd=function(e){return null!==e&&"object"==typeof e},hh=function(e){return String(Math.floor(Number(e)))===e},hp=function(e){return"[object String]"===Object.prototype.toString.call(e)},hb=function(e){return 0===l.Children.count(e)},hm=function(e){return hd(e)&&hf(e.then)};function hg(e,t,n,r){void 0===r&&(r=0);for(var i=d8(t);e&&r=0?[]:{}}}return(0===a?e:i)[o[a]]===n?e:(void 0===n?delete i[o[a]]:i[o[a]]=n,0===a&&void 0===n&&delete r[o[a]],r)}function hy(e,t,n,r){void 0===n&&(n=new WeakMap),void 0===r&&(r={});for(var i=0,a=Object.keys(e);i0?t.map(function(t){return x(t,hg(e,t))}):[Promise.resolve("DO_NOT_DELETE_YOU_WILL_BE_FIRED")]).then(function(e){return e.reduce(function(e,n,r){return"DO_NOT_DELETE_YOU_WILL_BE_FIRED"===n||n&&(e=hv(e,t[r],n)),e},{})})},[x]),M=(0,l.useCallback)(function(e){return Promise.all([T(e),h.validationSchema?k(e):{},h.validate?S(e):{}]).then(function(e){var t=e[0],n=e[1],r=e[2];return sx.all([t,n,r],{arrayMerge:hC})})},[h.validate,h.validationSchema,T,S,k]),O=hP(function(e){return void 0===e&&(e=_.values),E({type:"SET_ISVALIDATING",payload:!0}),M(e).then(function(e){return v.current&&(E({type:"SET_ISVALIDATING",payload:!1}),sh()(_.errors,e)||E({type:"SET_ERRORS",payload:e})),e})});(0,l.useEffect)(function(){o&&!0===v.current&&sh()(p.current,h.initialValues)&&O(p.current)},[o,O]);var A=(0,l.useCallback)(function(e){var t=e&&e.values?e.values:p.current,n=e&&e.errors?e.errors:b.current?b.current:h.initialErrors||{},r=e&&e.touched?e.touched:m.current?m.current:h.initialTouched||{},i=e&&e.status?e.status:g.current?g.current:h.initialStatus;p.current=t,b.current=n,m.current=r,g.current=i;var a=function(){E({type:"RESET_FORM",payload:{isSubmitting:!!e&&!!e.isSubmitting,errors:n,touched:r,status:i,values:t,isValidating:!!e&&!!e.isValidating,submitCount:e&&e.submitCount&&"number"==typeof e.submitCount?e.submitCount:0}})};if(h.onReset){var o=h.onReset(_.values,V);hm(o)?o.then(a):a()}else a()},[h.initialErrors,h.initialStatus,h.initialTouched]);(0,l.useEffect)(function(){!0===v.current&&!sh()(p.current,h.initialValues)&&(c&&(p.current=h.initialValues,A()),o&&O(p.current))},[c,h.initialValues,A,o,O]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(b.current,h.initialErrors)&&(b.current=h.initialErrors||hk,E({type:"SET_ERRORS",payload:h.initialErrors||hk}))},[c,h.initialErrors]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(m.current,h.initialTouched)&&(m.current=h.initialTouched||hx,E({type:"SET_TOUCHED",payload:h.initialTouched||hx}))},[c,h.initialTouched]),(0,l.useEffect)(function(){c&&!0===v.current&&!sh()(g.current,h.initialStatus)&&(g.current=h.initialStatus,E({type:"SET_STATUS",payload:h.initialStatus}))},[c,h.initialStatus,h.initialTouched]);var L=hP(function(e){if(y.current[e]&&hf(y.current[e].validate)){var t=hg(_.values,e),n=y.current[e].validate(t);return hm(n)?(E({type:"SET_ISVALIDATING",payload:!0}),n.then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}}),E({type:"SET_ISVALIDATING",payload:!1})})):(E({type:"SET_FIELD_ERROR",payload:{field:e,value:n}}),Promise.resolve(n))}return h.validationSchema?(E({type:"SET_ISVALIDATING",payload:!0}),k(_.values,e).then(function(e){return e}).then(function(t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t[e]}}),E({type:"SET_ISVALIDATING",payload:!1})})):Promise.resolve()}),C=(0,l.useCallback)(function(e,t){var n=t.validate;y.current[e]={validate:n}},[]),I=(0,l.useCallback)(function(e){delete y.current[e]},[]),D=hP(function(e,t){return E({type:"SET_TOUCHED",payload:e}),(void 0===t?i:t)?O(_.values):Promise.resolve()}),N=(0,l.useCallback)(function(e){E({type:"SET_ERRORS",payload:e})},[]),P=hP(function(e,t){var r=hf(e)?e(_.values):e;return E({type:"SET_VALUES",payload:r}),(void 0===t?n:t)?O(r):Promise.resolve()}),R=(0,l.useCallback)(function(e,t){E({type:"SET_FIELD_ERROR",payload:{field:e,value:t}})},[]),j=hP(function(e,t,r){return E({type:"SET_FIELD_VALUE",payload:{field:e,value:t}}),(void 0===r?n:r)?O(hv(_.values,e,t)):Promise.resolve()}),F=(0,l.useCallback)(function(e,t){var n,r=t,i=e;if(!hp(e)){e.persist&&e.persist();var a=e.target?e.target:e.currentTarget,o=a.type,s=a.name,u=a.id,c=a.value,l=a.checked,f=(a.outerHTML,a.options),d=a.multiple;r=t||s||u,i=/number|range/.test(o)?(n=parseFloat(c),isNaN(n)?"":n):/checkbox/.test(o)?hD(hg(_.values,r),l,c):d?hI(f):c}r&&j(r,i)},[j,_.values]),Y=hP(function(e){if(hp(e))return function(t){return F(t,e)};F(e)}),B=hP(function(e,t,n){return void 0===t&&(t=!0),E({type:"SET_FIELD_TOUCHED",payload:{field:e,value:t}}),(void 0===n?i:n)?O(_.values):Promise.resolve()}),U=(0,l.useCallback)(function(e,t){e.persist&&e.persist();var n,r=e.target,i=r.name,a=r.id;r.outerHTML,B(t||i||a,!0)},[B]),H=hP(function(e){if(hp(e))return function(t){return U(t,e)};U(e)}),$=(0,l.useCallback)(function(e){hf(e)?E({type:"SET_FORMIK_STATE",payload:e}):E({type:"SET_FORMIK_STATE",payload:function(){return e}})},[]),z=(0,l.useCallback)(function(e){E({type:"SET_STATUS",payload:e})},[]),G=(0,l.useCallback)(function(e){E({type:"SET_ISSUBMITTING",payload:e})},[]),W=hP(function(){return E({type:"SUBMIT_ATTEMPT"}),O().then(function(e){var t,n=e instanceof Error;if(!n&&0===Object.keys(e).length){try{if(void 0===(t=q()))return}catch(r){throw r}return Promise.resolve(t).then(function(e){return v.current&&E({type:"SUBMIT_SUCCESS"}),e}).catch(function(e){if(v.current)throw E({type:"SUBMIT_FAILURE"}),e})}if(v.current&&(E({type:"SUBMIT_FAILURE"}),n))throw e})}),K=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),W().catch(function(e){console.warn("Warning: An unhandled error was caught from submitForm()",e)})}),V={resetForm:A,validateForm:O,validateField:L,setErrors:N,setFieldError:R,setFieldTouched:B,setFieldValue:j,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,setFormikState:$,submitForm:W},q=hP(function(){return f(_.values,V)}),Z=hP(function(e){e&&e.preventDefault&&hf(e.preventDefault)&&e.preventDefault(),e&&e.stopPropagation&&hf(e.stopPropagation)&&e.stopPropagation(),A()}),X=(0,l.useCallback)(function(e){return{value:hg(_.values,e),error:hg(_.errors,e),touched:!!hg(_.touched,e),initialValue:hg(p.current,e),initialTouched:!!hg(m.current,e),initialError:hg(b.current,e)}},[_.errors,_.touched,_.values]),J=(0,l.useCallback)(function(e){return{setValue:function(t,n){return j(e,t,n)},setTouched:function(t,n){return B(e,t,n)},setError:function(t){return R(e,t)}}},[j,B,R]),Q=(0,l.useCallback)(function(e){var t=hd(e),n=t?e.name:e,r=hg(_.values,n),i={name:n,value:r,onChange:Y,onBlur:H};if(t){var a=e.type,o=e.value,s=e.as,u=e.multiple;"checkbox"===a?void 0===o?i.checked=!!r:(i.checked=!!(Array.isArray(r)&&~r.indexOf(o)),i.value=o):"radio"===a?(i.checked=r===o,i.value=o):"select"===s&&u&&(i.value=i.value||[],i.multiple=!0)}return i},[H,Y,_.values]),ee=(0,l.useMemo)(function(){return!sh()(p.current,_.values)},[p.current,_.values]),et=(0,l.useMemo)(function(){return void 0!==s?ee?_.errors&&0===Object.keys(_.errors).length:!1!==s&&hf(s)?s(h):s:_.errors&&0===Object.keys(_.errors).length},[s,ee,_.errors,h]);return ho({},_,{initialValues:p.current,initialErrors:b.current,initialTouched:m.current,initialStatus:g.current,handleBlur:H,handleChange:Y,handleReset:Z,handleSubmit:K,resetForm:A,setErrors:N,setFormikState:$,setFieldTouched:B,setFieldValue:j,setFieldError:R,setStatus:z,setSubmitting:G,setTouched:D,setValues:P,submitForm:W,validateForm:O,validateField:L,isValid:et,dirty:ee,unregisterField:I,registerField:C,getFieldProps:Q,getFieldMeta:X,getFieldHelpers:J,validateOnBlur:i,validateOnChange:n,validateOnMount:o})}function hM(e){var t=hT(e),n=e.component,r=e.children,i=e.render,a=e.innerRef;return(0,l.useImperativeHandle)(a,function(){return t}),(0,l.createElement)(h_,{value:t},n?(0,l.createElement)(n,t):i?i(t):r?hf(r)?r(t):hb(r)?null:l.Children.only(r):null)}function hO(e){var t={};if(e.inner){if(0===e.inner.length)return hv(t,e.path,e.message);for(var n=e.inner,r=Array.isArray(n),i=0,n=r?n:n[Symbol.iterator]();;){if(r){if(i>=n.length)break;a=n[i++]}else{if((i=n.next()).done)break;a=i.value}var a,o=a;hg(t,o.path)||(t=hv(t,o.path,o.message))}}return t}function hA(e,t,n,r){void 0===n&&(n=!1),void 0===r&&(r={});var i=hL(e);return t[n?"validateSync":"validate"](i,{abortEarly:!1,context:r})}function hL(e){var t=Array.isArray(e)?[]:{};for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n)){var r=String(n);!0===Array.isArray(e[r])?t[r]=e[r].map(function(e){return!0===Array.isArray(e)||sj(e)?hL(e):""!==e?e:void 0}):sj(e[r])?t[r]=hL(e[r]):t[r]=""!==e[r]?e[r]:void 0}return t}function hC(e,t,n){var r=e.slice();return t.forEach(function(t,i){if(void 0===r[i]){var a=!1!==n.clone&&n.isMergeableObject(t);r[i]=a?sx(Array.isArray(t)?[]:{},t,n):t}else n.isMergeableObject(t)?r[i]=sx(e[i],t,n):-1===e.indexOf(t)&&r.push(t)}),r}function hI(e){return Array.from(e).filter(function(e){return e.selected}).map(function(e){return e.value})}function hD(e,t,n){if("boolean"==typeof e)return Boolean(t);var r=[],i=!1,a=-1;if(Array.isArray(e))r=e,i=(a=e.indexOf(n))>=0;else if(!n||"true"==n||"false"==n)return Boolean(t);return t&&n&&!i?r.concat(n):i?r.slice(0,a).concat(r.slice(a+1)):r}var hN="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement?l.useLayoutEffect:l.useEffect;function hP(e){var t=(0,l.useRef)(e);return hN(function(){t.current=e}),(0,l.useCallback)(function(){for(var e=arguments.length,n=Array(e),r=0;re?t:e},0);return Array.from(ho({},e,{length:t+1}))};(function(e){function t(t){var n;return(n=e.call(this,t)||this).updateArrayField=function(e,t,r){var i=n.props,a=i.name;(0,i.formik.setFormikState)(function(n){var i="function"==typeof r?r:e,o="function"==typeof t?t:e,s=hv(n.values,a,e(hg(n.values,a))),u=r?i(hg(n.errors,a)):void 0,c=t?o(hg(n.touched,a)):void 0;return hl(u)&&(u=void 0),hl(c)&&(c=void 0),ho({},n,{values:s,errors:r?hv(n.errors,a,u):n.errors,touched:t?hv(n.touched,a,c):n.touched})})},n.push=function(e){return n.updateArrayField(function(t){return[].concat(hH(t),[ha(e)])},!1,!1)},n.handlePush=function(e){return function(){return n.push(e)}},n.swap=function(e,t){return n.updateArrayField(function(n){return hY(n,e,t)},!0,!0)},n.handleSwap=function(e,t){return function(){return n.swap(e,t)}},n.move=function(e,t){return n.updateArrayField(function(n){return hF(n,e,t)},!0,!0)},n.handleMove=function(e,t){return function(){return n.move(e,t)}},n.insert=function(e,t){return n.updateArrayField(function(n){return hB(n,e,t)},function(t){return hB(t,e,null)},function(t){return hB(t,e,null)})},n.handleInsert=function(e,t){return function(){return n.insert(e,t)}},n.replace=function(e,t){return n.updateArrayField(function(n){return hU(n,e,t)},!1,!1)},n.handleReplace=function(e,t){return function(){return n.replace(e,t)}},n.unshift=function(e){var t=-1;return n.updateArrayField(function(n){var r=n?[e].concat(n):[e];return t<0&&(t=r.length),r},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n},function(e){var n=e?[null].concat(e):[null];return t<0&&(t=n.length),n}),t},n.handleUnshift=function(e){return function(){return n.unshift(e)}},n.handleRemove=function(e){return function(){return n.remove(e)}},n.handlePop=function(){return function(){return n.pop()}},n.remove=n.remove.bind(hc(n)),n.pop=n.pop.bind(hc(n)),n}hs(t,e);var n=t.prototype;return n.componentDidUpdate=function(e){this.props.validateOnChange&&this.props.formik.validateOnChange&&!sh()(hg(e.formik.values,e.name),hg(this.props.formik.values,this.props.name))&&this.props.formik.validateForm(this.props.formik.values)},n.remove=function(e){var t;return this.updateArrayField(function(n){var r=n?hH(n):[];return t||(t=r[e]),hf(r.splice)&&r.splice(e,1),r},!0,!0),t},n.pop=function(){var e;return this.updateArrayField(function(t){var n=t;return e||(e=n&&n.pop&&n.pop()),n},!0,!0),e},n.render=function(){var e={push:this.push,pop:this.pop,swap:this.swap,move:this.move,insert:this.insert,replace:this.replace,unshift:this.unshift,remove:this.remove,handlePush:this.handlePush,handlePop:this.handlePop,handleSwap:this.handleSwap,handleMove:this.handleMove,handleInsert:this.handleInsert,handleReplace:this.handleReplace,handleUnshift:this.handleUnshift,handleRemove:this.handleRemove},t=this.props,n=t.component,r=t.render,i=t.children,a=t.name,o=hu(t.formik,["validate","validationSchema"]),s=ho({},e,{form:o,name:a});return n?(0,l.createElement)(n,s):r?r(s):i?"function"==typeof i?i(s):hb(i)?null:l.Children.only(i):null},t})(l.Component).defaultProps={validateOnChange:!0},l.Component,l.Component;var h$=n(24802),hz=n(71209),hG=n(91750),hW=n(11970),hK=n(4689),hV=n(67598),hq=function(){return(hq=Object.assign||function(e){for(var t,n=1,r=arguments.length;nt.indexOf(r)&&(n[r]=e[r]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);it.indexOf(r[i])&&(n[r[i]]=e[r[i]]);return n}function hX(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form,o=a.isSubmitting,s=a.touched,u=a.errors,c=e.onBlur,l=e.helperText,f=hZ(e,["disabled","field","form","onBlur","helperText"]),d=hg(u,i.name),h=hg(s,i.name)&&!!d;return hq(hq({variant:f.variant,error:h,helperText:h?d:l,disabled:null!=t?t:o,onBlur:null!=c?c:function(e){r(null!=e?e:i.name)}},i),f)}function hJ(e){var t=e.children,n=hZ(e,["children"]);return(0,l.createElement)(i_.Z,hq({},hX(n)),t)}function hQ(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=(e.type,e.onBlur),s=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h1(e){return(0,l.createElement)(h$.Z,hq({},hQ(e)))}function h0(e){var t,n=e.disabled,r=e.field,i=r.onBlur,a=hZ(r,["onBlur"]),o=e.form.isSubmitting,s=(e.type,e.onBlur),u=hZ(e,["disabled","field","form","type","onBlur"]);return hq(hq({disabled:null!=n?n:o,indeterminate:!Array.isArray(a.value)&&null==a.value,onBlur:null!=s?s:function(e){i(null!=e?e:a.name)}},a),u)}function h2(e){return(0,l.createElement)(hz.Z,hq({},h0(e)))}function h3(e){var t=e.Label,n=hZ(e,["Label"]);return(0,l.createElement)(hG.Z,hq({control:(0,l.createElement)(hz.Z,hq({},h0(n)))},t))}function h4(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h5(e){return(0,l.createElement)(hW.default,hq({},h4(e)))}function h6(e){var t=e.field,n=t.onBlur,r=hZ(t,["onBlur"]),i=(e.form,e.onBlur),a=hZ(e,["field","form","onBlur"]);return hq(hq({onBlur:null!=i?i:function(e){n(null!=e?e:r.name)}},r),a)}function h9(e){return(0,l.createElement)(hK.Z,hq({},h6(e)))}function h8(e){var t=e.disabled,n=e.field,r=n.onBlur,i=hZ(n,["onBlur"]),a=e.form.isSubmitting,o=e.onBlur,s=hZ(e,["disabled","field","form","onBlur"]);return hq(hq({disabled:null!=t?t:a,onBlur:null!=o?o:function(e){r(null!=e?e:i.name)}},i),s)}function h7(e){return(0,l.createElement)(hV.default,hq({},h8(e)))}hJ.displayName="FormikMaterialUITextField",h1.displayName="FormikMaterialUISwitch",h2.displayName="FormikMaterialUICheckbox",h3.displayName="FormikMaterialUICheckboxWithLabel",h5.displayName="FormikMaterialUISelect",h9.displayName="FormikMaterialUIRadioGroup",h7.displayName="FormikMaterialUIInputBase";try{a=Map}catch(pe){}try{o=Set}catch(pt){}function pn(e,t,n){if(!e||"object"!=typeof e||"function"==typeof e)return e;if(e.nodeType&&"cloneNode"in e)return e.cloneNode(!0);if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return RegExp(e);if(Array.isArray(e))return e.map(pr);if(a&&e instanceof a)return new Map(Array.from(e.entries()));if(o&&e instanceof o)return new Set(Array.from(e.values()));if(e instanceof Object){t.push(e);var r=Object.create(e);for(var i in n.push(r),e){var s=t.findIndex(function(t){return t===e[i]});r[i]=s>-1?n[s]:pn(e[i],t,n)}return r}return e}function pr(e){return pn(e,[],[])}let pi=Object.prototype.toString,pa=Error.prototype.toString,po=RegExp.prototype.toString,ps="undefined"!=typeof Symbol?Symbol.prototype.toString:()=>"",pu=/^Symbol\((.*)\)(.*)$/;function pc(e){if(e!=+e)return"NaN";let t=0===e&&1/e<0;return t?"-0":""+e}function pl(e,t=!1){if(null==e||!0===e||!1===e)return""+e;let n=typeof e;if("number"===n)return pc(e);if("string"===n)return t?`"${e}"`:e;if("function"===n)return"[Function "+(e.name||"anonymous")+"]";if("symbol"===n)return ps.call(e).replace(pu,"Symbol($1)");let r=pi.call(e).slice(8,-1);return"Date"===r?isNaN(e.getTime())?""+e:e.toISOString(e):"Error"===r||e instanceof Error?"["+pa.call(e)+"]":"RegExp"===r?po.call(e):null}function pf(e,t){let n=pl(e,t);return null!==n?n:JSON.stringify(e,function(e,n){let r=pl(this[e],t);return null!==r?r:n},2)}let pd={default:"${path} is invalid",required:"${path} is a required field",oneOf:"${path} must be one of the following values: ${values}",notOneOf:"${path} must not be one of the following values: ${values}",notType({path:e,type:t,value:n,originalValue:r}){let i=null!=r&&r!==n,a=`${e} must be a \`${t}\` type, but the final value was: \`${pf(n,!0)}\``+(i?` (cast from the value \`${pf(r,!0)}\`).`:".");return null===n&&(a+='\n If "null" is intended as an empty value be sure to mark the schema as `.nullable()`'),a},defined:"${path} must be defined"},ph={length:"${path} must be exactly ${length} characters",min:"${path} must be at least ${min} characters",max:"${path} must be at most ${max} characters",matches:'${path} must match the following: "${regex}"',email:"${path} must be a valid email",url:"${path} must be a valid URL",uuid:"${path} must be a valid UUID",trim:"${path} must be a trimmed string",lowercase:"${path} must be a lowercase string",uppercase:"${path} must be a upper case string"},pp={min:"${path} must be greater than or equal to ${min}",max:"${path} must be less than or equal to ${max}",lessThan:"${path} must be less than ${less}",moreThan:"${path} must be greater than ${more}",positive:"${path} must be a positive number",negative:"${path} must be a negative number",integer:"${path} must be an integer"},pb={min:"${path} field must be later than ${min}",max:"${path} field must be at earlier than ${max}"},pm={isValue:"${path} field must be ${value}"},pg={noUnknown:"${path} field has unspecified keys: ${unknown}"},pv={min:"${path} field must have at least ${min} items",max:"${path} field must have less than or equal to ${max} items",length:"${path} must be have ${length} items"};Object.assign(Object.create(null),{mixed:pd,string:ph,number:pp,date:pb,object:pg,array:pv,boolean:pm});var py=n(18721),pw=n.n(py);let p_=e=>e&&e.__isYupSchema__;class pE{constructor(e,t){if(this.refs=e,this.refs=e,"function"==typeof t){this.fn=t;return}if(!pw()(t,"is"))throw TypeError("`is:` is required for `when()` conditions");if(!t.then&&!t.otherwise)throw TypeError("either `then:` or `otherwise:` is required for `when()` conditions");let{is:n,then:r,otherwise:i}=t,a="function"==typeof n?n:(...e)=>e.every(e=>e===n);this.fn=function(...e){let t=e.pop(),n=e.pop(),o=a(...e)?r:i;if(o)return"function"==typeof o?o(n):n.concat(o.resolve(t))}}resolve(e,t){let n=this.refs.map(e=>e.getValue(null==t?void 0:t.value,null==t?void 0:t.parent,null==t?void 0:t.context)),r=this.fn.apply(e,n.concat(e,t));if(void 0===r||r===e)return e;if(!p_(r))throw TypeError("conditions must return a schema object");return r.resolve(t)}}let pS=pE;function pk(e){return null==e?[]:[].concat(e)}function px(){return(px=Object.assign||function(e){for(var t=1;tpf(t[n])):"function"==typeof e?e(t):e}static isError(e){return e&&"ValidationError"===e.name}constructor(e,t,n,r){super(),this.name="ValidationError",this.value=t,this.path=n,this.type=r,this.errors=[],this.inner=[],pk(e).forEach(e=>{pM.isError(e)?(this.errors.push(...e.errors),this.inner=this.inner.concat(e.inner.length?e.inner:e)):this.errors.push(e)}),this.message=this.errors.length>1?`${this.errors.length} errors occurred`:this.errors[0],Error.captureStackTrace&&Error.captureStackTrace(this,pM)}}let pO=e=>{let t=!1;return(...n)=>{t||(t=!0,e(...n))}};function pA(e,t){let{endEarly:n,tests:r,args:i,value:a,errors:o,sort:s,path:u}=e,c=pO(t),l=r.length,f=[];if(o=o||[],!l)return o.length?c(new pM(o,a,u)):c(null,a);for(let d=0;d=0||(i[n]=e[n]);return i}function pj(e){function t(t,n){let{value:r,path:i="",label:a,options:o,originalValue:s,sync:u}=t,c=pR(t,["value","path","label","options","originalValue","sync"]),{name:l,test:f,params:d,message:h}=e,{parent:p,context:b}=o;function m(e){return pN.isRef(e)?e.getValue(r,p,b):e}function g(e={}){let t=pC()(pP({value:r,originalValue:s,label:a,path:e.path||i},d,e.params),m),n=new pM(pM.formatError(e.message||h,t),r,t.path,e.type||l);return n.params=t,n}let v=pP({path:i,parent:p,type:l,createError:g,resolve:m,options:o,originalValue:s},c);if(!u){try{Promise.resolve(f.call(v,r,v)).then(e=>{pM.isError(e)?n(e):e?n(null,e):n(g())})}catch(y){n(y)}return}let w;try{var _;if(w=f.call(v,r,v),"function"==typeof(null==(_=w)?void 0:_.then))throw Error(`Validation test of type: "${v.type}" returned a Promise during a synchronous validate. This test will finish after the validate call has returned`)}catch(E){n(E);return}pM.isError(w)?n(w):w?n(null,w):n(g())}return t.OPTIONS=e,t}pN.prototype.__isYupRef=!0;let pF=e=>e.substr(0,e.length-1).substr(1);function pY(e,t,n,r=n){let i,a,o;return t?((0,pI.forEach)(t,(s,u,c)=>{let l=u?pF(s):s;if((e=e.resolve({context:r,parent:i,value:n})).innerType){let f=c?parseInt(l,10):0;if(n&&f>=n.length)throw Error(`Yup.reach cannot resolve an array item at index: ${s}, in the path: ${t}. because there is no value at that index. `);i=n,n=n&&n[f],e=e.innerType}if(!c){if(!e.fields||!e.fields[l])throw Error(`The schema does not contain the path: ${t}. (failed at: ${o} which is a type: "${e._type}")`);i=n,n=n&&n[l],e=e.fields[l]}a=l,o=u?"["+s+"]":"."+s}),{schema:e,parent:i,parentPath:a}):{parent:i,parentPath:t,schema:e}}class pB{constructor(){this.list=new Set,this.refs=new Map}get size(){return this.list.size+this.refs.size}describe(){let e=[];for(let t of this.list)e.push(t);for(let[,n]of this.refs)e.push(n.describe());return e}toArray(){return Array.from(this.list).concat(Array.from(this.refs.values()))}add(e){pN.isRef(e)?this.refs.set(e.key,e):this.list.add(e)}delete(e){pN.isRef(e)?this.refs.delete(e.key):this.list.delete(e)}has(e,t){if(this.list.has(e))return!0;let n,r=this.refs.values();for(;!(n=r.next()).done;)if(t(n.value)===e)return!0;return!1}clone(){let e=new pB;return e.list=new Set(this.list),e.refs=new Map(this.refs),e}merge(e,t){let n=this.clone();return e.list.forEach(e=>n.add(e)),e.refs.forEach(e=>n.add(e)),t.list.forEach(e=>n.delete(e)),t.refs.forEach(e=>n.delete(e)),n}}function pU(){return(pU=Object.assign||function(e){for(var t=1;t{this.typeError(pd.notType)}),this.type=(null==e?void 0:e.type)||"mixed",this.spec=pU({strip:!1,strict:!1,abortEarly:!0,recursive:!0,nullable:!1,presence:"optional"},null==e?void 0:e.spec)}get _type(){return this.type}_typeCheck(e){return!0}clone(e){if(this._mutate)return e&&Object.assign(this.spec,e),this;let t=Object.create(Object.getPrototypeOf(this));return t.type=this.type,t._typeError=this._typeError,t._whitelistError=this._whitelistError,t._blacklistError=this._blacklistError,t._whitelist=this._whitelist.clone(),t._blacklist=this._blacklist.clone(),t.exclusiveTests=pU({},this.exclusiveTests),t.deps=[...this.deps],t.conditions=[...this.conditions],t.tests=[...this.tests],t.transforms=[...this.transforms],t.spec=pr(pU({},this.spec,e)),t}label(e){var t=this.clone();return t.spec.label=e,t}meta(...e){if(0===e.length)return this.spec.meta;let t=this.clone();return t.spec.meta=Object.assign(t.spec.meta||{},e[0]),t}withMutation(e){let t=this._mutate;this._mutate=!0;let n=e(this);return this._mutate=t,n}concat(e){if(!e||e===this)return this;if(e.type!==this.type&&"mixed"!==this.type)throw TypeError(`You cannot \`concat()\` schema's of different types: ${this.type} and ${e.type}`);let t=this,n=e.clone(),r=pU({},t.spec,n.spec);return n.spec=r,n._typeError||(n._typeError=t._typeError),n._whitelistError||(n._whitelistError=t._whitelistError),n._blacklistError||(n._blacklistError=t._blacklistError),n._whitelist=t._whitelist.merge(e._whitelist,e._blacklist),n._blacklist=t._blacklist.merge(e._blacklist,e._whitelist),n.tests=t.tests,n.exclusiveTests=t.exclusiveTests,n.withMutation(t=>{e.tests.forEach(e=>{t.test(e.OPTIONS)})}),n}isType(e){return!!this.spec.nullable&&null===e||this._typeCheck(e)}resolve(e){let t=this;if(t.conditions.length){let n=t.conditions;(t=t.clone()).conditions=[],t=(t=n.reduce((t,n)=>n.resolve(t,e),t)).resolve(e)}return t}cast(e,t={}){let n=this.resolve(pU({value:e},t)),r=n._cast(e,t);if(void 0!==e&&!1!==t.assert&&!0!==n.isType(r)){let i=pf(e),a=pf(r);throw TypeError(`The value of ${t.path||"field"} could not be cast to a value that satisfies the schema type: "${n._type}". attempted value: ${i} -`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pU({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pA({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pA({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pU({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pU({},t,{value:e}))._validate(e,pU({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pM.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pM.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pr(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pd.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pd.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pd.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pj(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pk(e).map(e=>new pN(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pS(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pj({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pd.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pj({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pd.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pj({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let p$ of(pH.prototype.__isYupSchema__=!0,["validate","validateSync"]))pH.prototype[`${p$}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pY(this,e,t,n.context);return a[p$](r&&r[i],pU({},n,{parent:r,path:e}))};for(let pz of["equals","is"])pH.prototype[pz]=pH.prototype.oneOf;for(let pG of["not","nope"])pH.prototype[pG]=pH.prototype.notOneOf;pH.prototype.optional=pH.prototype.notRequired;let pW=pH;function pK(){return new pW}pK.prototype=pW.prototype;let pV=e=>null==e;function pq(){return new pZ}class pZ extends pH{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pV(e)||!0===e})}isFalse(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pV(e)||!1===e})}}pq.prototype=pZ.prototype;let pX=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pJ=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pQ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,p1=e=>pV(e)||e===e.trim(),p0=({}).toString();function p2(){return new p3}class p3 extends pH{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p0?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=ph.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t=ph.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||ph.matches,params:{regex:e},test:t=>pV(t)||""===t&&n||-1!==t.search(e)})}email(e=ph.email){return this.matches(pX,{name:"email",message:e,excludeEmptyString:!0})}url(e=ph.url){return this.matches(pJ,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=ph.uuid){return this.matches(pQ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=ph.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:p1})}lowercase(e=ph.lowercase){return this.transform(e=>pV(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toLowerCase()})}uppercase(e=ph.uppercase){return this.transform(e=>pV(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toUpperCase()})}}p2.prototype=p3.prototype;let p4=e=>e!=+e;function p5(){return new p6}class p6 extends pH{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p4(e)}min(e,t=pp.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t>=this.resolve(e)}})}max(e,t=pp.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t<=this.resolve(e)}})}lessThan(e,t=pp.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pV(t)||tthis.resolve(e)}})}positive(e=pp.positive){return this.moreThan(0,e)}negative(e=pp.negative){return this.lessThan(0,e)}integer(e=pp.integer){return this.test({name:"integer",message:e,test:e=>pV(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pV(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pV(t)?t:Math[e](t))}}p5.prototype=p6.prototype;var p9=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p9.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p7=new Date(""),be=e=>"[object Date]"===Object.prototype.toString.call(e);function bt(){return new bn}class bn extends pH{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p7:new Date(e))})})}_typeCheck(e){return be(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pN.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pb.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pV(e)||e>=this.resolve(n)}})}max(e,t=pb.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pV(e)||e<=this.resolve(n)}})}}bn.INVALID_DATE=p7,bt.prototype=bn.prototype,bt.INVALID_DATE=p7;var br=n(11865),bi=n.n(br),ba=n(68929),bo=n.n(ba),bs=n(67523),bu=n.n(bs),bc=n(94633),bl=n.n(bc);function bf(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pI.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(pw()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pN.isRef(o)&&o.isSibling?i(o.path,a):p_(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bl().array(r,n).reverse()}function bd(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bh(e){return(t,n)=>bd(e,t)-bd(e,n)}function bp(){return(bp=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bm(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bg=bh([]);class bv extends pH{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bg,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bb(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bp({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=pw()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pM.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bb(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bp({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pA({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bp({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pH&&i instanceof pH&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bh(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bf(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pI.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return pw()(i,e)&&(a=bp({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pg.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bm(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pg.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bu()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(bo())}snakeCase(){return this.transformKeys(bi())}constantCase(){return this.transformKeys(e=>bi()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pC()(this.fields,e=>e.describe()),e}}function by(e){return new bv(e)}function bw(){return(bw=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,bw({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pM.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pA({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!p_(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pf(e));return t.innerType=e,t}length(e,t=pv.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pv.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pv.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}b_.prototype=bE.prototype;var bS=by().shape({name:p2().required("Required"),url:p2().required("Required")}),bk=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hM,{initialValues:t,validationSchema:bS,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hj,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bx=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Bridge",action:l.createElement(aL.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aK.Z,null,l.createElement(bk,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},ml=n(76023);function mf(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0||(i[n]=e[n]);return i}function mB(e,t){if(null==e)return{};var n,r,i=mY(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mU(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mX={};function mJ(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mX[t]||(mX[t]=mZ(e)),mX[t]}function mQ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mJ(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mV({},e,n[t])},t)}function m1(e){return e.join(" ")}function m0(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m2({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m2(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m0(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mV({},s,{className:m1(m)||void 0,style:mQ(s.className,Object.assign({},s.style,i),n)})}else d=mV({},s,{className:m1(s.className)});var g=h(t.children);return l.createElement(c,mq({key:o},d),g)}}let m3=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m4=/\n/g;function m5(e){return e.match(m4)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m9(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m7(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function ge(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mV({},i,"function"==typeof e?e(t):e)}function gt(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=ge(r,n,i);t.unshift(m7(n,h))}return f&l&&(d.style=mV({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gn(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return gt({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=ge(s,t,o);e.unshift(m7(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m5(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(gt({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=gt({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gc=n(98695),gl=n.n(gc);let gf=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gd=gs(gl(),gu);gd.supportedLanguages=gf;let gh=gd;var gp=n(64566),gb=n(68239);function gm(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gg(){var e=gm(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gg=function(){return e},e}var gv=function(){var e="[[TelemetryIngress.Endpoints]] \nNetwork = '...' # e.g. EVM. Solana, Starknet, Cosmos \nChainID = '...' # e.g. 1, 5, devnet, mainnet-beta URL\nURL = '...'\nServerPubKey = '...'";return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Deprecation warning"}),l.createElement(aK.Z,null,l.createElement(x.default,{variant:"h5",gutterBottom:!0},"Starting in ",l.createElement("code",null,"v2.9.0"),":"),l.createElement(w.default,{dense:!0},l.createElement(_.default,null,l.createElement(ol.Z,null,l.createElement(gb.Z,null)),l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},l.createElement("code",null,"TelemetryIngress.URL")," and"," ",l.createElement("code",null,"TelemetryIngress.ServerPubKey")," will no longer be allowed. Please switch to ",l.createElement("code",null,"TelemetryIngress.Endpoints"),":",l.createElement(gh,{language:"toml",style:gu},e))),l.createElement(_.default,null,l.createElement(ol.Z,null,l.createElement(gb.Z,null)),l.createElement(x.default,{variant:"subtitle2",gutterBottom:!0},l.createElement("code",null,"P2P.V1")," will no longer be supported and must not be set in TOML configuration in order to boot. Use"," ",l.createElement("code",null,"P2P.V2")," instead. If you are using both,"," ",l.createElement("code",null,"V1")," can simply be removed.")))))},gy=n0(gg()),gw=function(e){var t=e.children;return l.createElement(ii.Z,null,l.createElement(ie.default,{component:"th",scope:"row",colSpan:3},t))},g_=function(){return l.createElement(gw,null,"...")},gE=function(e){var t=e.children;return l.createElement(gw,null,t)},gS=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gE,null,i);if(t)return l.createElement(g_,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mR.Z,{defaultExpanded:o},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},a),l.createElement(mF.Z,{style:s},l.createElement(gh,{language:"toml",style:gu},n))))},gk=function(){var e=ry(gy,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(gS,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gv,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(gS,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(gS,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gx=n(34823),gT=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gM=(0,b.withStyles)(gT)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gx.N,A.wU);return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r7.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gO=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(gk,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gM,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mP,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mS,null))))))},gA=function(){return l.createElement(gO,null)},gL=function(){return l.createElement(gA,null)},gC=n(44431),gI=1e18,gD=function(e){return new gC.BigNumber(e).dividedBy(gI).toFixed(8)},gN=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sf.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aK.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ob,{title:"Address"}),l.createElement(om,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"Native Token Balance"}),l.createElement(om,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"LINK Balance"}),l.createElement(om,{value:e.linkBalance?gD(e.linkBalance):"--"}))))})),r+1s&&l.createElement(g$.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:r.footer},l.createElement(aL.Z,{href:"/runs",component:tz},"View More"))))))});function vi(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function va(){var e=vi(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return va=function(){return e},e}var vo=5,vs=n0(va(),vt),vu=function(){var e=ry(vs,{variables:{offset:0,limit:vo},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vr,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vo})},vc=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vl=(0,b.withStyles)(vc)(function(e){var t=e.classes,n=(0,A.v9)(gx.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ia.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vf=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vd=(0,b.withStyles)(vf)(function(e){var t=e.classes,n=e.job;return l.createElement(ii.Z,null,l.createElement(ie.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ip,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aA,{tooltip:!0},n.createdAt))))))});function vh(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vp(){var e=vh(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vp=function(){return e},e}var vb=n0(vp()),vm=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vg=(0,b.withStyles)(vm)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r7.Z,null,l.createElement(gW,{visible:o}),l.createElement(gK,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gz,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vd,{job:e,key:t})}))))});function vv(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vy(){var e=vv(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vy=function(){return e},e}var vw=5,v_=n0(vy(),vb),vE=function(){var e=ry(v_,{variables:{offset:0,limit:vw},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vg,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},vS=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(vu,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gH,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vE,null))))),l.createElement(vl,null))},vk=function(){return l.createElement(vS,null)},vx=function(){return l.createElement(vk,null)},vT=n(87239),vM=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vO=n(5022),vA=n(78718),vL=n.n(vA);function vC(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ii.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(ie.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(ie.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aA,{tooltip:!0},e.createdAt))),l.createElement(ie.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,ym(t,e.status))},e.status.toLowerCase())))})))}),yv=n(16839),yy=n.n(yv);function yw(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=yy().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var y_=n(94164),yE=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},yS=n(73343),yk=n(3379),yx=n.n(yk);function yT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(y_.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:yS.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yE,{data:e}))}))};function yD(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyH&&l.createElement("div",{className:t.runDetails},l.createElement(aL.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yU,{observationSource:n.observationSource})))});function yG(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vO.parse(e),!0}catch(t){return!1}})}),wq=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hM,{initialValues:t,validationSchema:wV,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hj,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hR,{component:hJ,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wZ=n(50109),wX="persistSpec";function wJ(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wZ.t8(wX,n),{toml:n}):{toml:wZ.U2(wX)||""}}var wQ=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wJ({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wZ.t8("".concat(wX),t),n&&n(t)};return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"New Job"}),l.createElement(aK.Z,null,l.createElement(wq,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function w1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _L(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(_q,e)},_X=function(){var e=_Z({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_z,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_J=function(e){var t=e.csaKey;return l.createElement(ii.Z,{hover:!0},l.createElement(ie.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_O,{data:t.publicKey}))))};function _Q(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _1(){var e=_Q(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _1=function(){return e},e}var _0=n0(_1()),_2=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r9.Z,null,l.createElement(sf.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ox.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(it.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,null,"Public Key"))),l.createElement(r7.Z,null,l.createElement(gW,{visible:o}),l.createElement(gK,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gz,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_J,{csaKey:e,key:t})}))))};function _3(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EL,e)};function EI(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(E0,e)},E6=function(){return os(E2)},E9=function(){return os(E3)},E8=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return ry(E4,e)};function E7(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(SZ,e)};function SJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kX(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kJ=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kZ(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kq(kK({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r9.Z,null,l.createElement(aK.Z,null,l.createElement(kG,{object:n})))};function kQ(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function k1(e){for(var t=1;t0&&l.createElement(ko,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kJ,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kj,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k7(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xe(){var e=k7(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return xe=function(){return e},e}var xt=n0(xe(),k9),xn=function(){var e=ry(xt,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(ij,null);if(r)return l.createElement(iN,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k8,{run:i});case"NotFoundError":return l.createElement(oo,null);default:return null}};function xr(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xi(){var e=xr(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xi=function(){return e},e}var xa=n0(xi()),xo=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iw,null,"Job Runs")),t&&l.createElement(ij,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(yg,{runs:o}),l.createElement(ir.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xs(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xu(){var e=xs(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xu=function(){return e},e}var xc=n0(xu(),xa),xl=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=ry(xc,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iN,{error:o}):l.createElement(xo,{loading:a,data:i,page:t,pageSize:n})},xf=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xl,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(xn,null)))},xd=by().shape({name:p2().required("Required"),uri:p2().required("Required"),publicKey:p2().required("Required")}),xh=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hM,{initialValues:t,validationSchema:xd,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hj,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ox.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xp=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xh,{initialValues:r,onSubmit:n})))))};function xb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xm(){var e=xb(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xm=function(){return e},e}var xg=n0(xm()),xv=function(){return ry(xg)};function xy(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(xJ,e)};function x1(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(Tz,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},TW={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TK=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Register Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xh,{initialValues:TW,onSubmit:t})))))};function TV(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return Mm(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mR.Z,{defaultExpanded:0===n,key:n},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(El.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aA,{tooltip:!0},e.createdAt)))),l.createElement(mF.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ox.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gh,{language:"toml",style:gu,"data-testid":"codeblock"},e.definition)))}),l.createElement(oI,{open:null!=c,title:c?M_[c.action].title:"",body:c?M_[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Mo,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function MS(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function Mk(){var e=MS(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return Mk=function(){return e},e}var Mx=n0(Mk(),My),MT=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iw,null,"Job Proposal #",a.id))),l.createElement(Me,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(T$,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ME,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function MM(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(55977),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(55977),a=n(47886),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(97779),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(55977),a=n(15857),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ri,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nr})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;nr,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(23564);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(23564),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},87462(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;tr})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(55977),p=__webpack_require__(15857),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t5(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t9("(",t5(e.variableDefinitions,", "),")"),i=t5(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t5([t,t5([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t9(" = ",r)+t9(" ",t5(i," "))},SelectionSet:function(e){return t6(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t9("",t,": ")+n,s=o+t9("(",t5(r,", "),")");return s.length>t2&&(s=o+t9("(\n",t8(t5(r,"\n")),"\n)")),t5([s,t5(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t9(" ",t5(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t5(["...",t9("on ",t),t5(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t9("(",t5(r,", "),")")," ")+"on ".concat(n," ").concat(t9("",t5(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t5(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t5(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t9("(",t5(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t5(["schema",t5(t," "),t6(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t5(["scalar",e.name,t5(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+": "+r+t9(" ",t5(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t5([t+": "+n,t9("= ",r),t5(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t5(["union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t5(["enum",t,t5(n," "),t6(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t5([e.name,t5(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["input",t,t5(n," "),t6(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+(r?" repeatable":"")+" on "+t5(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t5(["extend schema",t5(t," "),t6(n)]," ")},ScalarTypeExtension:function(e){var t;return t5(["extend scalar",e.name,t5(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t5(["extend union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t5(["extend enum",t,t5(n," "),t6(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["extend input",t,t5(n," "),t6(r)]," ")}};function t4(e){return function(t){return t5([t.description,e(t)],"\n")}}function t5(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t6(e){return t9("{\n",t8(t5(e,"\n")),"\n}")}function t9(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t8(e){return t9(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n5(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n6(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n9(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n8(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e9(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n8(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n8(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r5=new(t_.mr?WeakMap:Map);function r6(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r5.set(e,(r5.get(e)+1)%1e15),n.apply(this,arguments)})}function r9(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r8=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r5.has(n)||(r5.set(n,0),r6(n,"evict"),r6(n,"modify"),r6(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r9(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r9(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r5.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r5.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e8(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r8(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r8&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n6(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r8(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e8(e5(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e9(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e8(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i6(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i9(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i8(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i6(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i5=[];function i6(e,t){var n=e.map;return n.has(t)||n.set(t,i5.pop()||{map:new Map}),n.get(t)}function i9(e,t){if(e===t||!t||i8(t))return e;if(!e||i8(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i9(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i9(t.map.get(n),e.map.get(n)))})}return a}function i8(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i8(r)&&(i5.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","VRFSpec","WebhookSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file +`+(a!==i?`result of cast: ${a}`:""))}return r}_cast(e,t){let n=void 0===e?e:this.transforms.reduce((t,n)=>n.call(this,t,e,this),e);return void 0===n&&(n=this.getDefault()),n}_validate(e,t={},n){let{sync:r,path:i,from:a=[],originalValue:o=e,strict:s=this.spec.strict,abortEarly:u=this.spec.abortEarly}=t,c=e;s||(c=this._cast(c,pU({assert:!1},t)));let l={value:c,path:i,options:t,originalValue:o,schema:this,label:this.spec.label,sync:r,from:a},f=[];this._typeError&&f.push(this._typeError),this._whitelistError&&f.push(this._whitelistError),this._blacklistError&&f.push(this._blacklistError),pA({args:l,value:c,path:i,sync:r,tests:f,endEarly:u},e=>{if(e)return void n(e,c);pA({tests:this.tests,args:l,path:i,sync:r,value:c,endEarly:u},n)})}validate(e,t,n){let r=this.resolve(pU({},t,{value:e}));return"function"==typeof n?r._validate(e,t,n):new Promise((n,i)=>r._validate(e,t,(e,t)=>{e?i(e):n(t)}))}validateSync(e,t){let n;return this.resolve(pU({},t,{value:e}))._validate(e,pU({},t,{sync:!0}),(e,t)=>{if(e)throw e;n=t}),n}isValid(e,t){return this.validate(e,t).then(()=>!0,e=>{if(pM.isError(e))return!1;throw e})}isValidSync(e,t){try{return this.validateSync(e,t),!0}catch(n){if(pM.isError(n))return!1;throw n}}_getDefault(){let e=this.spec.default;return null==e?e:"function"==typeof e?e.call(this):pr(e)}getDefault(e){return this.resolve(e||{})._getDefault()}default(e){return 0===arguments.length?this._getDefault():this.clone({default:e})}strict(e=!0){var t=this.clone();return t.spec.strict=e,t}_isPresent(e){return null!=e}defined(e=pd.defined){return this.test({message:e,name:"defined",exclusive:!0,test:e=>void 0!==e})}required(e=pd.required){return this.clone({presence:"required"}).withMutation(t=>t.test({message:e,name:"required",exclusive:!0,test(e){return this.schema._isPresent(e)}}))}notRequired(){var e=this.clone({presence:"optional"});return e.tests=e.tests.filter(e=>"required"!==e.OPTIONS.name),e}nullable(e=!0){return this.clone({nullable:!1!==e})}transform(e){var t=this.clone();return t.transforms.push(e),t}test(...e){let t;if(void 0===(t=1===e.length?"function"==typeof e[0]?{test:e[0]}:e[0]:2===e.length?{name:e[0],test:e[1]}:{name:e[0],message:e[1],test:e[2]}).message&&(t.message=pd.default),"function"!=typeof t.test)throw TypeError("`test` is a required parameters");let n=this.clone(),r=pj(t),i=t.exclusive||t.name&&!0===n.exclusiveTests[t.name];if(t.exclusive&&!t.name)throw TypeError("Exclusive tests must provide a unique `name` identifying the test");return t.name&&(n.exclusiveTests[t.name]=!!t.exclusive),n.tests=n.tests.filter(e=>e.OPTIONS.name!==t.name||!i&&e.OPTIONS.test!==r.OPTIONS.test),n.tests.push(r),n}when(e,t){Array.isArray(e)||"string"==typeof e||(t=e,e=".");let n=this.clone(),r=pk(e).map(e=>new pN(e));return r.forEach(e=>{e.isSibling&&n.deps.push(e.key)}),n.conditions.push(new pS(r,t)),n}typeError(e){var t=this.clone();return t._typeError=pj({message:e,name:"typeError",test(e){return!!(void 0===e||this.schema.isType(e))||this.createError({params:{type:this.schema._type}})}}),t}oneOf(e,t=pd.oneOf){var n=this.clone();return e.forEach(e=>{n._whitelist.add(e),n._blacklist.delete(e)}),n._whitelistError=pj({message:t,name:"oneOf",test(e){if(void 0===e)return!0;let t=this.schema._whitelist;return!!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}notOneOf(e,t=pd.notOneOf){var n=this.clone();return e.forEach(e=>{n._blacklist.add(e),n._whitelist.delete(e)}),n._blacklistError=pj({message:t,name:"notOneOf",test(e){let t=this.schema._blacklist;return!t.has(e,this.resolve)||this.createError({params:{values:t.toArray().join(", ")}})}}),n}strip(e=!0){let t=this.clone();return t.spec.strip=e,t}describe(){let e=this.clone(),{label:t,meta:n}=e.spec,r={meta:n,label:t,type:e.type,oneOf:e._whitelist.describe(),notOneOf:e._blacklist.describe(),tests:e.tests.map(e=>({name:e.OPTIONS.name,params:e.OPTIONS.params})).filter((e,t,n)=>n.findIndex(t=>t.name===e.name)===t)};return r}}for(let p$ of(pH.prototype.__isYupSchema__=!0,["validate","validateSync"]))pH.prototype[`${p$}At`]=function(e,t,n={}){let{parent:r,parentPath:i,schema:a}=pY(this,e,t,n.context);return a[p$](r&&r[i],pU({},n,{parent:r,path:e}))};for(let pz of["equals","is"])pH.prototype[pz]=pH.prototype.oneOf;for(let pG of["not","nope"])pH.prototype[pG]=pH.prototype.notOneOf;pH.prototype.optional=pH.prototype.notRequired;let pW=pH;function pK(){return new pW}pK.prototype=pW.prototype;let pV=e=>null==e;function pq(){return new pZ}class pZ extends pH{constructor(){super({type:"boolean"}),this.withMutation(()=>{this.transform(function(e){if(!this.isType(e)){if(/^(true|1)$/i.test(String(e)))return!0;if(/^(false|0)$/i.test(String(e)))return!1}return e})})}_typeCheck(e){return e instanceof Boolean&&(e=e.valueOf()),"boolean"==typeof e}isTrue(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"true"},test:e=>pV(e)||!0===e})}isFalse(e=pm.isValue){return this.test({message:e,name:"is-value",exclusive:!0,params:{value:"false"},test:e=>pV(e)||!1===e})}}pq.prototype=pZ.prototype;let pX=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i,pJ=/^((https?|ftp):)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,pQ=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i,p1=e=>pV(e)||e===e.trim(),p0=({}).toString();function p2(){return new p3}class p3 extends pH{constructor(){super({type:"string"}),this.withMutation(()=>{this.transform(function(e){if(this.isType(e)||Array.isArray(e))return e;let t=null!=e&&e.toString?e.toString():e;return t===p0?e:t})})}_typeCheck(e){return e instanceof String&&(e=e.valueOf()),"string"==typeof e}_isPresent(e){return super._isPresent(e)&&!!e.length}length(e,t=ph.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t=ph.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t=ph.max){return this.test({name:"max",exclusive:!0,message:t,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}matches(e,t){let n=!1,r,i;return t&&("object"==typeof t?{excludeEmptyString:n=!1,message:r,name:i}=t:r=t),this.test({name:i||"matches",message:r||ph.matches,params:{regex:e},test:t=>pV(t)||""===t&&n||-1!==t.search(e)})}email(e=ph.email){return this.matches(pX,{name:"email",message:e,excludeEmptyString:!0})}url(e=ph.url){return this.matches(pJ,{name:"url",message:e,excludeEmptyString:!0})}uuid(e=ph.uuid){return this.matches(pQ,{name:"uuid",message:e,excludeEmptyString:!1})}ensure(){return this.default("").transform(e=>null===e?"":e)}trim(e=ph.trim){return this.transform(e=>null!=e?e.trim():e).test({message:e,name:"trim",test:p1})}lowercase(e=ph.lowercase){return this.transform(e=>pV(e)?e:e.toLowerCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toLowerCase()})}uppercase(e=ph.uppercase){return this.transform(e=>pV(e)?e:e.toUpperCase()).test({message:e,name:"string_case",exclusive:!0,test:e=>pV(e)||e===e.toUpperCase()})}}p2.prototype=p3.prototype;let p4=e=>e!=+e;function p5(){return new p6}class p6 extends pH{constructor(){super({type:"number"}),this.withMutation(()=>{this.transform(function(e){let t=e;if("string"==typeof t){if(""===(t=t.replace(/\s/g,"")))return NaN;t=+t}return this.isType(t)?t:parseFloat(t)})})}_typeCheck(e){return e instanceof Number&&(e=e.valueOf()),"number"==typeof e&&!p4(e)}min(e,t=pp.min){return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t>=this.resolve(e)}})}max(e,t=pp.max){return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t<=this.resolve(e)}})}lessThan(e,t=pp.lessThan){return this.test({message:t,name:"max",exclusive:!0,params:{less:e},test(t){return pV(t)||tthis.resolve(e)}})}positive(e=pp.positive){return this.moreThan(0,e)}negative(e=pp.negative){return this.lessThan(0,e)}integer(e=pp.integer){return this.test({name:"integer",message:e,test:e=>pV(e)||Number.isInteger(e)})}truncate(){return this.transform(e=>pV(e)?e:0|e)}round(e){var t,n=["ceil","floor","round","trunc"];if("trunc"===(e=(null==(t=e)?void 0:t.toLowerCase())||"round"))return this.truncate();if(-1===n.indexOf(e.toLowerCase()))throw TypeError("Only valid options for round() are: "+n.join(", "));return this.transform(t=>pV(t)?t:Math[e](t))}}p5.prototype=p6.prototype;var p9=/^(\d{4}|[+\-]\d{6})(?:-?(\d{2})(?:-?(\d{2}))?)?(?:[ T]?(\d{2}):?(\d{2})(?::?(\d{2})(?:[,\.](\d{1,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?)?)?$/;function p8(e){var t,n,r=[1,4,5,6,7,10,11],i=0;if(n=p9.exec(e)){for(var a,o=0;a=r[o];++o)n[a]=+n[a]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,n[7]=n[7]?String(n[7]).substr(0,3):0,(void 0===n[8]||""===n[8])&&(void 0===n[9]||""===n[9])?t=+new Date(n[1],n[2],n[3],n[4],n[5],n[6],n[7]):("Z"!==n[8]&&void 0!==n[9]&&(i=60*n[10]+n[11],"+"===n[9]&&(i=0-i)),t=Date.UTC(n[1],n[2],n[3],n[4],n[5]+i,n[6],n[7]))}else t=Date.parse?Date.parse(e):NaN;return t}let p7=new Date(""),be=e=>"[object Date]"===Object.prototype.toString.call(e);function bt(){return new bn}class bn extends pH{constructor(){super({type:"date"}),this.withMutation(()=>{this.transform(function(e){return this.isType(e)?e:(e=p8(e),isNaN(e)?p7:new Date(e))})})}_typeCheck(e){return be(e)&&!isNaN(e.getTime())}prepareParam(e,t){let n;if(pN.isRef(e))n=e;else{let r=this.cast(e);if(!this._typeCheck(r))throw TypeError(`\`${t}\` must be a Date or a value that can be \`cast()\` to a Date`);n=r}return n}min(e,t=pb.min){let n=this.prepareParam(e,"min");return this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(e){return pV(e)||e>=this.resolve(n)}})}max(e,t=pb.max){var n=this.prepareParam(e,"max");return this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(e){return pV(e)||e<=this.resolve(n)}})}}bn.INVALID_DATE=p7,bt.prototype=bn.prototype,bt.INVALID_DATE=p7;var br=n(11865),bi=n.n(br),ba=n(68929),bo=n.n(ba),bs=n(67523),bu=n.n(bs),bc=n(94633),bl=n.n(bc);function bf(e,t=[]){let n=[],r=[];function i(e,i){var a=(0,pI.split)(e)[0];~r.indexOf(a)||r.push(a),~t.indexOf(`${i}-${a}`)||n.push([i,a])}for(let a in e)if(pw()(e,a)){let o=e[a];~r.indexOf(a)||r.push(a),pN.isRef(o)&&o.isSibling?i(o.path,a):p_(o)&&"deps"in o&&o.deps.forEach(e=>i(e,a))}return bl().array(r,n).reverse()}function bd(e,t){let n=1/0;return e.some((e,r)=>{var i;if((null==(i=t.path)?void 0:i.indexOf(e))!==-1)return n=r,!0}),n}function bh(e){return(t,n)=>bd(e,t)-bd(e,n)}function bp(){return(bp=Object.assign||function(e){for(var t=1;t"[object Object]"===Object.prototype.toString.call(e);function bm(e,t){let n=Object.keys(e.fields);return Object.keys(t).filter(e=>-1===n.indexOf(e))}let bg=bh([]);class bv extends pH{constructor(e){super({type:"object"}),this.fields=Object.create(null),this._sortErrors=bg,this._nodes=[],this._excludedEdges=[],this.withMutation(()=>{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null}),e&&this.shape(e)})}_typeCheck(e){return bb(e)||"function"==typeof e}_cast(e,t={}){var n;let r=super._cast(e,t);if(void 0===r)return this.getDefault();if(!this._typeCheck(r))return r;let i=this.fields,a=null!=(n=t.stripUnknown)?n:this.spec.noUnknown,o=this._nodes.concat(Object.keys(r).filter(e=>-1===this._nodes.indexOf(e))),s={},u=bp({},t,{parent:s,__validating:t.__validating||!1}),c=!1;for(let l of o){let f=i[l],d=pw()(r,l);if(f){let h,p=r[l];u.path=(t.path?`${t.path}.`:"")+l;let b="spec"in(f=f.resolve({value:p,context:t.context,parent:s}))?f.spec:void 0,m=null==b?void 0:b.strict;if(null==b?void 0:b.strip){c=c||l in r;continue}void 0!==(h=t.__validating&&m?r[l]:f.cast(r[l],u))&&(s[l]=h)}else d&&!a&&(s[l]=r[l]);s[l]!==r[l]&&(c=!0)}return c?s:r}_validate(e,t={},n){let r=[],{sync:i,from:a=[],originalValue:o=e,abortEarly:s=this.spec.abortEarly,recursive:u=this.spec.recursive}=t;a=[{schema:this,value:o},...a],t.__validating=!0,t.originalValue=o,t.from=a,super._validate(e,t,(e,c)=>{if(e){if(!pM.isError(e)||s)return void n(e,c);r.push(e)}if(!u||!bb(c)){n(r[0]||null,c);return}o=o||c;let l=this._nodes.map(e=>(n,r)=>{let i=-1===e.indexOf(".")?(t.path?`${t.path}.`:"")+e:`${t.path||""}["${e}"]`,s=this.fields[e];if(s&&"validate"in s){s.validate(c[e],bp({},t,{path:i,from:a,strict:!0,parent:c,originalValue:o[e]}),r);return}r(null)});pA({sync:i,tests:l,value:c,errors:r,endEarly:s,sort:this._sortErrors,path:t.path},n)})}clone(e){let t=super.clone(e);return t.fields=bp({},this.fields),t._nodes=this._nodes,t._excludedEdges=this._excludedEdges,t._sortErrors=this._sortErrors,t}concat(e){let t=super.concat(e),n=t.fields;for(let[r,i]of Object.entries(this.fields)){let a=n[r];void 0===a?n[r]=i:a instanceof pH&&i instanceof pH&&(n[r]=i.concat(a))}return t.withMutation(()=>t.shape(n))}getDefaultFromShape(){let e={};return this._nodes.forEach(t=>{let n=this.fields[t];e[t]="default"in n?n.getDefault():void 0}),e}_getDefault(){return"default"in this.spec?super._getDefault():this._nodes.length?this.getDefaultFromShape():void 0}shape(e,t=[]){let n=this.clone(),r=Object.assign(n.fields,e);if(n.fields=r,n._sortErrors=bh(Object.keys(r)),t.length){Array.isArray(t[0])||(t=[t]);let i=t.map(([e,t])=>`${e}-${t}`);n._excludedEdges=n._excludedEdges.concat(i)}return n._nodes=bf(r,n._excludedEdges),n}pick(e){let t={};for(let n of e)this.fields[n]&&(t[n]=this.fields[n]);return this.clone().withMutation(e=>(e.fields={},e.shape(t)))}omit(e){let t=this.clone(),n=t.fields;for(let r of(t.fields={},e))delete n[r];return t.withMutation(()=>t.shape(n))}from(e,t,n){let r=(0,pI.getter)(e,!0);return this.transform(i=>{if(null==i)return i;let a=i;return pw()(i,e)&&(a=bp({},i),n||delete a[e],a[t]=r(i)),a})}noUnknown(e=!0,t=pg.noUnknown){"string"==typeof e&&(t=e,e=!0);let n=this.test({name:"noUnknown",exclusive:!0,message:t,test(t){if(null==t)return!0;let n=bm(this.schema,t);return!e||0===n.length||this.createError({params:{unknown:n.join(", ")}})}});return n.spec.noUnknown=e,n}unknown(e=!0,t=pg.noUnknown){return this.noUnknown(!e,t)}transformKeys(e){return this.transform(t=>t&&bu()(t,(t,n)=>e(n)))}camelCase(){return this.transformKeys(bo())}snakeCase(){return this.transformKeys(bi())}constantCase(){return this.transformKeys(e=>bi()(e).toUpperCase())}describe(){let e=super.describe();return e.fields=pC()(this.fields,e=>e.describe()),e}}function by(e){return new bv(e)}function bw(){return(bw=Object.assign||function(e){for(var t=1;t{this.transform(function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(t){e=null}return this.isType(e)?e:null})})}_typeCheck(e){return Array.isArray(e)}get _subType(){return this.innerType}_cast(e,t){let n=super._cast(e,t);if(!this._typeCheck(n)||!this.innerType)return n;let r=!1,i=n.map((e,n)=>{let i=this.innerType.cast(e,bw({},t,{path:`${t.path||""}[${n}]`}));return i!==e&&(r=!0),i});return r?i:n}_validate(e,t={},n){var r,i;let a=[],o=t.sync,s=t.path,u=this.innerType,c=null!=(r=t.abortEarly)?r:this.spec.abortEarly,l=null!=(i=t.recursive)?i:this.spec.recursive,f=null!=t.originalValue?t.originalValue:e;super._validate(e,t,(e,r)=>{if(e){if(!pM.isError(e)||c)return void n(e,r);a.push(e)}if(!l||!u||!this._typeCheck(r)){n(a[0]||null,r);return}f=f||r;let i=Array(r.length);for(let d=0;du.validate(h,b,t)}pA({sync:o,path:s,value:r,errors:a,endEarly:c,tests:i},n)})}clone(e){let t=super.clone(e);return t.innerType=this.innerType,t}concat(e){let t=super.concat(e);return t.innerType=this.innerType,e.innerType&&(t.innerType=t.innerType?t.innerType.concat(e.innerType):e.innerType),t}of(e){let t=this.clone();if(!p_(e))throw TypeError("`array.of()` sub-schema must be a valid yup schema not: "+pf(e));return t.innerType=e,t}length(e,t=pv.length){return this.test({message:t,name:"length",exclusive:!0,params:{length:e},test(t){return pV(t)||t.length===this.resolve(e)}})}min(e,t){return t=t||pv.min,this.test({message:t,name:"min",exclusive:!0,params:{min:e},test(t){return pV(t)||t.length>=this.resolve(e)}})}max(e,t){return t=t||pv.max,this.test({message:t,name:"max",exclusive:!0,params:{max:e},test(t){return pV(t)||t.length<=this.resolve(e)}})}ensure(){return this.default(()=>[]).transform((e,t)=>this._typeCheck(e)?e:null==t?[]:[].concat(t))}compact(e){let t=e?(t,n,r)=>!e(t,n,r):e=>!!e;return this.transform(e=>null!=e?e.filter(t):e)}describe(){let e=super.describe();return this.innerType&&(e.innerType=this.innerType.describe()),e}nullable(e=!0){return super.nullable(e)}defined(){return super.defined()}required(e){return super.required(e)}}b_.prototype=bE.prototype;var bS=by().shape({name:p2().required("Required"),url:p2().required("Required")}),bk=function(e){var t=e.initialValues,n=e.onSubmit,r=e.submitButtonText,i=e.nameDisabled,a=void 0!==i&&i;return l.createElement(hM,{initialValues:t,validationSchema:bS,onSubmit:n},function(e){var t=e.isSubmitting;return l.createElement(l.Fragment,null,l.createElement(hj,{"data-testid":"bridge-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",disabled:a,required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(hR,{component:hJ,id:"url",name:"url",label:"Bridge URL",placeholder:"https://",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"url-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"minimumContractPayment",name:"minimumContractPayment",label:"Minimum Contract Payment",placeholder:"0",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"minimumContractPayment-helper-text"}})),l.createElement(d.Z,{item:!0,xs:7},l.createElement(hR,{component:hJ,id:"confirmations",name:"confirmations",label:"Confirmations",placeholder:"0",type:"number",fullWidth:!0,inputProps:{min:0},FormHelperTextProps:{"data-testid":"confirmations-helper-text"}})))),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},r)))))})},bx=function(e){var t=e.bridge,n=e.onSubmit,r={name:t.name,url:t.url,minimumContractPayment:t.minimumContractPayment,confirmations:t.confirmations};return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:40},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Bridge",action:l.createElement(aL.Z,{component:tz,href:"/bridges/".concat(t.id)},"Cancel")}),l.createElement(aK.Z,null,l.createElement(bk,{nameDisabled:!0,initialValues:r,onSubmit:n,submitButtonText:"Save Bridge"}))))))};function bT(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]&&arguments[0],t=e?function(){return l.createElement(x.default,{variant:"body1"},"Loading...")}:function(){return null};return{isLoading:e,LoadingPlaceholder:t}},ml=n(76023);function mf(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=0||(i[n]=e[n]);return i}function mB(e,t){if(null==e)return{};var n,r,i=mY(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function mU(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=4?[e[0],e[1],e[2],e[3],"".concat(e[0],".").concat(e[1]),"".concat(e[0],".").concat(e[2]),"".concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[0]),"".concat(e[1],".").concat(e[2]),"".concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[1]),"".concat(e[2],".").concat(e[3]),"".concat(e[3],".").concat(e[0]),"".concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[0]),"".concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[0],".").concat(e[1],".").concat(e[2],".").concat(e[3]),"".concat(e[0],".").concat(e[1],".").concat(e[3],".").concat(e[2]),"".concat(e[0],".").concat(e[2],".").concat(e[1],".").concat(e[3]),"".concat(e[0],".").concat(e[2],".").concat(e[3],".").concat(e[1]),"".concat(e[0],".").concat(e[3],".").concat(e[1],".").concat(e[2]),"".concat(e[0],".").concat(e[3],".").concat(e[2],".").concat(e[1]),"".concat(e[1],".").concat(e[0],".").concat(e[2],".").concat(e[3]),"".concat(e[1],".").concat(e[0],".").concat(e[3],".").concat(e[2]),"".concat(e[1],".").concat(e[2],".").concat(e[0],".").concat(e[3]),"".concat(e[1],".").concat(e[2],".").concat(e[3],".").concat(e[0]),"".concat(e[1],".").concat(e[3],".").concat(e[0],".").concat(e[2]),"".concat(e[1],".").concat(e[3],".").concat(e[2],".").concat(e[0]),"".concat(e[2],".").concat(e[0],".").concat(e[1],".").concat(e[3]),"".concat(e[2],".").concat(e[0],".").concat(e[3],".").concat(e[1]),"".concat(e[2],".").concat(e[1],".").concat(e[0],".").concat(e[3]),"".concat(e[2],".").concat(e[1],".").concat(e[3],".").concat(e[0]),"".concat(e[2],".").concat(e[3],".").concat(e[0],".").concat(e[1]),"".concat(e[2],".").concat(e[3],".").concat(e[1],".").concat(e[0]),"".concat(e[3],".").concat(e[0],".").concat(e[1],".").concat(e[2]),"".concat(e[3],".").concat(e[0],".").concat(e[2],".").concat(e[1]),"".concat(e[3],".").concat(e[1],".").concat(e[0],".").concat(e[2]),"".concat(e[3],".").concat(e[1],".").concat(e[2],".").concat(e[0]),"".concat(e[3],".").concat(e[2],".").concat(e[0],".").concat(e[1]),"".concat(e[3],".").concat(e[2],".").concat(e[1],".").concat(e[0])]:void 0}var mX={};function mJ(e){if(0===e.length||1===e.length)return e;var t=e.join(".");return mX[t]||(mX[t]=mZ(e)),mX[t]}function mQ(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;return mJ(e.filter(function(e){return"token"!==e})).reduce(function(e,t){return mV({},e,n[t])},t)}function m1(e){return e.join(" ")}function m0(e,t){var n=0;return function(r){return n+=1,r.map(function(r,i){return m2({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(i)})})}}function m2(e){var t=e.node,n=e.stylesheet,r=e.style,i=void 0===r?{}:r,a=e.useInlineStyles,o=e.key,s=t.properties,u=t.type,c=t.tagName,f=t.value;if("text"===u)return f;if(c){var d,h=m0(n,a);if(a){var p=Object.keys(n).reduce(function(e,t){return t.split(".").forEach(function(t){e.includes(t)||e.push(t)}),e},[]),b=s.className&&s.className.includes("token")?["token"]:[],m=s.className&&b.concat(s.className.filter(function(e){return!p.includes(e)}));d=mV({},s,{className:m1(m)||void 0,style:mQ(s.className,Object.assign({},s.style,i),n)})}else d=mV({},s,{className:m1(s.className)});var g=h(t.children);return l.createElement(c,mq({key:o},d),g)}}let m3=function(e,t){return -1!==e.listLanguages().indexOf(t)};var m4=/\n/g;function m5(e){return e.match(m4)}function m6(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map(function(e,t){var i=t+n;return l.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(i):r},"".concat(i,"\n"))})}function m9(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,i=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,o=void 0===a?{}:a,s=e.startingLineNumber;return l.createElement("code",{style:Object.assign({},n,i)},m6({lines:t.replace(/\n$/,"").split("\n"),style:o,startingLineNumber:s}))}function m8(e){return"".concat(e.toString().length,".25em")}function m7(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function ge(e,t,n){var r,i={display:"inline-block",minWidth:m8(n),paddingRight:"1em",textAlign:"right",userSelect:"none"};return mV({},i,"function"==typeof e?e(t):e)}function gt(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,i=e.largestLineNumber,a=e.showInlineLineNumbers,o=e.lineProps,s=void 0===o?{}:o,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,f=e.wrapLongLines,d="function"==typeof s?s(n):s;if(d.className=c,n&&a){var h=ge(r,n,i);t.unshift(m7(n,h))}return f&l&&(d.style=mV({},d.style,{display:"flex"})),{type:"element",tagName:"span",properties:d,children:t}}function gn(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return gt({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:o,showInlineLineNumbers:i,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function b(e,t){if(r&&t&&i){var n=ge(s,t,o);e.unshift(m7(t,n))}return e}function m(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?p(e,n,r):b(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(m5(t)){var n=t.split("\n");n.forEach(function(t,i){var o=r&&f.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===i){var u=l.slice(d+1,h).concat(gt({children:[s],className:e.properties.className})),c=m(u,o);f.push(c)}else if(i===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var p={type:"text",value:"".concat(t)},b=gt({children:[p],className:e.properties.className});l.splice(h+1,0,b)}else{var g=[s],v=m(g,o,e.properties.className);f.push(v)}}else{var y=[s],w=m(y,o,e.properties.className);f.push(w)}}),d=h}h++};h code[class*="language-"]':{background:"#f5f2f0",padding:".1em",borderRadius:".3em",whiteSpace:"normal"},comment:{color:"slategray"},prolog:{color:"slategray"},doctype:{color:"slategray"},cdata:{color:"slategray"},punctuation:{color:"#999"},namespace:{Opacity:".7"},property:{color:"#905"},tag:{color:"#905"},boolean:{color:"#905"},number:{color:"#905"},constant:{color:"#905"},symbol:{color:"#905"},deleted:{color:"#905"},selector:{color:"#690"},"attr-name":{color:"#690"},string:{color:"#690"},char:{color:"#690"},builtin:{color:"#690"},inserted:{color:"#690"},operator:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},entity:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)",cursor:"help"},url:{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".language-css .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},".style .token.string":{color:"#9a6e3a",background:"hsla(0, 0%, 100%, .5)"},atrule:{color:"#07a"},"attr-value":{color:"#07a"},keyword:{color:"#07a"},function:{color:"#DD4A68"},"class-name":{color:"#DD4A68"},regex:{color:"#e90"},important:{color:"#e90",fontWeight:"bold"},variable:{color:"#e90"},bold:{fontWeight:"bold"},italic:{fontStyle:"italic"}};var gc=n(98695),gl=n.n(gc);let gf=["abap","abnf","actionscript","ada","agda","al","antlr4","apacheconf","apl","applescript","aql","arduino","arff","asciidoc","asm6502","aspnet","autohotkey","autoit","bash","basic","batch","bbcode","birb","bison","bnf","brainfuck","brightscript","bro","bsl","c","cil","clike","clojure","cmake","coffeescript","concurnas","cpp","crystal","csharp","csp","css-extras","css","cypher","d","dart","dax","dhall","diff","django","dns-zone-file","docker","ebnf","editorconfig","eiffel","ejs","elixir","elm","erb","erlang","etlua","excel-formula","factor","firestore-security-rules","flow","fortran","fsharp","ftl","gcode","gdscript","gedcom","gherkin","git","glsl","gml","go","graphql","groovy","haml","handlebars","haskell","haxe","hcl","hlsl","hpkp","hsts","http","ichigojam","icon","iecst","ignore","inform7","ini","io","j","java","javadoc","javadoclike","javascript","javastacktrace","jolie","jq","js-extras","js-templates","jsdoc","json","json5","jsonp","jsstacktrace","jsx","julia","keyman","kotlin","latex","latte","less","lilypond","liquid","lisp","livescript","llvm","lolcode","lua","makefile","markdown","markup-templating","markup","matlab","mel","mizar","mongodb","monkey","moonscript","n1ql","n4js","nand2tetris-hdl","naniscript","nasm","neon","nginx","nim","nix","nsis","objectivec","ocaml","opencl","oz","parigp","parser","pascal","pascaligo","pcaxis","peoplecode","perl","php-extras","php","phpdoc","plsql","powerquery","powershell","processing","prolog","properties","protobuf","pug","puppet","pure","purebasic","purescript","python","q","qml","qore","r","racket","reason","regex","renpy","rest","rip","roboconf","robotframework","ruby","rust","sas","sass","scala","scheme","scss","shell-session","smali","smalltalk","smarty","sml","solidity","solution-file","soy","sparql","splunk-spl","sqf","sql","stan","stylus","swift","t4-cs","t4-templating","t4-vb","tap","tcl","textile","toml","tsx","tt2","turtle","twig","typescript","typoscript","unrealscript","vala","vbnet","velocity","verilog","vhdl","vim","visual-basic","warpscript","wasm","wiki","xeora","xml-doc","xojo","xquery","yaml","yang","zig"];var gd=gs(gl(),gu);gd.supportedLanguages=gf;let gh=gd;var gp=n(64566);function gb(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function gm(){var e=gb(["\n query FetchConfigV2 {\n configv2 {\n user\n effective\n }\n }\n"]);return gm=function(){return e},e}var gg=n0(gm()),gv=function(e){var t=e.children;return l.createElement(ii.Z,null,l.createElement(ie.default,{component:"th",scope:"row",colSpan:3},t))},gy=function(){return l.createElement(gv,null,"...")},gw=function(e){var t=e.children;return l.createElement(gv,null,t)},g_=function(e){var t=e.loading,n=e.toml,r=e.error,i=void 0===r?"":r,a=e.title,o=e.expanded;if(i)return l.createElement(gw,null,i);if(t)return l.createElement(gy,null);a||(a="TOML");var s={display:"block"};return l.createElement(x.default,null,l.createElement(mR.Z,{defaultExpanded:o},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},a),l.createElement(mF.Z,{style:s},l.createElement(gh,{language:"toml",style:gu},n))))},gE=function(){var e=ry(gg,{fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return(null==t?void 0:t.configv2.effective)=="N/A"?l.createElement(l.Fragment,null,l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(g_,{title:"V2 config dump:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0})))):l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"TOML Configuration"}),l.createElement(g_,{title:"User specified:",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.user,showHead:!0,expanded:!0}),l.createElement(g_,{title:"Effective (with defaults):",error:null==r?void 0:r.message,loading:n,toml:null==t?void 0:t.configv2.effective,showHead:!0})))))},gS=n(34823),gk=function(e){return(0,b.createStyles)({cell:{paddingTop:1.5*e.spacing.unit,paddingBottom:1.5*e.spacing.unit}})},gx=(0,b.withStyles)(gk)(function(e){var t=e.classes,n=(0,A.I0)();(0,l.useEffect)(function(){n((0,ty.DQ)())});var r=(0,A.v9)(gS.N,A.wU);return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Node"}),l.createElement(r8.Z,null,l.createElement(r7.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"Version"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.version))),l.createElement(ii.Z,null,l.createElement(ie.default,{className:t.cell},l.createElement(x.default,null,"SHA"),l.createElement(x.default,{variant:"subtitle1",color:"textSecondary"},r.commitSHA))))))}),gT=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,sm:12,md:8},l.createElement(d.Z,{container:!0},l.createElement(gE,null))),l.createElement(d.Z,{item:!0,sm:12,md:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gx,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mP,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(mS,null))))))},gM=function(){return l.createElement(gT,null)},gO=function(){return l.createElement(gM,null)},gA=n(44431),gL=1e18,gC=function(e){return new gA.BigNumber(e).dividedBy(gL).toFixed(8)},gI=function(e){var t=e.keys,n=e.chainID,r=e.hideHeaderTitle;return l.createElement(l.Fragment,null,l.createElement(sf.Z,{title:!r&&"Account Balances",subheader:"Chain ID "+n}),l.createElement(aK.Z,null,l.createElement(w.default,{dense:!1,disablePadding:!0},t&&t.map(function(e,r){return l.createElement(l.Fragment,null,l.createElement(_.default,{disableGutters:!0,key:["acc-balance",n.toString(),r.toString()].join("-")},l.createElement(E.Z,{primary:l.createElement(l.Fragment,null,l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ob,{title:"Address"}),l.createElement(om,{value:e.address})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"Native Token Balance"}),l.createElement(om,{value:e.ethBalance||"--"})),l.createElement(d.Z,{item:!0,xs:6},l.createElement(ob,{title:"LINK Balance"}),l.createElement(om,{value:e.linkBalance?gC(e.linkBalance):"--"}))))})),r+1s&&l.createElement(gU.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,{className:r.footer},l.createElement(aL.Z,{href:"/runs",component:tz},"View More"))))))});function vn(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vr(){var e=vn(["\n ","\n query FetchRecentJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...RecentJobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return vr=function(){return e},e}var vi=5,va=n0(vr(),g7),vo=function(){var e=ry(va,{variables:{offset:0,limit:vi},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vt,{data:t,errorMsg:null==r?void 0:r.message,loading:n,maxRunsSize:vi})},vs=function(e){return(0,b.createStyles)({style:{textAlign:"center",padding:2.5*e.spacing.unit,position:"fixed",left:"0",bottom:"0",width:"100%",borderRadius:0},bareAnchor:{color:e.palette.common.black,textDecoration:"none"}})},vu=(0,b.withStyles)(vs)(function(e){var t=e.classes,n=(0,A.v9)(gS.N,A.wU),r=(0,A.I0)();return(0,l.useEffect)(function(){r((0,ty.DQ)())}),l.createElement(ia.default,{className:t.style},l.createElement(x.default,null,"Chainlink Node ",n.version," at commit"," ",l.createElement("a",{target:"_blank",rel:"noopener noreferrer",href:"https://github.com/smartcontractkit/chainlink/commit/".concat(n.commitSHA),className:t.bareAnchor},n.commitSHA)))}),vc=function(e){return(0,b.createStyles)({cell:{borderColor:e.palette.divider,borderTop:"1px solid",borderBottom:"none",paddingTop:2*e.spacing.unit,paddingBottom:2*e.spacing.unit,paddingLeft:2*e.spacing.unit},block:{display:"block"},overflowEllipsis:{textOverflow:"ellipsis",overflow:"hidden"}})},vl=(0,b.withStyles)(vc)(function(e){var t=e.classes,n=e.job;return l.createElement(ii.Z,null,l.createElement(ie.default,{scope:"row",className:t.cell},l.createElement(d.Z,{container:!0,spacing:0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(ip,{href:"/jobs/".concat(n.id),classes:{linkContent:t.block}},l.createElement(x.default,{className:t.overflowEllipsis,variant:"body1",component:"span",color:"primary"},n.name||n.id))),l.createElement(d.Z,{item:!0,xs:12},l.createElement(x.default,{variant:"body1",color:"textSecondary"},"Created ",l.createElement(aA,{tooltip:!0},n.createdAt))))))});function vf(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vd(){var e=vf(["\n fragment RecentJobsPayload_ResultsFields on Job {\n id\n name\n createdAt\n }\n"]);return vd=function(){return e},e}var vh=n0(vd()),vp=function(){return(0,b.createStyles)({cardHeader:{borderBottom:0},table:{tableLayout:"fixed"}})},vb=(0,b.withStyles)(vp)(function(e){var t,n,r=e.classes,i=e.data,a=e.errorMsg,o=e.loading;return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Recent Jobs",className:r.cardHeader}),l.createElement(r8.Z,{className:r.table},l.createElement(r7.Z,null,l.createElement(gz,{visible:o}),l.createElement(gG,{visible:(null===(t=null==i?void 0:i.jobs.results)||void 0===t?void 0:t.length)===0},"No recently created jobs"),l.createElement(gH,{msg:a}),null===(n=null==i?void 0:i.jobs.results)||void 0===n?void 0:n.map(function(e,t){return l.createElement(vl,{job:e,key:t})}))))});function vm(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function vg(){var e=vm(["\n ","\n query FetchRecentJobs($offset: Int, $limit: Int) {\n jobs(offset: $offset, limit: $limit) {\n results {\n ...RecentJobsPayload_ResultsFields\n }\n }\n }\n"]);return vg=function(){return e},e}var vv=5,vy=n0(vg(),vh),vw=function(){var e=ry(vy,{variables:{offset:0,limit:vv},fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error;return l.createElement(vb,{data:t,errorMsg:null==r?void 0:r.message,loading:n})},v_=function(){return l.createElement(iv,null,l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:8},l.createElement(vo,null)),l.createElement(d.Z,{item:!0,xs:4},l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12},l.createElement(gB,null)),l.createElement(d.Z,{item:!0,xs:12},l.createElement(vw,null))))),l.createElement(vu,null))},vE=function(){return l.createElement(v_,null)},vS=function(){return l.createElement(vE,null)},vk=n(87239),vx=function(e){switch(e){case"DirectRequestSpec":return"Direct Request";case"FluxMonitorSpec":return"Flux Monitor";default:return e.replace(/Spec$/,"")}},vT=n(5022),vM=n(78718),vO=n.n(vM);function vA(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1?t-1:0),r=1;r1?t-1:0),r=1;re.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&n.map(function(e){return l.createElement(ii.Z,{key:e.id,style:{cursor:"pointer"},onClick:function(){return r.push("/runs/".concat(e.id))}},l.createElement(ie.default,{className:t.idCell,scope:"row"},l.createElement("div",{className:t.runDetails},l.createElement(x.default,{variant:"h5",color:"primary",component:"span"},e.id))),l.createElement(ie.default,{className:t.stampCell},l.createElement(x.default,{variant:"body1",color:"textSecondary",className:t.stamp},"Created ",l.createElement(aA,{tooltip:!0},e.createdAt))),l.createElement(ie.default,{className:t.statusCell,scope:"row"},l.createElement(x.default,{variant:"body1",className:O()(t.status,yp(t,e.status))},e.status.toLowerCase())))})))}),ym=n(16839),yg=n.n(ym);function yv(e){var t=e.replace(/\w+\s*=\s*<([^>]|[\r\n])*>/g,""),n=yg().read(t),r=n.edges();return n.nodes().map(function(e){var t={id:e,parentIds:r.filter(function(t){return t.w===e}).map(function(e){return e.v})};return Object.keys(n.node(e)).length>0&&(t.attributes=n.node(e)),t})}var yy=n(94164),yw=function(e){var t=e.data,n=[];return(null==t?void 0:t.attributes)&&Object.keys(t.attributes).forEach(function(e){var r;n.push(l.createElement("div",{key:e},l.createElement(x.default,{variant:"body1",color:"textSecondary",component:"div"},l.createElement("b",null,e,":")," ",null===(r=t.attributes)||void 0===r?void 0:r[e])))}),l.createElement("div",null,t&&l.createElement(x.default,{variant:"body1",color:"textPrimary"},l.createElement("b",null,t.id)),n)},y_=n(73343),yE=n(3379),yS=n.n(yE);function yk(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nwindow.innerWidth?u-r.getBoundingClientRect().width-a:u+a,n=c+r.getBoundingClientRect().height+i>window.innerHeight?c-r.getBoundingClientRect().height-a:c+a,r.style.opacity=String(1),r.style.top="".concat(n,"px"),r.style.left="".concat(t,"px"),r.style.zIndex=String(1)}},h=function(e){var t=document.getElementById("tooltip-d3-chart-".concat(e));t&&(t.style.opacity=String(0),t.style.zIndex=String(-1))};return l.createElement("div",{style:{fontFamily:"sans-serif",fontWeight:"normal"}},l.createElement(yy.kJ,{id:"task-list-graph-d3",data:i,config:s,onMouseOverNode:d,onMouseOutNode:h},"D3 chart"),n.map(function(e){return l.createElement("div",{key:"d3-tooltip-key-".concat(e.id),id:"tooltip-d3-chart-".concat(e.id),style:{position:"absolute",opacity:"0",border:"1px solid rgba(0, 0, 0, 0.1)",padding:y_.r.spacing.unit,background:"white",borderRadius:5,zIndex:-1,inlineSize:"min-content"}},l.createElement(yw,{data:e}))}))};function yC(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);nyB&&l.createElement("div",{className:t.runDetails},l.createElement(aL.Z,{href:"/jobs/".concat(n.id,"/runs"),component:tz},"View more")))),l.createElement(d.Z,{item:!0,xs:12,sm:6},l.createElement(yY,{observationSource:n.observationSource})))});function y$(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&void 0!==arguments[0]?arguments[0]:"";try{return vT.parse(e),!0}catch(t){return!1}})}),wK=function(e){var t=e.initialValues,n=e.onSubmit,r=e.onTOMLChange;return l.createElement(hM,{initialValues:t,validationSchema:wW,onSubmit:n},function(e){var t=e.isSubmitting,n=e.values;return r&&r(n.toml),l.createElement(hj,{"data-testid":"job-form",noValidate:!0},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12},l.createElement(hR,{component:hJ,id:"toml",name:"toml",label:"Job Spec (TOML)",required:!0,fullWidth:!0,multiline:!0,rows:10,rowsMax:25,variant:"outlined",autoComplete:"off",FormHelperTextProps:{"data-testid":"toml-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:7},l.createElement(ox.default,{variant:"contained",color:"primary",type:"submit",disabled:t,size:"large"},"Create Job"))))})},wV=n(50109),wq="persistSpec";function wZ(e){var t=e.query,n=new URLSearchParams(t).get("definition");return n?(wV.t8(wq,n),{toml:n}):{toml:wV.U2(wq)||""}}var wX=function(e){var t=e.onSubmit,n=e.onTOMLChange,r=wZ({query:(0,h.TH)().search}),i=function(e){var t=e.replace(/[\u200B-\u200D\uFEFF]/g,"");wV.t8("".concat(wq),t),n&&n(t)};return l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"New Job"}),l.createElement(aK.Z,null,l.createElement(wK,{initialValues:r,onSubmit:t,onTOMLChange:i})))};function wJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:{},n=t.start,r=void 0===n?6:n,i=t.end,a=void 0===i?4:i;return e.substring(0,r)+"..."+e.substring(e.length-a)}function _O(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(_K,e)},_q=function(){var e=_V({fetchPolicy:"cache-and-network"}),t=e.data,n=e.loading,r=e.error,i=e.refetch;return l.createElement(_H,{loading:n,data:t,errorMsg:null==r?void 0:r.message,refetch:i})},_Z=function(e){var t=e.csaKey;return l.createElement(ii.Z,{hover:!0},l.createElement(ie.default,null,l.createElement(x.default,{variant:"body1"},t.publicKey," ",l.createElement(_T,{data:t.publicKey}))))};function _X(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _J(){var e=_X(["\n fragment CSAKeysPayload_ResultsFields on CSAKey {\n id\n publicKey\n }\n"]);return _J=function(){return e},e}var _Q=n0(_J()),_1=function(e){var t,n,r,i=e.data,a=e.errorMsg,o=e.loading,s=e.onCreate;return l.createElement(r9.Z,null,l.createElement(sf.Z,{action:(null===(t=null==i?void 0:i.csaKeys.results)||void 0===t?void 0:t.length)===0&&l.createElement(ox.default,{variant:"outlined",color:"primary",onClick:s},"New CSA Key"),title:"CSA Key",subheader:"Manage your CSA Key"}),l.createElement(r8.Z,null,l.createElement(it.Z,null,l.createElement(ii.Z,null,l.createElement(ie.default,null,"Public Key"))),l.createElement(r7.Z,null,l.createElement(gz,{visible:o}),l.createElement(gG,{visible:(null===(n=null==i?void 0:i.csaKeys.results)||void 0===n?void 0:n.length)===0}),l.createElement(gH,{msg:a}),null===(r=null==i?void 0:i.csaKeys.results)||void 0===r?void 0:r.map(function(e,t){return l.createElement(_Z,{csaKey:e,key:t})}))))};function _0(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EO,e)};function EL(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(EQ,e)},E4=function(){return os(E1)},E5=function(){return os(E0)},E6=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return ry(E2,e)};function E9(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(SV,e)};function SZ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);n=0)&&Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function kq(e,t){if(null==e)return{};var n,r,i={},a=Object.keys(e);for(r=0;r=0||(i[n]=e[n]);return i}var kZ=function(e){var t=e.run,n=l.useMemo(function(){var e=t.inputs,n=t.outputs,r=t.taskRuns,i=kV(t,["inputs","outputs","taskRuns"]),a={};try{a=JSON.parse(e)}catch(o){a={}}return kK(kG({},i),{inputs:a,outputs:n,taskRuns:r})},[t]);return l.createElement(r9.Z,null,l.createElement(aK.Z,null,l.createElement(k$,{object:n})))};function kX(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function kJ(e){for(var t=1;t0&&l.createElement(ki,{errors:t.allErrors})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(h.rs,null,l.createElement(h.AW,{path:"".concat(n,"/json")},l.createElement(kZ,{run:t})),l.createElement(h.AW,{path:n},t.taskRuns.length>0&&l.createElement(kP,{taskRuns:t.taskRuns,observationSource:t.job.observationSource}))))))))};function k9(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function k8(){var e=k9(["\n ","\n query FetchJobRun($id: ID!) {\n jobRun(id: $id) {\n __typename\n ... on JobRun {\n ...JobRunPayload_Fields\n }\n ... on NotFoundError {\n message\n }\n }\n }\n"]);return k8=function(){return e},e}var k7=n0(k8(),k5),xe=function(){var e=ry(k7,{variables:{id:(0,h.UO)().id}}),t=e.data,n=e.loading,r=e.error;if(n)return l.createElement(ij,null);if(r)return l.createElement(iN,{error:r});var i=null==t?void 0:t.jobRun;switch(null==i?void 0:i.__typename){case"JobRun":return l.createElement(k6,{run:i});case"NotFoundError":return l.createElement(oo,null);default:return null}};function xt(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xn(){var e=xt(["\n fragment JobRunsPayload_ResultsFields on JobRun {\n id\n allErrors\n createdAt\n finishedAt\n status\n job {\n id\n }\n }\n"]);return xn=function(){return e},e}var xr=n0(xn()),xi=function(e){var t=e.loading,n=e.data,r=e.page,i=e.pageSize,a=(0,h.k6)(),o=l.useMemo(function(){return null==n?void 0:n.jobRuns.results.map(function(e){var t,n=e.allErrors,r=e.id,i=e.createdAt;return{id:r,createdAt:i,errors:n,finishedAt:e.finishedAt,status:e.status}})},[n]);return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(iw,null,"Job Runs")),t&&l.createElement(ij,null),n&&o&&l.createElement(d.Z,{item:!0,xs:12},l.createElement(r9.Z,null,l.createElement(yb,{runs:o}),l.createElement(ir.Z,{component:"div",count:n.jobRuns.metadata.total,rowsPerPage:i,rowsPerPageOptions:[i],page:r-1,onChangePage:function(e,t){a.push("/runs?page=".concat(t+1,"&per=").concat(i))},onChangeRowsPerPage:function(){},backIconButtonProps:{"aria-label":"prev-page"},nextIconButtonProps:{"aria-label":"next-page"}})))))};function xa(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xo(){var e=xa(["\n ","\n query FetchJobRuns($offset: Int, $limit: Int) {\n jobRuns(offset: $offset, limit: $limit) {\n results {\n ...JobRunsPayload_ResultsFields\n }\n metadata {\n total\n }\n }\n }\n"]);return xo=function(){return e},e}var xs=n0(xo(),xr),xu=function(){var e=iF(),t=parseInt(e.get("page")||"1",10),n=parseInt(e.get("per")||"25",10),r=ry(xs,{variables:{offset:(t-1)*n,limit:n},fetchPolicy:"cache-and-network"}),i=r.data,a=r.loading,o=r.error;return o?l.createElement(iN,{error:o}):l.createElement(xi,{loading:a,data:i,page:t,pageSize:n})},xc=function(){var e=(0,h.$B)().path;return l.createElement(h.rs,null,l.createElement(h.AW,{exact:!0,path:e},l.createElement(xu,null)),l.createElement(h.AW,{path:"".concat(e,"/:id")},l.createElement(xe,null)))},xl=by().shape({name:p2().required("Required"),uri:p2().required("Required"),publicKey:p2().required("Required")}),xf=function(e){var t=e.initialValues,n=e.onSubmit;return l.createElement(hM,{initialValues:t,validationSchema:xl,onSubmit:n},function(e){var t=e.isSubmitting,n=e.submitForm;return l.createElement(hj,{"data-testid":"feeds-manager-form"},l.createElement(d.Z,{container:!0,spacing:16},l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"name",name:"name",label:"Name",required:!0,fullWidth:!0,FormHelperTextProps:{"data-testid":"name-helper-text"}})),l.createElement(d.Z,{item:!0,xs:!1,md:6}),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"uri",name:"uri",label:"URI",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"uri-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12,md:6},l.createElement(hR,{component:hJ,id:"publicKey",name:"publicKey",label:"Public Key",required:!0,fullWidth:!0,helperText:"Provided by the Feeds Manager operator",FormHelperTextProps:{"data-testid":"publicKey-helper-text"}})),l.createElement(d.Z,{item:!0,xs:12},l.createElement(ox.default,{variant:"contained",color:"primary",disabled:t,onClick:n},"Submit"))))})},xd=function(e){var t=e.data,n=e.onSubmit,r={name:t.name,uri:t.uri,publicKey:t.publicKey};return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Edit Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xf,{initialValues:r,onSubmit:n})))))};function xh(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function xp(){var e=xh(["\n query FetchFeedsManagers {\n feedsManagers {\n results {\n __typename\n id\n name\n uri\n publicKey\n isConnectionActive\n createdAt\n }\n }\n }\n"]);return xp=function(){return e},e}var xb=n0(xp()),xm=function(){return ry(xb)};function xg(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&void 0!==arguments[0]?arguments[0]:{};return ry(xZ,e)};function xJ(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);n0?n.feedsManagers.results[0]:void 0;return n&&a?l.createElement(TH,{manager:a}):l.createElement(h.l_,{to:{pathname:"/feeds_manager/new",state:{from:e}}})},Tz={name:"Chainlink Feeds Manager",uri:"",publicKey:""},TG=function(e){var t=e.onSubmit;return l.createElement(d.Z,{container:!0},l.createElement(d.Z,{item:!0,xs:12,md:11,lg:9},l.createElement(r9.Z,null,l.createElement(sf.Z,{title:"Register Feeds Manager"}),l.createElement(aK.Z,null,l.createElement(xf,{initialValues:Tz,onSubmit:t})))))};function TW(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);nt.version?e:t})},[o]),g=l.useMemo(function(){return Mp(o).sort(function(e,t){return t.version-e.version})},[o]),v=function(e,t,n){switch(e){case"PENDING":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"text",color:"secondary",onClick:function(){return b("reject",t)}},"Reject"),m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status&&l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve"),m.id===t&&"DELETED"===n.status&&n.pendingUpdate&&l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("cancel",t)}},"Cancel"),l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs")));case"APPROVED":return l.createElement(l.Fragment,null,l.createElement(ox.default,{variant:"contained",onClick:function(){return b("cancel",t)}},"Cancel"),"DELETED"===n.status&&n.pendingUpdate&&l.createElement(x.default,{color:"error"},"This proposal was deleted. Cancel the spec to delete any running jobs"));case"CANCELLED":if(m.id===t&&"DELETED"!==n.status&&"REVOKED"!==n.status)return l.createElement(ox.default,{variant:"contained",color:"primary",onClick:function(){return b("approve",t)}},"Approve");return null;default:return null}};return l.createElement("div",null,g.map(function(e,n){return l.createElement(mR.Z,{defaultExpanded:0===n,key:n},l.createElement(mj.Z,{expandIcon:l.createElement(gp.Z,null)},l.createElement(x.default,{className:t.versionText},"Version ",e.version),l.createElement(Eu.Z,{label:e.status,color:"APPROVED"===e.status?"primary":"default",variant:"REJECTED"===e.status||"CANCELLED"===e.status?"outlined":"default"}),l.createElement("div",{className:t.proposedAtContainer},l.createElement(x.default,null,"Proposed ",l.createElement(aA,{tooltip:!0},e.createdAt)))),l.createElement(mF.Z,{className:t.expansionPanelDetails},l.createElement("div",{className:t.actions},l.createElement("div",{className:t.editContainer},0===n&&("PENDING"===e.status||"CANCELLED"===e.status)&&"DELETED"!==s.status&&"REVOKED"!==s.status&&l.createElement(ox.default,{variant:"contained",onClick:function(){return p(!0)}},"Edit")),l.createElement("div",{className:t.actionsContainer},v(e.status,e.id,s))),l.createElement(gh,{language:"toml",style:gu,"data-testid":"codeblock"},e.definition)))}),l.createElement(oI,{open:null!=c,title:c?My[c.action].title:"",body:c?My[c.action].body:"",onConfirm:function(){if(c){switch(c.action){case"approve":n(c.id);break;case"cancel":r(c.id);break;case"reject":i(c.id)}f(null)}},cancelButtonText:"Cancel",onCancel:function(){return f(null)}}),l.createElement(Mi,{open:h,onClose:function(){return p(!1)},initialValues:{definition:m.definition,id:m.id},onSubmit:a}))});function M_(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function ME(){var e=M_(["\n ","\n fragment JobProposalPayloadFields on JobProposal {\n id\n externalJobID\n remoteUUID\n jobID\n specs {\n ...JobProposal_SpecsFields\n }\n status\n pendingUpdate\n }\n"]);return ME=function(){return e},e}var MS=n0(ME(),Mg),Mk=function(e){var t=e.onApprove,n=e.onCancel,r=e.onReject,i=e.onUpdateSpec,a=e.proposal;return l.createElement(iv,null,l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(iw,null,"Job Proposal #",a.id))),l.createElement(T8,{proposal:a}),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:9},l.createElement(TU,null,"Specs"))),l.createElement(d.Z,{container:!0,spacing:32},l.createElement(d.Z,{item:!0,xs:12},l.createElement(Mw,{proposal:a,specs:a.specs,onReject:r,onApprove:t,onCancel:n,onUpdateSpec:i}))))};function Mx(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]e.length)&&(t=e.length);for(var n=0,r=Array(t);ne.length)&&(t=e.length);for(var n=0,r=Array(t);nU,tA:()=>$,KL:()=>H,Iw:()=>V,DQ:()=>W,cB:()=>T,LO:()=>M,t5:()=>k,qt:()=>x,Jc:()=>C,L7:()=>Y,EO:()=>B});var r,i,a=n(66289),o=n(41800),s=n.n(o),u=n(67932);(i=r||(r={})).IN_PROGRESS="in_progress",i.PENDING_INCOMING_CONFIRMATIONS="pending_incoming_confirmations",i.PENDING_CONNECTION="pending_connection",i.PENDING_BRIDGE="pending_bridge",i.PENDING_SLEEP="pending_sleep",i.ERRORED="errored",i.COMPLETED="completed";var c=n(87013),l=n(19084),f=n(34823);function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]j,v2:()=>F});var r=n(66289);function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var a="/sessions",o="/sessions",s=function e(t){var n=this;i(this,e),this.api=t,this.createSession=function(e){return n.create(e)},this.destroySession=function(){return n.destroy()},this.create=this.api.createResource(a),this.destroy=this.api.deleteResource(o)};function u(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var c="/v2/bulk_delete_runs",l=function e(t){var n=this;u(this,e),this.api=t,this.bulkDeleteJobRuns=function(e){return n.destroy(e)},this.destroy=this.api.deleteResource(c)};function f(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var d="/v2/chains/evm",h="".concat(d,"/:id"),p=function e(t){var n=this;f(this,e),this.api=t,this.getChains=function(){return n.index()},this.createChain=function(e){return n.create(e)},this.destroyChain=function(e){return n.destroy(void 0,{id:e})},this.updateChain=function(e,t){return n.update(t,{id:e})},this.index=this.api.fetchResource(d),this.create=this.api.createResource(d),this.destroy=this.api.deleteResource(h),this.update=this.api.updateResource(h)};function b(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var m="/v2/keys/evm/chain",g=function e(t){var n=this;b(this,e),this.api=t,this.chain=function(e){var t=new URLSearchParams;t.append("address",e.address),t.append("evmChainID",e.evmChainID),null!==e.nextNonce&&t.append("nextNonce",e.nextNonce),null!==e.abandon&&t.append("abandon",String(e.abandon)),null!==e.enabled&&t.append("enabled",String(e.enabled));var r=m+"?"+t.toString();return n.api.createResource(r)()}};function v(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var y="/v2/jobs",w="".concat(y,"/:specId/runs"),_=function e(t){var n=this;v(this,e),this.api=t,this.createJobRunV2=function(e,t){return n.post(t,{specId:e})},this.post=this.api.createResource(w,!0)};function E(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var S="/v2/log",k=function e(t){var n=this;E(this,e),this.api=t,this.getLogConfig=function(){return n.show()},this.updateLogConfig=function(e){return n.update(e)},this.show=this.api.fetchResource(S),this.update=this.api.updateResource(S)};function x(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var T="/v2/nodes",M=function e(t){var n=this;x(this,e),this.api=t,this.getNodes=function(){return n.index()},this.createNode=function(e){return n.create(e)},this.index=this.api.fetchResource(T),this.create=this.api.createResource(T)};function O(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var A="/v2/enroll_webauthn",L=function e(t){var n=this;O(this,e),this.api=t,this.beginKeyRegistration=function(e){return n.create(e)},this.finishKeyRegistration=function(e){return n.put(e)},this.create=this.api.fetchResource(A),this.put=this.api.createResource(A)};function C(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var I="/v2/build_info",D=function e(t){var n=this;C(this,e),this.api=t,this.show=function(){return n.api.GET(I)()}};function N(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}var P=function e(t){N(this,e),this.api=t,this.buildInfo=new D(this.api),this.bulkDeleteRuns=new l(this.api),this.chains=new p(this.api),this.logConfig=new k(this.api),this.nodes=new M(this.api),this.jobs=new _(this.api),this.webauthn=new L(this.api),this.evmKeys=new g(this.api)},R=new r.V0({base:void 0}),j=new s(R),F=new P(R)},1398(e,t,n){"use strict";n.d(t,{Z:()=>d});var r=n(67294),i=n(32316),a=n(83638),o=n(94184),s=n.n(o);function u(){return(u=Object.assign||function(e){for(var t=1;tc});var r=n(67294),i=n(32316);function a(){return(a=Object.assign||function(e){for(var t=1;tx,jK:()=>v});var r=n(67294),i=n(55977),a=n(45697),o=n.n(a),s=n(82204),u=n(71426),c=n(94184),l=n.n(c),f=n(32316),d=function(e){var t=e.palette.success||{},n=e.palette.warning||{};return{base:{paddingLeft:5*e.spacing.unit,paddingRight:5*e.spacing.unit},success:{backgroundColor:t.main,color:t.contrastText},error:{backgroundColor:e.palette.error.dark,color:e.palette.error.contrastText},warning:{backgroundColor:n.contrastText,color:n.main}}},h=function(e){var t,n=e.success,r=e.error,i=e.warning,a=e.classes,o=e.className;return n?t=a.success:r?t=a.error:i&&(t=a.warning),l()(a.base,o,t)},p=function(e){return r.createElement(s.Z,{className:h(e),square:!0},r.createElement(u.default,{variant:"body2",color:"inherit",component:"div"},e.children))};p.defaultProps={success:!1,error:!1,warning:!1},p.propTypes={success:o().bool,error:o().bool,warning:o().bool};let b=(0,f.withStyles)(d)(p);var m=function(){return r.createElement(r.Fragment,null,"Unhandled error. Please help us by opening a"," ",r.createElement("a",{href:"https://github.com/smartcontractkit/chainlink/issues/new"},"bug report"))};let g=m;function v(e){return"string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null)}function y(e,t){var n;return n="string"==typeof e?e:e.component?e.component(e.props):r.createElement(g,null),r.createElement("p",{key:t},n)}var w=function(e){var t=e.notifications;return r.createElement(b,{error:!0},t.map(y))},_=function(e){var t=e.notifications;return r.createElement(b,{success:!0},t.map(y))},E=function(e){var t=e.errors,n=e.successes;return r.createElement("div",null,(null==t?void 0:t.length)>0&&r.createElement(w,{notifications:t}),n.length>0&&r.createElement(_,{notifications:n}))},S=function(e){return{errors:e.notifications.errors,successes:e.notifications.successes}},k=(0,i.$j)(S)(E);let x=k},9409(e,t,n){"use strict";n.d(t,{ZP:()=>j});var r=n(67294),i=n(55977),a=n(47886),o=n(32316),s=n(1398),u=n(82204),c=n(30060),l=n(71426),f=n(60520),d=n(97779),h=n(57209),p=n(26842),b=n(3950),m=n(5536),g=n(45697),v=n.n(g);let y=n.p+"9f6d832ef97e8493764e.svg";function w(){return(w=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&_.map(function(e,t){return r.createElement(d.Z,{item:!0,xs:12,key:t},r.createElement(u.Z,{raised:!1,className:v.error},r.createElement(c.Z,null,r.createElement(l.default,{variant:"body1",className:v.errorText},(0,b.jK)(e)))))}),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"email",label:"Email",margin:"normal",value:n,onChange:m("email"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(f.Z,{id:"password",label:"Password",type:"password",autoComplete:"password",margin:"normal",value:h,onChange:m("password"),error:_.length>0,variant:"outlined",fullWidth:!0})),r.createElement(d.Z,{item:!0,xs:12},r.createElement(d.Z,{container:!0,spacing:0,justify:"center"},r.createElement(d.Z,{item:!0},r.createElement(s.Z,{type:"submit",variant:"primary"},"Access Account")))),y&&r.createElement(l.default,{variant:"body1",color:"textSecondary"},"Signing in...")))))))},P=function(e){return{fetching:e.authentication.fetching,authenticated:e.authentication.allowed,errors:e.notifications.errors}},R=(0,i.$j)(P,x({submitSignIn:p.L7}))(N);let j=(0,h.wU)(e)((0,o.withStyles)(D)(R))},16353(e,t,n){"use strict";n.d(t,{ZP:()=>H,rH:()=>U});var r,i=n(55977),a=n(15857),o=n(9541),s=n(19084);function u(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function c(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:h,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.Mk.RECEIVE_SIGNOUT_SUCCESS:case s.Mk.RECEIVE_SIGNIN_SUCCESS:var n={allowed:t.authenticated};return o.Ks(n),f(c({},e,n),{errors:[]});case s.Mk.RECEIVE_SIGNIN_FAIL:var r={allowed:!1};return o.Ks(r),f(c({},e,r),{errors:[]});case s.Mk.RECEIVE_SIGNIN_ERROR:case s.Mk.RECEIVE_SIGNOUT_ERROR:var i={allowed:!1};return o.Ks(i),f(c({},e,i),{errors:t.errors||[]});default:return e}};let b=p;function m(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function g(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:_,t=arguments.length>1?arguments[1]:void 0;return t.type?t.type.startsWith(r.REQUEST)?y(g({},e),{count:e.count+1}):t.type.startsWith(r.RECEIVE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type.startsWith(r.RESPONSE)?y(g({},e),{count:Math.max(e.count-1,0)}):t.type===s.di.REDIRECT?y(g({},e),{count:0}):e:e};let S=E;function k(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function x(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:O,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.MATCH_ROUTE:return M(x({},O),{currentUrl:t.pathname});case s.Ih.NOTIFY_SUCCESS:var n={component:t.component,props:t.props};return M(x({},e),{successes:[n],errors:[]});case s.Ih.NOTIFY_SUCCESS_MSG:return M(x({},e),{successes:[t.msg],errors:[]});case s.Ih.NOTIFY_ERROR:var r=t.error.errors,i=null==r?void 0:r.map(function(e){return L(t,e)});return M(x({},e),{successes:[],errors:i});case s.Ih.NOTIFY_ERROR_MSG:return M(x({},e),{successes:[],errors:[t.msg]});case s.Mk.RECEIVE_SIGNIN_FAIL:return M(x({},e),{successes:[],errors:["Your email or password is incorrect. Please try again"]});default:return e}};function L(e,t){return{component:e.component,props:{msg:t.detail}}}let C=A;function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function D(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:R,t=arguments.length>1?arguments[1]:void 0;switch(t.type){case s.di.REDIRECT:return P(D({},e),{to:t.to});case s.di.MATCH_ROUTE:return P(D({},e),{to:void 0});default:return e}};let F=j;var Y=n(87013),B=(0,a.UY)({authentication:b,fetching:S,notifications:C,redirect:F,buildInfo:Y.Z});B(void 0,{type:"INITIAL_STATE"});var U=i.v9;let H=B},19084(e,t,n){"use strict";var r,i,a,o,s,u,c,l,f,d;n.d(t,{Ih:()=>i,Mk:()=>a,Y0:()=>s,di:()=>r,jp:()=>o}),n(67294),(u=r||(r={})).REDIRECT="REDIRECT",u.MATCH_ROUTE="MATCH_ROUTE",(c=i||(i={})).NOTIFY_SUCCESS="NOTIFY_SUCCESS",c.NOTIFY_SUCCESS_MSG="NOTIFY_SUCCESS_MSG",c.NOTIFY_ERROR="NOTIFY_ERROR",c.NOTIFY_ERROR_MSG="NOTIFY_ERROR_MSG",(l=a||(a={})).REQUEST_SIGNIN="REQUEST_SIGNIN",l.RECEIVE_SIGNIN_SUCCESS="RECEIVE_SIGNIN_SUCCESS",l.RECEIVE_SIGNIN_FAIL="RECEIVE_SIGNIN_FAIL",l.RECEIVE_SIGNIN_ERROR="RECEIVE_SIGNIN_ERROR",l.RECEIVE_SIGNOUT_SUCCESS="RECEIVE_SIGNOUT_SUCCESS",l.RECEIVE_SIGNOUT_ERROR="RECEIVE_SIGNOUT_ERROR",(f=o||(o={})).RECEIVE_CREATE_ERROR="RECEIVE_CREATE_ERROR",f.RECEIVE_CREATE_SUCCESS="RECEIVE_CREATE_SUCCESS",f.RECEIVE_DELETE_ERROR="RECEIVE_DELETE_ERROR",f.RECEIVE_DELETE_SUCCESS="RECEIVE_DELETE_SUCCESS",f.RECEIVE_UPDATE_ERROR="RECEIVE_UPDATE_ERROR",f.RECEIVE_UPDATE_SUCCESS="RECEIVE_UPDATE_SUCCESS",f.REQUEST_CREATE="REQUEST_CREATE",f.REQUEST_DELETE="REQUEST_DELETE",f.REQUEST_UPDATE="REQUEST_UPDATE",f.UPSERT_CONFIGURATION="UPSERT_CONFIGURATION",f.UPSERT_JOB_RUN="UPSERT_JOB_RUN",f.UPSERT_JOB_RUNS="UPSERT_JOB_RUNS",f.UPSERT_TRANSACTION="UPSERT_TRANSACTION",f.UPSERT_TRANSACTIONS="UPSERT_TRANSACTIONS",f.UPSERT_BUILD_INFO="UPSERT_BUILD_INFO",(d=s||(s={})).FETCH_BUILD_INFO_REQUESTED="FETCH_BUILD_INFO_REQUESTED",d.FETCH_BUILD_INFO_SUCCEEDED="FETCH_BUILD_INFO_SUCCEEDED",d.FETCH_BUILD_INFO_FAILED="FETCH_BUILD_INFO_FAILED"},87013(e,t,n){"use strict";n.d(t,{Y:()=>o,Z:()=>u});var r=n(19084);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:o,t=arguments.length>1?arguments[1]:void 0;return t.type===r.Y0.FETCH_BUILD_INFO_SUCCEEDED?a({},t.buildInfo):e};let u=s},34823(e,t,n){"use strict";n.d(t,{N:()=>r});var r=function(e){return e.buildInfo}},73343(e,t,n){"use strict";n.d(t,{r:()=>u});var r=n(19350),i=n(32316),a=n(59114),o=n(5324),s={props:{MuiGrid:{spacing:3*o.default.unit},MuiCardHeader:{titleTypographyProps:{color:"secondary"}}},palette:{action:{hoverOpacity:.3},primary:{light:"#E5F1FF",main:"#3c40c6",contrastText:"#fff"},secondary:{main:"#3d5170"},success:{light:"#e8faf1",main:r.ek.A700,dark:r.ek[700],contrastText:r.y0.white},warning:{light:"#FFFBF1",main:"#fff6b6",contrastText:"#fad27a"},error:{light:"#ffdada",main:"#f44336",dark:"#d32f2f",contrastText:"#fff"},background:{default:"#f5f6f8",appBar:"#3c40c6"},text:{primary:(0,a.darken)(r.BA.A700,.7),secondary:"#818ea3"},listPendingStatus:{background:"#fef7e5",color:"#fecb4c"},listCompletedStatus:{background:"#e9faf2",color:"#4ed495"}},shape:{borderRadius:o.default.unit},overrides:{MuiButton:{root:{borderRadius:o.default.unit/2,textTransform:"none"},sizeLarge:{padding:void 0,fontSize:void 0,paddingTop:o.default.unit,paddingBottom:o.default.unit,paddingLeft:5*o.default.unit,paddingRight:5*o.default.unit}},MuiTableCell:{body:{fontSize:"1rem"},head:{fontSize:"1rem",fontWeight:400}},MuiCardHeader:{root:{borderBottom:"1px solid rgba(0, 0, 0, 0.12)"},action:{marginTop:-2,marginRight:0,"& >*":{marginLeft:2*o.default.unit}},subheader:{marginTop:.5*o.default.unit}}},typography:{useNextVariants:!0,fontFamily:"-apple-system,BlinkMacSystemFont,Roboto,Helvetica,Arial,sans-serif",button:{textTransform:"none",fontSize:"1.2em"},body1:{fontSize:"1.0rem",fontWeight:400,lineHeight:"1.46429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body2:{fontSize:"1.0rem",fontWeight:500,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},body1Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"1rem",lineHeight:1.5,letterSpacing:-.4},body2Next:{color:"rgb(29, 29, 29)",fontWeight:400,fontSize:"0.875rem",lineHeight:1.5,letterSpacing:-.4},display1:{color:"#818ea3",fontSize:"2.125rem",fontWeight:400,lineHeight:"1.20588em",letterSpacing:-.4},display2:{color:"#818ea3",fontSize:"2.8125rem",fontWeight:400,lineHeight:"1.13333em",marginLeft:"-.02em",letterSpacing:-.4},display3:{color:"#818ea3",fontSize:"3.5rem",fontWeight:400,lineHeight:"1.30357em",marginLeft:"-.02em",letterSpacing:-.4},display4:{fontSize:14,fontWeightLight:300,fontWeightMedium:500,fontWeightRegular:400,letterSpacing:-.4},h1:{color:"rgb(29, 29, 29)",fontSize:"6rem",fontWeight:300,lineHeight:1},h2:{color:"rgb(29, 29, 29)",fontSize:"3.75rem",fontWeight:300,lineHeight:1},h3:{color:"rgb(29, 29, 29)",fontSize:"3rem",fontWeight:400,lineHeight:1.04},h4:{color:"rgb(29, 29, 29)",fontSize:"2.125rem",fontWeight:400,lineHeight:1.17},h5:{color:"rgb(29, 29, 29)",fontSize:"1.5rem",fontWeight:400,lineHeight:1.33,letterSpacing:-.4},h6:{fontSize:"0.8rem",fontWeight:450,lineHeight:"1.71429em",color:"rgba(0, 0, 0, 0.87)",letterSpacing:-.4},subheading:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:"1.5em",letterSpacing:-.4},subtitle1:{color:"rgb(29, 29, 29)",fontSize:"1rem",fontWeight:400,lineHeight:1.75,letterSpacing:-.4},subtitle2:{color:"rgb(29, 29, 29)",fontSize:"0.875rem",fontWeight:500,lineHeight:1.57,letterSpacing:-.4}},shadows:["none","0px 1px 3px 0px rgba(0, 0, 0, 0.1),0px 1px 1px 0px rgba(0, 0, 0, 0.04),0px 2px 1px -1px rgba(0, 0, 0, 0.02)","0px 1px 5px 0px rgba(0, 0, 0, 0.1),0px 2px 2px 0px rgba(0, 0, 0, 0.04),0px 3px 1px -2px rgba(0, 0, 0, 0.02)","0px 1px 8px 0px rgba(0, 0, 0, 0.1),0px 3px 4px 0px rgba(0, 0, 0, 0.04),0px 3px 3px -2px rgba(0, 0, 0, 0.02)","0px 2px 4px -1px rgba(0, 0, 0, 0.1),0px 4px 5px 0px rgba(0, 0, 0, 0.04),0px 1px 10px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 5px 8px 0px rgba(0, 0, 0, 0.04),0px 1px 14px 0px rgba(0, 0, 0, 0.02)","0px 3px 5px -1px rgba(0, 0, 0, 0.1),0px 6px 10px 0px rgba(0, 0, 0, 0.04),0px 1px 18px 0px rgba(0, 0, 0, 0.02)","0px 4px 5px -2px rgba(0, 0, 0, 0.1),0px 7px 10px 1px rgba(0, 0, 0, 0.04),0px 2px 16px 1px rgba(0, 0, 0, 0.02)","0px 5px 5px -3px rgba(0, 0, 0, 0.1),0px 8px 10px 1px rgba(0, 0, 0, 0.04),0px 3px 14px 2px rgba(0, 0, 0, 0.02)","0px 5px 6px -3px rgba(0, 0, 0, 0.1),0px 9px 12px 1px rgba(0, 0, 0, 0.04),0px 3px 16px 2px rgba(0, 0, 0, 0.02)","0px 6px 6px -3px rgba(0, 0, 0, 0.1),0px 10px 14px 1px rgba(0, 0, 0, 0.04),0px 4px 18px 3px rgba(0, 0, 0, 0.02)","0px 6px 7px -4px rgba(0, 0, 0, 0.1),0px 11px 15px 1px rgba(0, 0, 0, 0.04),0px 4px 20px 3px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 12px 17px 2px rgba(0, 0, 0, 0.04),0px 5px 22px 4px rgba(0, 0, 0, 0.02)","0px 7px 8px -4px rgba(0, 0, 0, 0.1),0px 13px 19px 2px rgba(0, 0, 0, 0.04),0px 5px 24px 4px rgba(0, 0, 0, 0.02)","0px 7px 9px -4px rgba(0, 0, 0, 0.1),0px 14px 21px 2px rgba(0, 0, 0, 0.04),0px 5px 26px 4px rgba(0, 0, 0, 0.02)","0px 8px 9px -5px rgba(0, 0, 0, 0.1),0px 15px 22px 2px rgba(0, 0, 0, 0.04),0px 6px 28px 5px rgba(0, 0, 0, 0.02)","0px 8px 10px -5px rgba(0, 0, 0, 0.1),0px 16px 24px 2px rgba(0, 0, 0, 0.04),0px 6px 30px 5px rgba(0, 0, 0, 0.02)","0px 8px 11px -5px rgba(0, 0, 0, 0.1),0px 17px 26px 2px rgba(0, 0, 0, 0.04),0px 6px 32px 5px rgba(0, 0, 0, 0.02)","0px 9px 11px -5px rgba(0, 0, 0, 0.1),0px 18px 28px 2px rgba(0, 0, 0, 0.04),0px 7px 34px 6px rgba(0, 0, 0, 0.02)","0px 9px 12px -6px rgba(0, 0, 0, 0.1),0px 19px 29px 2px rgba(0, 0, 0, 0.04),0px 7px 36px 6px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 20px 31px 3px rgba(0, 0, 0, 0.04),0px 8px 38px 7px rgba(0, 0, 0, 0.02)","0px 10px 13px -6px rgba(0, 0, 0, 0.1),0px 21px 33px 3px rgba(0, 0, 0, 0.04),0px 8px 40px 7px rgba(0, 0, 0, 0.02)","0px 10px 14px -6px rgba(0, 0, 0, 0.1),0px 22px 35px 3px rgba(0, 0, 0, 0.04),0px 8px 42px 7px rgba(0, 0, 0, 0.02)","0px 11px 14px -7px rgba(0, 0, 0, 0.1),0px 23px 36px 3px rgba(0, 0, 0, 0.04),0px 9px 44px 8px rgba(0, 0, 0, 0.02)","0px 11px 15px -7px rgba(0, 0, 0, 0.1),0px 24px 38px 3px rgba(0, 0, 0, 0.04),0px 9px 46px 8px rgba(0, 0, 0, 0.02)",]},u=(0,i.createMuiTheme)(s)},66289(e,t,n){"use strict";function r(e){if(void 0===e)throw ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw TypeError("Cannot call a class as a function")}function a(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function o(e,t,n){return(o=a()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=new(Function.bind.apply(e,r));return n&&f(i,n.prototype),i}).apply(null,arguments)}function s(e){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function u(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&f(e,t)}function c(e){return -1!==Function.toString.call(e).indexOf("[native code]")}function l(e,t){return t&&("object"===p(t)||"function"==typeof t)?t:r(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}n.d(t,{V0:()=>B,_7:()=>v});var d,h,p=function(e){return e&&"undefined"!=typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};function b(e){var t="function"==typeof Map?new Map:void 0;return(b=function(e){if(null===e||!c(e))return e;if("function"!=typeof e)throw TypeError("Super expression must either be null or a function");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return o(e,arguments,s(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),f(n,e)})(e)}function m(){if("undefined"==typeof Reflect||!Reflect.construct||Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(e){return!1}}function g(e){var t=m();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return l(this,n)}}var v=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"AuthenticationError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e},],r}return n}(b(Error)),y=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"BadRequestError")).errors=a,r}return n}(b(Error)),w=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnprocessableEntityError")).errors=e,r}return n}(b(Error)),_=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"ServerError")).errors=e,r}return n}(b(Error)),E=function(e){u(n,e);var t=g(n);function n(e){var r,a=e.errors;return i(this,n),(r=t.call(this,"ConflictError")).errors=a,r}return n}(b(Error)),S=function(e){u(n,e);var t=g(n);function n(e){var r;return i(this,n),(r=t.call(this,"UnknownResponseError(".concat(e.statusText,")"))).errors=[{status:e.status,detail:e.statusText},],r}return n}(b(Error));function k(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:2e4;return Promise.race([fetch(e,t),new Promise(function(e,t){return setTimeout(function(){return t(Error("timeout"))},n)}),])}function x(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n0&&i[i.length-1])&&(6===a[0]||2===a[0])){o=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=200&&e.status<300))return[3,2];return[2,e.json()];case 2:if(400!==e.status)return[3,3];return[2,e.json().then(function(e){throw new y(e)})];case 3:if(401!==e.status)return[3,4];throw new v(e);case 4:if(422!==e.status)return[3,6];return[4,$(e)];case 5:throw n=i.sent(),new w(n);case 6:if(409!==e.status)return[3,7];return[2,e.json().then(function(e){throw new E(e)})];case 7:if(!(e.status>=500))return[3,9];return[4,$(e)];case 8:throw r=i.sent(),new _(r);case 9:throw new S(e);case 10:return[2]}})})).apply(this,arguments)}function $(e){return z.apply(this,arguments)}function z(){return(z=j(function(e){return Y(this,function(t){return[2,e.json().then(function(t){return t.errors?t.errors.map(function(t){return{status:e.status,detail:t.detail}}):G(e)}).catch(function(){return G(e)})]})})).apply(this,arguments)}function G(e){return[{status:e.status,detail:e.statusText},]}},50109(e,t,n){"use strict";n.d(t,{LK:()=>o,U2:()=>i,eT:()=>s,t8:()=>a});var r=n(12795);function i(e){return r.ZP.getItem("chainlink.".concat(e))}function a(e,t){r.ZP.setItem("chainlink.".concat(e),t)}function o(e){var t=i(e),n={};if(t)try{return JSON.parse(t)}catch(r){}return n}function s(e,t){a(e,JSON.stringify(t))}},9541(e,t,n){"use strict";n.d(t,{Ks:()=>u,Tp:()=>a,iR:()=>o,pm:()=>s});var r=n(50109),i="persistURL";function a(){return r.U2(i)||""}function o(e){r.t8(i,e)}function s(){return r.LK("authentication")}function u(e){r.eT("authentication",e)}},67121(e,t,n){"use strict";function r(e){var t,n=e.Symbol;return"function"==typeof n?n.observable?t=n.observable:(t=n("observable"),n.observable=t):t="@@observable",t}n.r(t),n.d(t,{default:()=>o}),e=n.hmd(e),i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==n.g?n.g:e;var i,a=r(i);let o=a},2177(e,t,n){"use strict";n.d(t,{Z:()=>o});var r=!0,i="Invariant failed";function a(e,t){if(!e){if(r)throw Error(i);throw Error(i+": "+(t||""))}}let o=a},11742(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],r=0;ri,pi:()=>a});var r=function(e,t){return(r=Object.setPrototypeOf||({__proto__:[]})instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])})(e,t)};function i(e,t){if("function"!=typeof t&&null!==t)throw TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}var a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;nr})},94927(e,t,n){function r(e,t){if(i("noDeprecation"))return e;var n=!1;function r(){if(!n){if(i("throwDeprecation"))throw Error(t);i("traceDeprecation")?console.trace(t):console.warn(t),n=!0}return e.apply(this,arguments)}return r}function i(e){try{if(!n.g.localStorage)return!1}catch(t){return!1}var r=n.g.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=r},42473(e){"use strict";var t=function(){};e.exports=t},84763(e){e.exports=Worker},47529(e){e.exports=n;var t=Object.prototype.hasOwnProperty;function n(){for(var e={},n=0;nr,O:()=>a}),(i=r||(r={}))[i.loading=1]="loading",i[i.setVariables=2]="setVariables",i[i.fetchMore=3]="fetchMore",i[i.refetch=4]="refetch",i[i.poll=6]="poll",i[i.ready=7]="ready",i[i.error=8]="error"},30990(e,t,n){"use strict";n.d(t,{MS:()=>s,YG:()=>a,cA:()=>c,ls:()=>o});var r=n(23564);n(83952);var i=n(13154),a=Symbol();function o(e){return!!e.extensions&&Array.isArray(e.extensions[a])}function s(e){return e.hasOwnProperty("graphQLErrors")}var u=function(e){var t=(0,r.ev)((0,r.ev)((0,r.ev)([],e.graphQLErrors,!0),e.clientErrors,!0),e.protocolErrors,!0);return e.networkError&&t.push(e.networkError),t.map(function(e){return(0,i.s)(e)&&e.message||"Error message not found."}).join("\n")},c=function(e){function t(n){var r=n.graphQLErrors,i=n.protocolErrors,a=n.clientErrors,o=n.networkError,s=n.errorMessage,c=n.extraInfo,l=e.call(this,s)||this;return l.name="ApolloError",l.graphQLErrors=r||[],l.protocolErrors=i||[],l.clientErrors=a||[],l.networkError=o||null,l.message=s||u(l),l.extraInfo=c,l.__proto__=t.prototype,l}return(0,r.ZT)(t,e),t}(Error)},85317(e,t,n){"use strict";n.d(t,{K:()=>a});var r=n(67294),i=n(30320).aS?Symbol.for("__APOLLO_CONTEXT__"):"__APOLLO_CONTEXT__";function a(){var e=r.createContext[i];return e||(Object.defineProperty(r.createContext,i,{value:e=r.createContext({}),enumerable:!1,writable:!1,configurable:!0}),e.displayName="ApolloContext"),e}},21436(e,t,n){"use strict";n.d(t,{O:()=>i,k:()=>r});var r=Array.isArray;function i(e){return Array.isArray(e)&&e.length>0}},30320(e,t,n){"use strict";n.d(t,{DN:()=>s,JC:()=>l,aS:()=>o,mr:()=>i,sy:()=>a});var r=n(83952),i="function"==typeof WeakMap&&"ReactNative"!==(0,r.wY)(function(){return navigator.product}),a="function"==typeof WeakSet,o="function"==typeof Symbol&&"function"==typeof Symbol.for,s=o&&Symbol.asyncIterator,u="function"==typeof(0,r.wY)(function(){return window.document.createElement}),c=(0,r.wY)(function(){return navigator.userAgent.indexOf("jsdom")>=0})||!1,l=u&&!c},53712(e,t,n){"use strict";function r(){for(var e=[],t=0;tr})},10542(e,t,n){"use strict";n.d(t,{J:()=>o}),n(83952);var r=n(13154);function i(e){var t=new Set([e]);return t.forEach(function(e){(0,r.s)(e)&&a(e)===e&&Object.getOwnPropertyNames(e).forEach(function(n){(0,r.s)(e[n])&&t.add(e[n])})}),e}function a(e){if(__DEV__&&!Object.isFrozen(e))try{Object.freeze(e)}catch(t){if(t instanceof TypeError)return null;throw t}return e}function o(e){return __DEV__&&i(e),e}},14012(e,t,n){"use strict";n.d(t,{J:()=>a});var r=n(23564),i=n(53712);function a(e,t){return(0,i.o)(e,t,t.variables&&{variables:(0,r.pi)((0,r.pi)({},e&&e.variables),t.variables)})}},13154(e,t,n){"use strict";function r(e){return null!==e&&"object"==typeof e}n.d(t,{s:()=>r})},83952(e,t,n){"use strict";n.d(t,{ej:()=>u,kG:()=>c,wY:()=>h});var r,i=n(70655),a="Invariant Violation",o=Object.setPrototypeOf,s=void 0===o?function(e,t){return e.__proto__=t,e}:o,u=function(e){function t(n){void 0===n&&(n=a);var r=e.call(this,"number"==typeof n?a+": "+n+" (see https://github.com/apollographql/invariant-packages)":n)||this;return r.framesToPop=1,r.name=a,s(r,t.prototype),r}return(0,i.ZT)(t,e),t}(Error);function c(e,t){if(!e)throw new u(t)}var l=["debug","log","warn","error","silent"],f=l.indexOf("log");function d(e){return function(){if(l.indexOf(e)>=f)return(console[e]||console.log).apply(console,arguments)}}function h(e){try{return e()}catch(t){}}(r=c||(c={})).debug=d("debug"),r.log=d("log"),r.warn=d("warn"),r.error=d("error");let p=h(function(){return globalThis})||h(function(){return window})||h(function(){return self})||h(function(){return global})||h(function(){return h.constructor("return this")()});var b="__",m=[b,b].join("DEV");function g(){try{return Boolean(__DEV__)}catch(e){return Object.defineProperty(p,m,{value:"production"!==h(function(){return"production"}),enumerable:!1,configurable:!0,writable:!0}),p[m]}}let v=g();function y(e){try{return e()}catch(t){}}var w=y(function(){return globalThis})||y(function(){return window})||y(function(){return self})||y(function(){return global})||y(function(){return y.constructor("return this")()}),_=!1;function E(){!w||y(function(){return"production"})||y(function(){return process})||(Object.defineProperty(w,"process",{value:{env:{NODE_ENV:"production"}},configurable:!0,enumerable:!1,writable:!0}),_=!0)}function S(){_&&(delete w.process,_=!1)}E();var k=n(10143);function x(){return k.H,S()}function T(){__DEV__?c("boolean"==typeof v,v):c("boolean"==typeof v,39)}x(),T()},87462(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;tr})},25821(e,t,n){"use strict";n.d(t,{Z:()=>s});var r=n(45695);function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}var a=10,o=2;function s(e){return u(e,[])}function u(e,t){switch(i(e)){case"string":return JSON.stringify(e);case"function":return e.name?"[function ".concat(e.name,"]"):"[function]";case"object":if(null===e)return"null";return c(e,t);default:return String(e)}}function c(e,t){if(-1!==t.indexOf(e))return"[Circular]";var n=[].concat(t,[e]),r=d(e);if(void 0!==r){var i=r.call(e);if(i!==e)return"string"==typeof i?i:u(i,n)}else if(Array.isArray(e))return f(e,n);return l(e,n)}function l(e,t){var n=Object.keys(e);return 0===n.length?"{}":t.length>o?"["+h(e)+"]":"{ "+n.map(function(n){var r=u(e[n],t);return n+": "+r}).join(", ")+" }"}function f(e,t){if(0===e.length)return"[]";if(t.length>o)return"[Array]";for(var n=Math.min(a,e.length),r=e.length-n,i=[],s=0;s1&&i.push("... ".concat(r," more items")),"["+i.join(", ")+"]"}function d(e){var t=e[String(r.Z)];return"function"==typeof t?t:"function"==typeof e.inspect?e.inspect:void 0}function h(e){var t=Object.prototype.toString.call(e).replace(/^\[object /,"").replace(/]$/,"");if("Object"===t&&"function"==typeof e.constructor){var n=e.constructor.name;if("string"==typeof n&&""!==n)return n}return t}},45695(e,t,n){"use strict";n.d(t,{Z:()=>i});var r="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):void 0;let i=r},25217(e,t,n){"use strict";function r(e,t){if(!Boolean(e))throw Error(null!=t?t:"Unexpected invariant triggered.")}n.d(t,{Ye:()=>o,WU:()=>s,UG:()=>u});var i=n(45695);function a(e){var t=e.prototype.toJSON;"function"==typeof t||r(0),e.prototype.inspect=t,i.Z&&(e.prototype[i.Z]=t)}var o=function(){function e(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}return e.prototype.toJSON=function(){return{start:this.start,end:this.end}},e}();a(o);var s=function(){function e(e,t,n,r,i,a,o){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=o,this.prev=a,this.next=null}return e.prototype.toJSON=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}},e}();function u(e){return null!=e&&"string"==typeof e.kind}a(s)},87392(e,t,n){"use strict";function r(e){var t=e.split(/\r\n|[\n\r]/g),n=a(e);if(0!==n)for(var r=1;ro&&i(t[s-1]);)--s;return t.slice(o,s).join("\n")}function i(e){for(var t=0;t1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=-1===e.indexOf("\n"),i=" "===e[0]||" "===e[0],a='"'===e[e.length-1],o="\\"===e[e.length-1],s=!r||a||o||n,u="";return s&&!(r&&i)&&(u+="\n"+t),u+=t?e.replace(/\n/g,"\n"+t):e,s&&(u+="\n"),'"""'+u.replace(/"""/g,'\\"""')+'"""'}n.d(t,{LZ:()=>o,W7:()=>r})},97359(e,t,n){"use strict";n.d(t,{h:()=>r});var r=Object.freeze({NAME:"Name",DOCUMENT:"Document",OPERATION_DEFINITION:"OperationDefinition",VARIABLE_DEFINITION:"VariableDefinition",SELECTION_SET:"SelectionSet",FIELD:"Field",ARGUMENT:"Argument",FRAGMENT_SPREAD:"FragmentSpread",INLINE_FRAGMENT:"InlineFragment",FRAGMENT_DEFINITION:"FragmentDefinition",VARIABLE:"Variable",INT:"IntValue",FLOAT:"FloatValue",STRING:"StringValue",BOOLEAN:"BooleanValue",NULL:"NullValue",ENUM:"EnumValue",LIST:"ListValue",OBJECT:"ObjectValue",OBJECT_FIELD:"ObjectField",DIRECTIVE:"Directive",NAMED_TYPE:"NamedType",LIST_TYPE:"ListType",NON_NULL_TYPE:"NonNullType",SCHEMA_DEFINITION:"SchemaDefinition",OPERATION_TYPE_DEFINITION:"OperationTypeDefinition",SCALAR_TYPE_DEFINITION:"ScalarTypeDefinition",OBJECT_TYPE_DEFINITION:"ObjectTypeDefinition",FIELD_DEFINITION:"FieldDefinition",INPUT_VALUE_DEFINITION:"InputValueDefinition",INTERFACE_TYPE_DEFINITION:"InterfaceTypeDefinition",UNION_TYPE_DEFINITION:"UnionTypeDefinition",ENUM_TYPE_DEFINITION:"EnumTypeDefinition",ENUM_VALUE_DEFINITION:"EnumValueDefinition",INPUT_OBJECT_TYPE_DEFINITION:"InputObjectTypeDefinition",DIRECTIVE_DEFINITION:"DirectiveDefinition",SCHEMA_EXTENSION:"SchemaExtension",SCALAR_TYPE_EXTENSION:"ScalarTypeExtension",OBJECT_TYPE_EXTENSION:"ObjectTypeExtension",INTERFACE_TYPE_EXTENSION:"InterfaceTypeExtension",UNION_TYPE_EXTENSION:"UnionTypeExtension",ENUM_TYPE_EXTENSION:"EnumTypeExtension",INPUT_OBJECT_TYPE_EXTENSION:"InputObjectTypeExtension"})},10143(e,t,n){"use strict";n.d(t,{H:()=>c,T:()=>l});var r=n(99763),i=n(25821);function a(e,t){if(!Boolean(e))throw Error(t)}let o=function(e,t){return e instanceof t};function s(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:"GraphQL request",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{line:1,column:1};"string"==typeof e||a(0,"Body must be a string. Received: ".concat((0,i.Z)(e),".")),this.body=e,this.name=t,this.locationOffset=n,this.locationOffset.line>0||a(0,"line in locationOffset is 1-indexed and must be positive."),this.locationOffset.column>0||a(0,"column in locationOffset is 1-indexed and must be positive.")}return u(e,[{key:r.YF,get:function(){return"Source"}}]),e}();function l(e){return o(e,c)}},99763(e,t,n){"use strict";n.d(t,{YF:()=>r});var r="function"==typeof Symbol&&null!=Symbol.toStringTag?Symbol.toStringTag:"@@toStringTag"},37452(e){"use strict";e.exports=JSON.parse('{"AElig":"\xc6","AMP":"&","Aacute":"\xc1","Acirc":"\xc2","Agrave":"\xc0","Aring":"\xc5","Atilde":"\xc3","Auml":"\xc4","COPY":"\xa9","Ccedil":"\xc7","ETH":"\xd0","Eacute":"\xc9","Ecirc":"\xca","Egrave":"\xc8","Euml":"\xcb","GT":">","Iacute":"\xcd","Icirc":"\xce","Igrave":"\xcc","Iuml":"\xcf","LT":"<","Ntilde":"\xd1","Oacute":"\xd3","Ocirc":"\xd4","Ograve":"\xd2","Oslash":"\xd8","Otilde":"\xd5","Ouml":"\xd6","QUOT":"\\"","REG":"\xae","THORN":"\xde","Uacute":"\xda","Ucirc":"\xdb","Ugrave":"\xd9","Uuml":"\xdc","Yacute":"\xdd","aacute":"\xe1","acirc":"\xe2","acute":"\xb4","aelig":"\xe6","agrave":"\xe0","amp":"&","aring":"\xe5","atilde":"\xe3","auml":"\xe4","brvbar":"\xa6","ccedil":"\xe7","cedil":"\xb8","cent":"\xa2","copy":"\xa9","curren":"\xa4","deg":"\xb0","divide":"\xf7","eacute":"\xe9","ecirc":"\xea","egrave":"\xe8","eth":"\xf0","euml":"\xeb","frac12":"\xbd","frac14":"\xbc","frac34":"\xbe","gt":">","iacute":"\xed","icirc":"\xee","iexcl":"\xa1","igrave":"\xec","iquest":"\xbf","iuml":"\xef","laquo":"\xab","lt":"<","macr":"\xaf","micro":"\xb5","middot":"\xb7","nbsp":"\xa0","not":"\xac","ntilde":"\xf1","oacute":"\xf3","ocirc":"\xf4","ograve":"\xf2","ordf":"\xaa","ordm":"\xba","oslash":"\xf8","otilde":"\xf5","ouml":"\xf6","para":"\xb6","plusmn":"\xb1","pound":"\xa3","quot":"\\"","raquo":"\xbb","reg":"\xae","sect":"\xa7","shy":"\xad","sup1":"\xb9","sup2":"\xb2","sup3":"\xb3","szlig":"\xdf","thorn":"\xfe","times":"\xd7","uacute":"\xfa","ucirc":"\xfb","ugrave":"\xf9","uml":"\xa8","uuml":"\xfc","yacute":"\xfd","yen":"\xa5","yuml":"\xff"}')},93580(e){"use strict";e.exports=JSON.parse('{"0":"�","128":"€","130":"‚","131":"ƒ","132":"„","133":"…","134":"†","135":"‡","136":"ˆ","137":"‰","138":"Š","139":"‹","140":"Œ","142":"Ž","145":"‘","146":"’","147":"“","148":"”","149":"•","150":"–","151":"—","152":"˜","153":"™","154":"š","155":"›","156":"œ","158":"ž","159":"Ÿ"}')},67946(e){"use strict";e.exports=JSON.parse('{"locale":"en","long":{"year":{"previous":"last year","current":"this year","next":"next year","past":{"one":"{0} year ago","other":"{0} years ago"},"future":{"one":"in {0} year","other":"in {0} years"}},"quarter":{"previous":"last quarter","current":"this quarter","next":"next quarter","past":{"one":"{0} quarter ago","other":"{0} quarters ago"},"future":{"one":"in {0} quarter","other":"in {0} quarters"}},"month":{"previous":"last month","current":"this month","next":"next month","past":{"one":"{0} month ago","other":"{0} months ago"},"future":{"one":"in {0} month","other":"in {0} months"}},"week":{"previous":"last week","current":"this week","next":"next week","past":{"one":"{0} week ago","other":"{0} weeks ago"},"future":{"one":"in {0} week","other":"in {0} weeks"}},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":{"one":"{0} hour ago","other":"{0} hours ago"},"future":{"one":"in {0} hour","other":"in {0} hours"}},"minute":{"current":"this minute","past":{"one":"{0} minute ago","other":"{0} minutes ago"},"future":{"one":"in {0} minute","other":"in {0} minutes"}},"second":{"current":"now","past":{"one":"{0} second ago","other":"{0} seconds ago"},"future":{"one":"in {0} second","other":"in {0} seconds"}}},"short":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"narrow":{"year":{"previous":"last yr.","current":"this yr.","next":"next yr.","past":"{0} yr. ago","future":"in {0} yr."},"quarter":{"previous":"last qtr.","current":"this qtr.","next":"next qtr.","past":{"one":"{0} qtr. ago","other":"{0} qtrs. ago"},"future":{"one":"in {0} qtr.","other":"in {0} qtrs."}},"month":{"previous":"last mo.","current":"this mo.","next":"next mo.","past":"{0} mo. ago","future":"in {0} mo."},"week":{"previous":"last wk.","current":"this wk.","next":"next wk.","past":"{0} wk. ago","future":"in {0} wk."},"day":{"previous":"yesterday","current":"today","next":"tomorrow","past":{"one":"{0} day ago","other":"{0} days ago"},"future":{"one":"in {0} day","other":"in {0} days"}},"hour":{"current":"this hour","past":"{0} hr. ago","future":"in {0} hr."},"minute":{"current":"this minute","past":"{0} min. ago","future":"in {0} min."},"second":{"current":"now","past":"{0} sec. ago","future":"in {0} sec."}},"now":{"now":{"current":"now","future":"in a moment","past":"just now"}},"mini":{"year":"{0}yr","month":"{0}mo","week":"{0}wk","day":"{0}d","hour":"{0}h","minute":"{0}m","second":"{0}s","now":"now"},"short-time":{"year":"{0} yr.","month":"{0} mo.","week":"{0} wk.","day":{"one":"{0} day","other":"{0} days"},"hour":"{0} hr.","minute":"{0} min.","second":"{0} sec."},"long-time":{"year":{"one":"{0} year","other":"{0} years"},"month":{"one":"{0} month","other":"{0} months"},"week":{"one":"{0} week","other":"{0} weeks"},"day":{"one":"{0} day","other":"{0} days"},"hour":{"one":"{0} hour","other":"{0} hours"},"minute":{"one":"{0} minute","other":"{0} minutes"},"second":{"one":"{0} second","other":"{0} seconds"}}}')}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={id:e,loaded:!1,exports:{}};return __webpack_modules__[e].call(n.exports,n,n.exports,__webpack_require__),n.loaded=!0,n.exports}__webpack_require__.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return __webpack_require__.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;__webpack_require__.t=function(n,r){if(1&r&&(n=this(n)),8&r||"object"==typeof n&&n&&(4&r&&n.__esModule||16&r&&"function"==typeof n.then))return n;var i=Object.create(null);__webpack_require__.r(i);var a={};e=e||[null,t({}),t([]),t(t)];for(var o=2&r&&n;"object"==typeof o&&!~e.indexOf(o);o=t(o))Object.getOwnPropertyNames(o).forEach(e=>a[e]=()=>n[e]);return a.default=()=>n,__webpack_require__.d(i,a),i}})(),__webpack_require__.d=(e,t)=>{for(var n in t)__webpack_require__.o(t,n)&&!__webpack_require__.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),__webpack_require__.hmd=e=>((e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set(){throw Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e),__webpack_require__.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),__webpack_require__.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},__webpack_require__.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),__webpack_require__.p="/assets/",__webpack_require__.nc=void 0;var __webpack_exports__={};(()=>{"use strict";var e,t,n,r,i=__webpack_require__(32316),a=__webpack_require__(8126),o=__webpack_require__(5690),s=__webpack_require__(30381),u=__webpack_require__.n(s),c=__webpack_require__(67294),l=__webpack_require__(73935),f=__webpack_require__.n(l),d=__webpack_require__(57209),h=__webpack_require__(55977),p=__webpack_require__(15857),b=__webpack_require__(28500);function m(e){return function(t){var n=t.dispatch,r=t.getState;return function(t){return function(i){return"function"==typeof i?i(n,r,e):t(i)}}}}var g=m();g.withExtraArgument=m;let v=g;var y=__webpack_require__(76489);function w(e){return function(t){return function(n){return function(r){n(r);var i=e||document&&document.cookie||"",a=t.getState();if("MATCH_ROUTE"===r.type&&"/signin"!==a.notifications.currentUrl){var o=(0,y.Q)(i);if(o.explorer)try{var s=JSON.parse(o.explorer);if("error"===s.status){var u=_(s.url);n({type:"NOTIFY_ERROR_MSG",msg:u})}}catch(c){n({type:"NOTIFY_ERROR_MSG",msg:"Invalid explorer status"})}}}}}}function _(e){var t="Can't connect to explorer: ".concat(e);return e.match(/^wss?:.+/)?t:"".concat(t,". You must use a websocket.")}var E=__webpack_require__(16353);function S(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}}}throw TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ei(e,t){if(e){if("string"==typeof e)return ea(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return ea(e,t)}}function ea(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1,i=!1,a=arguments[1],o=a;return new n(function(n){return t.subscribe({next:function(t){var a=!i;if(i=!0,!a||r)try{o=e(o,t)}catch(s){return n.error(s)}else o=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(TypeError("Cannot reduce an empty sequence"));n.next(o),n.complete()}})})},t.concat=function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&i.splice(e,1),o()}});i.push(s)},error:function(e){r.error(e)},complete:function(){o()}});function o(){a.closed&&0===i.length&&r.complete()}return function(){i.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})},t[ed]=function(){return this},e.from=function(t){var n="function"==typeof this?this:e;if(null==t)throw TypeError(t+" is not an object");var r=ep(t,ed);if(r){var i=r.call(t);if(Object(i)!==i)throw TypeError(i+" is not an object");return em(i)&&i.constructor===n?i:new n(function(e){return i.subscribe(e)})}if(ec("iterator")&&(r=ep(t,ef)))return new n(function(e){ev(function(){if(!e.closed){for(var n,i=er(r.call(t));!(n=i()).done;){var a=n.value;if(e.next(a),e.closed)return}e.complete()}})});if(Array.isArray(t))return new n(function(e){ev(function(){if(!e.closed){for(var n=0;n0))return n.connection.key;var r=n.connection.filter?n.connection.filter:[];r.sort();var i={};return r.forEach(function(e){i[e]=t[e]}),"".concat(n.connection.key,"(").concat(eV(i),")")}var a=e;if(t){var o=eV(t);a+="(".concat(o,")")}return n&&Object.keys(n).forEach(function(e){-1===eW.indexOf(e)&&(n[e]&&Object.keys(n[e]).length?a+="@".concat(e,"(").concat(eV(n[e]),")"):a+="@".concat(e))}),a},{setStringify:function(e){var t=eV;return eV=e,t}}),eV=function(e){return JSON.stringify(e,eq)};function eq(e,t){return(0,eO.s)(t)&&!Array.isArray(t)&&(t=Object.keys(t).sort().reduce(function(e,n){return e[n]=t[n],e},{})),t}function eZ(e,t){if(e.arguments&&e.arguments.length){var n={};return e.arguments.forEach(function(e){var r;return ez(n,e.name,e.value,t)}),n}return null}function eX(e){return e.alias?e.alias.value:e.name.value}function eJ(e,t,n){for(var r,i=0,a=t.selections;it.indexOf(i))throw __DEV__?new Q.ej("illegal argument: ".concat(i)):new Q.ej(27)}return e}function tt(e,t){return t?t(e):eT.of()}function tn(e){return"function"==typeof e?new ta(e):e}function tr(e){return e.request.length<=1}var ti=function(e){function t(t,n){var r=e.call(this,t)||this;return r.link=n,r}return(0,en.ZT)(t,e),t}(Error),ta=function(){function e(e){e&&(this.request=e)}return e.empty=function(){return new e(function(){return eT.of()})},e.from=function(t){return 0===t.length?e.empty():t.map(tn).reduce(function(e,t){return e.concat(t)})},e.split=function(t,n,r){var i=tn(n),a=tn(r||new e(tt));return new e(tr(i)&&tr(a)?function(e){return t(e)?i.request(e)||eT.of():a.request(e)||eT.of()}:function(e,n){return t(e)?i.request(e,n)||eT.of():a.request(e,n)||eT.of()})},e.execute=function(e,t){return e.request(eM(t.context,e7(te(t))))||eT.of()},e.concat=function(t,n){var r=tn(t);if(tr(r))return __DEV__&&Q.kG.warn(new ti("You are calling concat on a terminating link, which will have no effect",r)),r;var i=tn(n);return new e(tr(i)?function(e){return r.request(e,function(e){return i.request(e)||eT.of()})||eT.of()}:function(e,t){return r.request(e,function(e){return i.request(e,t)||eT.of()})||eT.of()})},e.prototype.split=function(t,n,r){return this.concat(e.split(t,n,r||new e(tt)))},e.prototype.concat=function(t){return e.concat(this,t)},e.prototype.request=function(e,t){throw __DEV__?new Q.ej("request is not implemented"):new Q.ej(22)},e.prototype.onError=function(e,t){if(t&&t.error)return t.error(e),!1;throw e},e.prototype.setOnError=function(e){return this.onError=e,this},e}(),to=__webpack_require__(25821),ts=__webpack_require__(25217),tu={Name:[],Document:["definitions"],OperationDefinition:["name","variableDefinitions","directives","selectionSet"],VariableDefinition:["variable","type","defaultValue","directives"],Variable:["name"],SelectionSet:["selections"],Field:["alias","name","arguments","directives","selectionSet"],Argument:["name","value"],FragmentSpread:["name","directives"],InlineFragment:["typeCondition","directives","selectionSet"],FragmentDefinition:["name","variableDefinitions","typeCondition","directives","selectionSet"],IntValue:[],FloatValue:[],StringValue:[],BooleanValue:[],NullValue:[],EnumValue:[],ListValue:["values"],ObjectValue:["fields"],ObjectField:["name","value"],Directive:["name","arguments"],NamedType:["name"],ListType:["type"],NonNullType:["type"],SchemaDefinition:["description","directives","operationTypes"],OperationTypeDefinition:["type"],ScalarTypeDefinition:["description","name","directives"],ObjectTypeDefinition:["description","name","interfaces","directives","fields"],FieldDefinition:["description","name","arguments","type","directives"],InputValueDefinition:["description","name","type","defaultValue","directives"],InterfaceTypeDefinition:["description","name","interfaces","directives","fields"],UnionTypeDefinition:["description","name","directives","types"],EnumTypeDefinition:["description","name","directives","values"],EnumValueDefinition:["description","name","directives"],InputObjectTypeDefinition:["description","name","directives","fields"],DirectiveDefinition:["description","name","arguments","locations"],SchemaExtension:["directives","operationTypes"],ScalarTypeExtension:["name","directives"],ObjectTypeExtension:["name","interfaces","directives","fields"],InterfaceTypeExtension:["name","interfaces","directives","fields"],UnionTypeExtension:["name","directives","types"],EnumTypeExtension:["name","directives","values"],InputObjectTypeExtension:["name","directives","fields"]},tc=Object.freeze({});function tl(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:tu,r=void 0,i=Array.isArray(e),a=[e],o=-1,s=[],u=void 0,c=void 0,l=void 0,f=[],d=[],h=e;do{var p,b=++o===a.length,m=b&&0!==s.length;if(b){if(c=0===d.length?void 0:f[f.length-1],u=l,l=d.pop(),m){if(i)u=u.slice();else{for(var g={},v=0,y=Object.keys(u);v1)for(var r=new tB,i=1;i=0;--a){var o=i[a],s=isNaN(+o)?{}:[];s[o]=t,t=s}n=r.merge(n,t)}),n}var tW=Object.prototype.hasOwnProperty;function tK(e,t){var n,r,i,a,o;return(0,en.mG)(this,void 0,void 0,function(){var s,u,c,l,f,d,h,p,b,m,g,v,y,w,_,E,S,k,x,T,M,O,A;return(0,en.Jh)(this,function(L){switch(L.label){case 0:if(void 0===TextDecoder)throw Error("TextDecoder must be defined in the environment: please import a polyfill.");s=new TextDecoder("utf-8"),u=null===(n=e.headers)||void 0===n?void 0:n.get("content-type"),c="boundary=",l=(null==u?void 0:u.includes(c))?null==u?void 0:u.substring((null==u?void 0:u.indexOf(c))+c.length).replace(/['"]/g,"").replace(/\;(.*)/gm,"").trim():"-",f="\r\n--".concat(l),d="",h=tI(e),p=!0,L.label=1;case 1:if(!p)return[3,3];return[4,h.next()];case 2:for(m=(b=L.sent()).value,g=b.done,v="string"==typeof m?m:s.decode(m),y=d.length-f.length+1,p=!g,d+=v,w=d.indexOf(f,y);w>-1;){if(_=void 0,_=(O=[d.slice(0,w),d.slice(w+f.length),])[0],d=O[1],E=_.indexOf("\r\n\r\n"),(k=(S=tV(_.slice(0,E)))["content-type"])&&-1===k.toLowerCase().indexOf("application/json"))throw Error("Unsupported patch content type: application/json is required.");if(x=_.slice(E))try{T=tq(e,x),Object.keys(T).length>1||"data"in T||"incremental"in T||"errors"in T||"payload"in T?tz(T)?(M={},"payload"in T&&(M=(0,en.pi)({},T.payload)),"errors"in T&&(M=(0,en.pi)((0,en.pi)({},M),{extensions:(0,en.pi)((0,en.pi)({},"extensions"in M?M.extensions:null),((A={})[tN.YG]=T.errors,A))})),null===(r=t.next)||void 0===r||r.call(t,M)):null===(i=t.next)||void 0===i||i.call(t,T):1===Object.keys(T).length&&"hasNext"in T&&!T.hasNext&&(null===(a=t.complete)||void 0===a||a.call(t))}catch(C){tZ(C,t)}w=d.indexOf(f)}return[3,1];case 3:return null===(o=t.complete)||void 0===o||o.call(t),[2]}})})}function tV(e){var t={};return e.split("\n").forEach(function(e){var n=e.indexOf(":");if(n>-1){var r=e.slice(0,n).trim().toLowerCase(),i=e.slice(n+1).trim();t[r]=i}}),t}function tq(e,t){e.status>=300&&tD(e,function(){try{return JSON.parse(t)}catch(e){return t}}(),"Response not successful: Received status code ".concat(e.status));try{return JSON.parse(t)}catch(n){var r=n;throw r.name="ServerParseError",r.response=e,r.statusCode=e.status,r.bodyText=t,r}}function tZ(e,t){var n,r;"AbortError"!==e.name&&(e.result&&e.result.errors&&e.result.data&&(null===(n=t.next)||void 0===n||n.call(t,e.result)),null===(r=t.error)||void 0===r||r.call(t,e))}function tX(e,t,n){tJ(t)(e).then(function(e){var t,r;null===(t=n.next)||void 0===t||t.call(n,e),null===(r=n.complete)||void 0===r||r.call(n)}).catch(function(e){return tZ(e,n)})}function tJ(e){return function(t){return t.text().then(function(e){return tq(t,e)}).then(function(n){return t.status>=300&&tD(t,n,"Response not successful: Received status code ".concat(t.status)),Array.isArray(n)||tW.call(n,"data")||tW.call(n,"errors")||tD(t,n,"Server response was missing for query '".concat(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName,"'.")),n})}}var tQ=function(e){if(!e&&"undefined"==typeof fetch)throw __DEV__?new Q.ej("\n\"fetch\" has not been found globally and no fetcher has been configured. To fix this, install a fetch package (like https://www.npmjs.com/package/cross-fetch), instantiate the fetcher, and pass it into your HttpLink constructor. For example:\n\nimport fetch from 'cross-fetch';\nimport { ApolloClient, HttpLink } from '@apollo/client';\nconst client = new ApolloClient({\n link: new HttpLink({ uri: '/graphql', fetch })\n});\n "):new Q.ej(23)},t1=__webpack_require__(87392);function t0(e){return tl(e,{leave:t3})}var t2=80,t3={Name:function(e){return e.value},Variable:function(e){return"$"+e.name},Document:function(e){return t5(e.definitions,"\n\n")+"\n"},OperationDefinition:function(e){var t=e.operation,n=e.name,r=t9("(",t5(e.variableDefinitions,", "),")"),i=t5(e.directives," "),a=e.selectionSet;return n||i||r||"query"!==t?t5([t,t5([n,r]),i,a]," "):a},VariableDefinition:function(e){var t=e.variable,n=e.type,r=e.defaultValue,i=e.directives;return t+": "+n+t9(" = ",r)+t9(" ",t5(i," "))},SelectionSet:function(e){return t6(e.selections)},Field:function(e){var t=e.alias,n=e.name,r=e.arguments,i=e.directives,a=e.selectionSet,o=t9("",t,": ")+n,s=o+t9("(",t5(r,", "),")");return s.length>t2&&(s=o+t9("(\n",t8(t5(r,"\n")),"\n)")),t5([s,t5(i," "),a]," ")},Argument:function(e){var t;return e.name+": "+e.value},FragmentSpread:function(e){var t;return"..."+e.name+t9(" ",t5(e.directives," "))},InlineFragment:function(e){var t=e.typeCondition,n=e.directives,r=e.selectionSet;return t5(["...",t9("on ",t),t5(n," "),r]," ")},FragmentDefinition:function(e){var t=e.name,n=e.typeCondition,r=e.variableDefinitions,i=e.directives,a=e.selectionSet;return"fragment ".concat(t).concat(t9("(",t5(r,", "),")")," ")+"on ".concat(n," ").concat(t9("",t5(i," ")," "))+a},IntValue:function(e){return e.value},FloatValue:function(e){return e.value},StringValue:function(e,t){var n=e.value;return e.block?(0,t1.LZ)(n,"description"===t?"":" "):JSON.stringify(n)},BooleanValue:function(e){return e.value?"true":"false"},NullValue:function(){return"null"},EnumValue:function(e){return e.value},ListValue:function(e){return"["+t5(e.values,", ")+"]"},ObjectValue:function(e){return"{"+t5(e.fields,", ")+"}"},ObjectField:function(e){var t;return e.name+": "+e.value},Directive:function(e){var t;return"@"+e.name+t9("(",t5(e.arguments,", "),")")},NamedType:function(e){return e.name},ListType:function(e){return"["+e.type+"]"},NonNullType:function(e){return e.type+"!"},SchemaDefinition:t4(function(e){var t=e.directives,n=e.operationTypes;return t5(["schema",t5(t," "),t6(n)]," ")}),OperationTypeDefinition:function(e){var t;return e.operation+": "+e.type},ScalarTypeDefinition:t4(function(e){var t;return t5(["scalar",e.name,t5(e.directives," ")]," ")}),ObjectTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),FieldDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.type,i=e.directives;return t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+": "+r+t9(" ",t5(i," "))}),InputValueDefinition:t4(function(e){var t=e.name,n=e.type,r=e.defaultValue,i=e.directives;return t5([t+": "+n,t9("= ",r),t5(i," ")]," ")}),InterfaceTypeDefinition:t4(function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")}),UnionTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.types;return t5(["union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")}),EnumTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.values;return t5(["enum",t,t5(n," "),t6(r)]," ")}),EnumValueDefinition:t4(function(e){var t;return t5([e.name,t5(e.directives," ")]," ")}),InputObjectTypeDefinition:t4(function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["input",t,t5(n," "),t6(r)]," ")}),DirectiveDefinition:t4(function(e){var t=e.name,n=e.arguments,r=e.repeatable,i=e.locations;return"directive @"+t+(ne(n)?t9("(\n",t8(t5(n,"\n")),"\n)"):t9("(",t5(n,", "),")"))+(r?" repeatable":"")+" on "+t5(i," | ")}),SchemaExtension:function(e){var t=e.directives,n=e.operationTypes;return t5(["extend schema",t5(t," "),t6(n)]," ")},ScalarTypeExtension:function(e){var t;return t5(["extend scalar",e.name,t5(e.directives," ")]," ")},ObjectTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend type",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},InterfaceTypeExtension:function(e){var t=e.name,n=e.interfaces,r=e.directives,i=e.fields;return t5(["extend interface",t,t9("implements ",t5(n," & ")),t5(r," "),t6(i)]," ")},UnionTypeExtension:function(e){var t=e.name,n=e.directives,r=e.types;return t5(["extend union",t,t5(n," "),r&&0!==r.length?"= "+t5(r," | "):""]," ")},EnumTypeExtension:function(e){var t=e.name,n=e.directives,r=e.values;return t5(["extend enum",t,t5(n," "),t6(r)]," ")},InputObjectTypeExtension:function(e){var t=e.name,n=e.directives,r=e.fields;return t5(["extend input",t,t5(n," "),t6(r)]," ")}};function t4(e){return function(t){return t5([t.description,e(t)],"\n")}}function t5(e){var t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return null!==(t=null==e?void 0:e.filter(function(e){return e}).join(n))&&void 0!==t?t:""}function t6(e){return t9("{\n",t8(t5(e,"\n")),"\n}")}function t9(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return null!=t&&""!==t?e+t+n:""}function t8(e){return t9(" ",e.replace(/\n/g,"\n "))}function t7(e){return -1!==e.indexOf("\n")}function ne(e){return null!=e&&e.some(t7)}var nt,nn,nr,ni={http:{includeQuery:!0,includeExtensions:!1,preserveHeaderCase:!1},headers:{accept:"*/*","content-type":"application/json"},options:{method:"POST"}},na=function(e,t){return t(e)};function no(e,t){for(var n=[],r=2;rObject.create(null),{forEach:nv,slice:ny}=Array.prototype,{hasOwnProperty:nw}=Object.prototype;class n_{constructor(e=!0,t=ng){this.weakness=e,this.makeData=t}lookup(...e){return this.lookupArray(e)}lookupArray(e){let t=this;return nv.call(e,e=>t=t.getChildTrie(e)),nw.call(t,"data")?t.data:t.data=this.makeData(ny.call(e))}peek(...e){return this.peekArray(e)}peekArray(e){let t=this;for(let n=0,r=e.length;t&&n=0;--o)t.definitions[o].kind===nL.h.OPERATION_DEFINITION&&++a;var s=nN(e),u=e.some(function(e){return e.remove}),c=function(e){return u&&e&&e.some(s)},l=new Map,f=!1,d={enter:function(e){if(c(e.directives))return f=!0,null}},h=tl(t,{Field:d,InlineFragment:d,VariableDefinition:{enter:function(){return!1}},Variable:{enter:function(e,t,n,r,a){var o=i(a);o&&o.variables.add(e.name.value)}},FragmentSpread:{enter:function(e,t,n,r,a){if(c(e.directives))return f=!0,null;var o=i(a);o&&o.fragmentSpreads.add(e.name.value)}},FragmentDefinition:{enter:function(e,t,n,r){l.set(JSON.stringify(r),e)},leave:function(e,t,n,i){return e===l.get(JSON.stringify(i))?e:a>0&&e.selectionSet.selections.every(function(e){return e.kind===nL.h.FIELD&&"__typename"===e.name.value})?(r(e.name.value).removed=!0,f=!0,null):void 0}},Directive:{leave:function(e){if(s(e))return f=!0,null}}});if(!f)return t;var p=function(e){return e.transitiveVars||(e.transitiveVars=new Set(e.variables),e.removed||e.fragmentSpreads.forEach(function(t){p(r(t)).transitiveVars.forEach(function(t){e.transitiveVars.add(t)})})),e},b=new Set;h.definitions.forEach(function(e){e.kind===nL.h.OPERATION_DEFINITION?p(n(e.name&&e.name.value)).fragmentSpreads.forEach(function(e){b.add(e)}):e.kind!==nL.h.FRAGMENT_DEFINITION||0!==a||r(e.name.value).removed||b.add(e.name.value)}),b.forEach(function(e){p(r(e)).fragmentSpreads.forEach(function(e){b.add(e)})});var m=function(e){return!!(!b.has(e)||r(e).removed)},g={enter:function(e){if(m(e.name.value))return null}};return nD(tl(h,{FragmentSpread:g,FragmentDefinition:g,OperationDefinition:{leave:function(e){if(e.variableDefinitions){var t=p(n(e.name&&e.name.value)).transitiveVars;if(t.size0},t.prototype.tearDownQuery=function(){this.isTornDown||(this.concast&&this.observer&&(this.concast.removeObserver(this.observer),delete this.concast,delete this.observer),this.stopPolling(),this.subscriptions.forEach(function(e){return e.unsubscribe()}),this.subscriptions.clear(),this.queryManager.stopQuery(this.queryId),this.observers.clear(),this.isTornDown=!0)},t}(eT);function n4(e){var t=e.options,n=t.fetchPolicy,r=t.nextFetchPolicy;return"cache-and-network"===n||"network-only"===n?e.reobserve({fetchPolicy:"cache-first",nextFetchPolicy:function(){return(this.nextFetchPolicy=r,"function"==typeof r)?r.apply(this,arguments):n}}):e.reobserve()}function n5(e){__DEV__&&Q.kG.error("Unhandled error",e.message,e.stack)}function n6(e){__DEV__&&e&&__DEV__&&Q.kG.debug("Missing cache result fields: ".concat(JSON.stringify(e)),e)}function n9(e){return"network-only"===e||"no-cache"===e||"standby"===e}nK(n3);function n8(e){return e.kind===nL.h.FIELD||e.kind===nL.h.FRAGMENT_SPREAD||e.kind===nL.h.INLINE_FRAGMENT}function n7(e){return e.kind===Kind.SCALAR_TYPE_DEFINITION||e.kind===Kind.OBJECT_TYPE_DEFINITION||e.kind===Kind.INTERFACE_TYPE_DEFINITION||e.kind===Kind.UNION_TYPE_DEFINITION||e.kind===Kind.ENUM_TYPE_DEFINITION||e.kind===Kind.INPUT_OBJECT_TYPE_DEFINITION}function re(e){return e.kind===Kind.SCALAR_TYPE_EXTENSION||e.kind===Kind.OBJECT_TYPE_EXTENSION||e.kind===Kind.INTERFACE_TYPE_EXTENSION||e.kind===Kind.UNION_TYPE_EXTENSION||e.kind===Kind.ENUM_TYPE_EXTENSION||e.kind===Kind.INPUT_OBJECT_TYPE_EXTENSION}var rt=function(){return Object.create(null)},rn=Array.prototype,rr=rn.forEach,ri=rn.slice,ra=function(){function e(e,t){void 0===e&&(e=!0),void 0===t&&(t=rt),this.weakness=e,this.makeData=t}return e.prototype.lookup=function(){for(var e=[],t=0;tclass{constructor(){this.id=["slot",rc++,Date.now(),Math.random().toString(36).slice(2),].join(":")}hasValue(){for(let e=rs;e;e=e.parent)if(this.id in e.slots){let t=e.slots[this.id];if(t===ru)break;return e!==rs&&(rs.slots[this.id]=t),!0}return rs&&(rs.slots[this.id]=ru),!1}getValue(){if(this.hasValue())return rs.slots[this.id]}withValue(e,t,n,r){let i={__proto__:null,[this.id]:e},a=rs;rs={parent:a,slots:i};try{return t.apply(r,n)}finally{rs=a}}static bind(e){let t=rs;return function(){let n=rs;try{return rs=t,e.apply(this,arguments)}finally{rs=n}}}static noContext(e,t,n){if(!rs)return e.apply(n,t);{let r=rs;try{return rs=null,e.apply(n,t)}finally{rs=r}}}};function rf(e){try{return e()}catch(t){}}let rd="@wry/context:Slot",rh=rf(()=>globalThis)||rf(()=>global)||Object.create(null),rp=rh,rb=rp[rd]||Array[rd]||function(e){try{Object.defineProperty(rp,rd,{value:e,enumerable:!1,writable:!1,configurable:!0})}finally{return e}}(rl()),{bind:rm,noContext:rg}=rb;function rv(){}var ry=function(){function e(e,t){void 0===e&&(e=1/0),void 0===t&&(t=rv),this.max=e,this.dispose=t,this.map=new Map,this.newest=null,this.oldest=null}return e.prototype.has=function(e){return this.map.has(e)},e.prototype.get=function(e){var t=this.getNode(e);return t&&t.value},e.prototype.getNode=function(e){var t=this.map.get(e);if(t&&t!==this.newest){var n=t.older,r=t.newer;r&&(r.older=n),n&&(n.newer=r),t.older=this.newest,t.older.newer=t,t.newer=null,this.newest=t,t===this.oldest&&(this.oldest=r)}return t},e.prototype.set=function(e,t){var n=this.getNode(e);return n?n.value=t:(n={key:e,value:t,newer:null,older:this.newest},this.newest&&(this.newest.newer=n),this.newest=n,this.oldest=this.oldest||n,this.map.set(e,n),n.value)},e.prototype.clean=function(){for(;this.oldest&&this.map.size>this.max;)this.delete(this.oldest.key)},e.prototype.delete=function(e){var t=this.map.get(e);return!!t&&(t===this.newest&&(this.newest=t.older),t===this.oldest&&(this.oldest=t.newer),t.newer&&(t.newer.older=t.older),t.older&&(t.older.newer=t.newer),this.map.delete(e),this.dispose(t.value,e),!0)},e}(),rw=new rb,r_=Object.prototype.hasOwnProperty,rE=void 0===(n=Array.from)?function(e){var t=[];return e.forEach(function(e){return t.push(e)}),t}:n;function rS(e){var t=e.unsubscribe;"function"==typeof t&&(e.unsubscribe=void 0,t())}var rk=[],rx=100;function rT(e,t){if(!e)throw Error(t||"assertion failure")}function rM(e,t){var n=e.length;return n>0&&n===t.length&&e[n-1]===t[n-1]}function rO(e){switch(e.length){case 0:throw Error("unknown value");case 1:return e[0];case 2:throw e[1]}}function rA(e){return e.slice(0)}var rL=function(){function e(t){this.fn=t,this.parents=new Set,this.childValues=new Map,this.dirtyChildren=null,this.dirty=!0,this.recomputing=!1,this.value=[],this.deps=null,++e.count}return e.prototype.peek=function(){if(1===this.value.length&&!rN(this))return rC(this),this.value[0]},e.prototype.recompute=function(e){return rT(!this.recomputing,"already recomputing"),rC(this),rN(this)?rI(this,e):rO(this.value)},e.prototype.setDirty=function(){this.dirty||(this.dirty=!0,this.value.length=0,rR(this),rS(this))},e.prototype.dispose=function(){var e=this;this.setDirty(),rH(this),rF(this,function(t,n){t.setDirty(),r$(t,e)})},e.prototype.forget=function(){this.dispose()},e.prototype.dependOn=function(e){e.add(this),this.deps||(this.deps=rk.pop()||new Set),this.deps.add(e)},e.prototype.forgetDeps=function(){var e=this;this.deps&&(rE(this.deps).forEach(function(t){return t.delete(e)}),this.deps.clear(),rk.push(this.deps),this.deps=null)},e.count=0,e}();function rC(e){var t=rw.getValue();if(t)return e.parents.add(t),t.childValues.has(e)||t.childValues.set(e,[]),rN(e)?rY(t,e):rB(t,e),t}function rI(e,t){return rH(e),rw.withValue(e,rD,[e,t]),rz(e,t)&&rP(e),rO(e.value)}function rD(e,t){e.recomputing=!0,e.value.length=0;try{e.value[0]=e.fn.apply(null,t)}catch(n){e.value[1]=n}e.recomputing=!1}function rN(e){return e.dirty||!!(e.dirtyChildren&&e.dirtyChildren.size)}function rP(e){e.dirty=!1,!rN(e)&&rj(e)}function rR(e){rF(e,rY)}function rj(e){rF(e,rB)}function rF(e,t){var n=e.parents.size;if(n)for(var r=rE(e.parents),i=0;i0&&e.childValues.forEach(function(t,n){r$(e,n)}),e.forgetDeps(),rT(null===e.dirtyChildren)}function r$(e,t){t.parents.delete(e),e.childValues.delete(t),rU(e,t)}function rz(e,t){if("function"==typeof e.subscribe)try{rS(e),e.unsubscribe=e.subscribe.apply(null,t)}catch(n){return e.setDirty(),!1}return!0}var rG={setDirty:!0,dispose:!0,forget:!0};function rW(e){var t=new Map,n=e&&e.subscribe;function r(e){var r=rw.getValue();if(r){var i=t.get(e);i||t.set(e,i=new Set),r.dependOn(i),"function"==typeof n&&(rS(i),i.unsubscribe=n(e))}}return r.dirty=function(e,n){var r=t.get(e);if(r){var i=n&&r_.call(rG,n)?n:"setDirty";rE(r).forEach(function(e){return e[i]()}),t.delete(e),rS(r)}},r}function rK(){var e=new ra("function"==typeof WeakMap);return function(){return e.lookupArray(arguments)}}var rV=rK(),rq=new Set;function rZ(e,t){void 0===t&&(t=Object.create(null));var n=new ry(t.max||65536,function(e){return e.dispose()}),r=t.keyArgs,i=t.makeCacheKey||rK(),a=function(){var a=i.apply(null,r?r.apply(null,arguments):arguments);if(void 0===a)return e.apply(null,arguments);var o=n.get(a);o||(n.set(a,o=new rL(e)),o.subscribe=t.subscribe,o.forget=function(){return n.delete(a)});var s=o.recompute(Array.prototype.slice.call(arguments));return n.set(a,o),rq.add(n),rw.hasValue()||(rq.forEach(function(e){return e.clean()}),rq.clear()),s};function o(e){var t=n.get(e);t&&t.setDirty()}function s(e){var t=n.get(e);if(t)return t.peek()}function u(e){return n.delete(e)}return Object.defineProperty(a,"size",{get:function(){return n.map.size},configurable:!1,enumerable:!1}),a.dirtyKey=o,a.dirty=function(){o(i.apply(null,arguments))},a.peekKey=s,a.peek=function(){return s(i.apply(null,arguments))},a.forgetKey=u,a.forget=function(){return u(i.apply(null,arguments))},a.makeCacheKey=i,a.getKey=r?function(){return i.apply(null,r.apply(null,arguments))}:i,Object.freeze(a)}var rX=new rb,rJ=new WeakMap;function rQ(e){var t=rJ.get(e);return t||rJ.set(e,t={vars:new Set,dep:rW()}),t}function r1(e){rQ(e).vars.forEach(function(t){return t.forgetCache(e)})}function r0(e){rQ(e).vars.forEach(function(t){return t.attachCache(e)})}function r2(e){var t=new Set,n=new Set,r=function(a){if(arguments.length>0){if(e!==a){e=a,t.forEach(function(e){rQ(e).dep.dirty(r),r3(e)});var o=Array.from(n);n.clear(),o.forEach(function(t){return t(e)})}}else{var s=rX.getValue();s&&(i(s),rQ(s).dep(r))}return e};r.onNextChange=function(e){return n.add(e),function(){n.delete(e)}};var i=r.attachCache=function(e){return t.add(e),rQ(e).vars.add(r),r};return r.forgetCache=function(e){return t.delete(e)},r}function r3(e){e.broadcastWatches&&e.broadcastWatches()}var r4=function(){function e(e){var t=e.cache,n=e.client,r=e.resolvers,i=e.fragmentMatcher;this.selectionsToResolveCache=new WeakMap,this.cache=t,n&&(this.client=n),r&&this.addResolvers(r),i&&this.setFragmentMatcher(i)}return e.prototype.addResolvers=function(e){var t=this;this.resolvers=this.resolvers||{},Array.isArray(e)?e.forEach(function(e){t.resolvers=tj(t.resolvers,e)}):this.resolvers=tj(this.resolvers,e)},e.prototype.setResolvers=function(e){this.resolvers={},this.addResolvers(e)},e.prototype.getResolvers=function(){return this.resolvers||{}},e.prototype.runResolvers=function(e){var t=e.document,n=e.remoteResult,r=e.context,i=e.variables,a=e.onlyRunForcedResolvers,o=void 0!==a&&a;return(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(e){return t?[2,this.resolveDocument(t,n.data,r,i,this.fragmentMatcher,o).then(function(e){return(0,en.pi)((0,en.pi)({},n),{data:e.result})})]:[2,n]})})},e.prototype.setFragmentMatcher=function(e){this.fragmentMatcher=e},e.prototype.getFragmentMatcher=function(){return this.fragmentMatcher},e.prototype.clientQuery=function(e){return tb(["client"],e)&&this.resolvers?e:null},e.prototype.serverQuery=function(e){return n$(e)},e.prototype.prepareContext=function(e){var t=this.cache;return(0,en.pi)((0,en.pi)({},e),{cache:t,getCacheKey:function(e){return t.identify(e)}})},e.prototype.addExportedVariables=function(e,t,n){return void 0===t&&(t={}),void 0===n&&(n={}),(0,en.mG)(this,void 0,void 0,function(){return(0,en.Jh)(this,function(r){return e?[2,this.resolveDocument(e,this.buildRootValueFromCache(e,t)||{},this.prepareContext(n),t).then(function(e){return(0,en.pi)((0,en.pi)({},t),e.exportedVariables)})]:[2,(0,en.pi)({},t)]})})},e.prototype.shouldForceResolvers=function(e){var t=!1;return tl(e,{Directive:{enter:function(e){if("client"===e.name.value&&e.arguments&&(t=e.arguments.some(function(e){return"always"===e.name.value&&"BooleanValue"===e.value.kind&&!0===e.value.value})))return tc}}}),t},e.prototype.buildRootValueFromCache=function(e,t){return this.cache.diff({query:nH(e),variables:t,returnPartialData:!0,optimistic:!1}).result},e.prototype.resolveDocument=function(e,t,n,r,i,a){return void 0===n&&(n={}),void 0===r&&(r={}),void 0===i&&(i=function(){return!0}),void 0===a&&(a=!1),(0,en.mG)(this,void 0,void 0,function(){var o,s,u,c,l,f,d,h,p,b,m;return(0,en.Jh)(this,function(g){return o=e9(e),s=e4(e),u=eL(s),c=this.collectSelectionsToResolve(o,u),f=(l=o.operation)?l.charAt(0).toUpperCase()+l.slice(1):"Query",d=this,h=d.cache,p=d.client,b={fragmentMap:u,context:(0,en.pi)((0,en.pi)({},n),{cache:h,client:p}),variables:r,fragmentMatcher:i,defaultOperationType:f,exportedVariables:{},selectionsToResolve:c,onlyRunForcedResolvers:a},m=!1,[2,this.resolveSelectionSet(o.selectionSet,m,t,b).then(function(e){return{result:e,exportedVariables:b.exportedVariables}})]})})},e.prototype.resolveSelectionSet=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c=this;return(0,en.Jh)(this,function(l){return i=r.fragmentMap,a=r.context,o=r.variables,s=[n],u=function(e){return(0,en.mG)(c,void 0,void 0,function(){var u,c;return(0,en.Jh)(this,function(l){return(t||r.selectionsToResolve.has(e))&&td(e,o)?eQ(e)?[2,this.resolveField(e,t,n,r).then(function(t){var n;void 0!==t&&s.push(((n={})[eX(e)]=t,n))})]:(e1(e)?u=e:(u=i[e.name.value],__DEV__?(0,Q.kG)(u,"No fragment named ".concat(e.name.value)):(0,Q.kG)(u,11)),u&&u.typeCondition&&(c=u.typeCondition.name.value,r.fragmentMatcher(n,c,a)))?[2,this.resolveSelectionSet(u.selectionSet,t,n,r).then(function(e){s.push(e)})]:[2]:[2]})})},[2,Promise.all(e.selections.map(u)).then(function(){return tF(s)})]})})},e.prototype.resolveField=function(e,t,n,r){return(0,en.mG)(this,void 0,void 0,function(){var i,a,o,s,u,c,l,f,d,h=this;return(0,en.Jh)(this,function(p){return n?(i=r.variables,a=e.name.value,o=eX(e),s=a!==o,c=Promise.resolve(u=n[o]||n[a]),(!r.onlyRunForcedResolvers||this.shouldForceResolvers(e))&&(l=n.__typename||r.defaultOperationType,(f=this.resolvers&&this.resolvers[l])&&(d=f[s?a:o])&&(c=Promise.resolve(rX.withValue(this.cache,d,[n,eZ(e,i),r.context,{field:e,fragmentMap:r.fragmentMap},])))),[2,c.then(function(n){if(void 0===n&&(n=u),e.directives&&e.directives.forEach(function(e){"export"===e.name.value&&e.arguments&&e.arguments.forEach(function(e){"as"===e.name.value&&"StringValue"===e.value.kind&&(r.exportedVariables[e.value.value]=n)})}),!e.selectionSet||null==n)return n;var i,a,o=null!==(a=null===(i=e.directives)||void 0===i?void 0:i.some(function(e){return"client"===e.name.value}))&&void 0!==a&&a;return Array.isArray(n)?h.resolveSubSelectedArray(e,t||o,n,r):e.selectionSet?h.resolveSelectionSet(e.selectionSet,t||o,n,r):void 0})]):[2,null]})})},e.prototype.resolveSubSelectedArray=function(e,t,n,r){var i=this;return Promise.all(n.map(function(n){return null===n?null:Array.isArray(n)?i.resolveSubSelectedArray(e,t,n,r):e.selectionSet?i.resolveSelectionSet(e.selectionSet,t,n,r):void 0}))},e.prototype.collectSelectionsToResolve=function(e,t){var n=function(e){return!Array.isArray(e)},r=this.selectionsToResolveCache;function i(e){if(!r.has(e)){var a=new Set;r.set(e,a),tl(e,{Directive:function(e,t,r,i,o){"client"===e.name.value&&o.forEach(function(e){n(e)&&n8(e)&&a.add(e)})},FragmentSpread:function(e,r,o,s,u){var c=t[e.name.value];__DEV__?(0,Q.kG)(c,"No fragment named ".concat(e.name.value)):(0,Q.kG)(c,12);var l=i(c);l.size>0&&(u.forEach(function(e){n(e)&&n8(e)&&a.add(e)}),a.add(e),l.forEach(function(e){a.add(e)}))}})}return r.get(e)}return i(e)},e}(),r5=new(t_.mr?WeakMap:Map);function r6(e,t){var n=e[t];"function"==typeof n&&(e[t]=function(){return r5.set(e,(r5.get(e)+1)%1e15),n.apply(this,arguments)})}function r9(e){e.notifyTimeout&&(clearTimeout(e.notifyTimeout),e.notifyTimeout=void 0)}var r8=function(){function e(e,t){void 0===t&&(t=e.generateQueryId()),this.queryId=t,this.listeners=new Set,this.document=null,this.lastRequestId=1,this.subscriptions=new Set,this.stopped=!1,this.dirty=!1,this.observableQuery=null;var n=this.cache=e.cache;r5.has(n)||(r5.set(n,0),r6(n,"evict"),r6(n,"modify"),r6(n,"reset"))}return e.prototype.init=function(e){var t=e.networkStatus||nZ.I.loading;return this.variables&&this.networkStatus!==nZ.I.loading&&!(0,nm.D)(this.variables,e.variables)&&(t=nZ.I.setVariables),(0,nm.D)(e.variables,this.variables)||(this.lastDiff=void 0),Object.assign(this,{document:e.document,variables:e.variables,networkError:null,graphQLErrors:this.graphQLErrors||[],networkStatus:t}),e.observableQuery&&this.setObservableQuery(e.observableQuery),e.lastRequestId&&(this.lastRequestId=e.lastRequestId),this},e.prototype.reset=function(){r9(this),this.dirty=!1},e.prototype.getDiff=function(e){void 0===e&&(e=this.variables);var t=this.getDiffOptions(e);if(this.lastDiff&&(0,nm.D)(t,this.lastDiff.options))return this.lastDiff.diff;this.updateWatch(this.variables=e);var n=this.observableQuery;if(n&&"no-cache"===n.options.fetchPolicy)return{complete:!1};var r=this.cache.diff(t);return this.updateLastDiff(r,t),r},e.prototype.updateLastDiff=function(e,t){this.lastDiff=e?{diff:e,options:t||this.getDiffOptions()}:void 0},e.prototype.getDiffOptions=function(e){var t;return void 0===e&&(e=this.variables),{query:this.document,variables:e,returnPartialData:!0,optimistic:!0,canonizeResults:null===(t=this.observableQuery)||void 0===t?void 0:t.options.canonizeResults}},e.prototype.setDiff=function(e){var t=this,n=this.lastDiff&&this.lastDiff.diff;this.updateLastDiff(e),this.dirty||(0,nm.D)(n&&n.result,e&&e.result)||(this.dirty=!0,this.notifyTimeout||(this.notifyTimeout=setTimeout(function(){return t.notify()},0)))},e.prototype.setObservableQuery=function(e){var t=this;e!==this.observableQuery&&(this.oqListener&&this.listeners.delete(this.oqListener),this.observableQuery=e,e?(e.queryInfo=this,this.listeners.add(this.oqListener=function(){t.getDiff().fromOptimisticTransaction?e.observe():n4(e)})):delete this.oqListener)},e.prototype.notify=function(){var e=this;r9(this),this.shouldNotify()&&this.listeners.forEach(function(t){return t(e)}),this.dirty=!1},e.prototype.shouldNotify=function(){if(!this.dirty||!this.listeners.size)return!1;if((0,nZ.O)(this.networkStatus)&&this.observableQuery){var e=this.observableQuery.options.fetchPolicy;if("cache-only"!==e&&"cache-and-network"!==e)return!1}return!0},e.prototype.stop=function(){if(!this.stopped){this.stopped=!0,this.reset(),this.cancel(),this.cancel=e.prototype.cancel,this.subscriptions.forEach(function(e){return e.unsubscribe()});var t=this.observableQuery;t&&t.stopPolling()}},e.prototype.cancel=function(){},e.prototype.updateWatch=function(e){var t=this;void 0===e&&(e=this.variables);var n=this.observableQuery;if(!n||"no-cache"!==n.options.fetchPolicy){var r=(0,en.pi)((0,en.pi)({},this.getDiffOptions(e)),{watcher:this,callback:function(e){return t.setDiff(e)}});this.lastWatch&&(0,nm.D)(r,this.lastWatch)||(this.cancel(),this.cancel=this.cache.watch(this.lastWatch=r))}},e.prototype.resetLastWrite=function(){this.lastWrite=void 0},e.prototype.shouldWrite=function(e,t){var n=this.lastWrite;return!(n&&n.dmCount===r5.get(this.cache)&&(0,nm.D)(t,n.variables)&&(0,nm.D)(e.data,n.result.data))},e.prototype.markResult=function(e,t,n,r){var i=this,a=new tB,o=(0,tP.O)(e.errors)?e.errors.slice(0):[];if(this.reset(),"incremental"in e&&(0,tP.O)(e.incremental)){var s=tG(this.getDiff().result,e);e.data=s}else if("hasNext"in e&&e.hasNext){var u=this.getDiff();e.data=a.merge(u.result,e.data)}this.graphQLErrors=o,"no-cache"===n.fetchPolicy?this.updateLastDiff({result:e.data,complete:!0},this.getDiffOptions(n.variables)):0!==r&&(r7(e,n.errorPolicy)?this.cache.performTransaction(function(a){if(i.shouldWrite(e,n.variables))a.writeQuery({query:t,data:e.data,variables:n.variables,overwrite:1===r}),i.lastWrite={result:e,variables:n.variables,dmCount:r5.get(i.cache)};else if(i.lastDiff&&i.lastDiff.diff.complete){e.data=i.lastDiff.diff.result;return}var o=i.getDiffOptions(n.variables),s=a.diff(o);i.stopped||i.updateWatch(n.variables),i.updateLastDiff(s,o),s.complete&&(e.data=s.result)}):this.lastWrite=void 0)},e.prototype.markReady=function(){return this.networkError=null,this.networkStatus=nZ.I.ready},e.prototype.markError=function(e){return this.networkStatus=nZ.I.error,this.lastWrite=void 0,this.reset(),e.graphQLErrors&&(this.graphQLErrors=e.graphQLErrors),e.networkError&&(this.networkError=e.networkError),e},e}();function r7(e,t){void 0===t&&(t="none");var n="ignore"===t||"all"===t,r=!nO(e);return!r&&n&&e.data&&(r=!0),r}var ie=Object.prototype.hasOwnProperty,it=function(){function e(e){var t=e.cache,n=e.link,r=e.defaultOptions,i=e.queryDeduplication,a=void 0!==i&&i,o=e.onBroadcast,s=e.ssrMode,u=void 0!==s&&s,c=e.clientAwareness,l=void 0===c?{}:c,f=e.localState,d=e.assumeImmutableResults;this.clientAwareness={},this.queries=new Map,this.fetchCancelFns=new Map,this.transformCache=new(t_.mr?WeakMap:Map),this.queryIdCounter=1,this.requestIdCounter=1,this.mutationIdCounter=1,this.inFlightLinkObservables=new Map,this.cache=t,this.link=n,this.defaultOptions=r||Object.create(null),this.queryDeduplication=a,this.clientAwareness=l,this.localState=f||new r4({cache:t}),this.ssrMode=u,this.assumeImmutableResults=!!d,(this.onBroadcast=o)&&(this.mutationStore=Object.create(null))}return e.prototype.stop=function(){var e=this;this.queries.forEach(function(t,n){e.stopQueryNoBroadcast(n)}),this.cancelPendingFetches(__DEV__?new Q.ej("QueryManager stopped while query was in flight"):new Q.ej(14))},e.prototype.cancelPendingFetches=function(e){this.fetchCancelFns.forEach(function(t){return t(e)}),this.fetchCancelFns.clear()},e.prototype.mutate=function(e){var t,n,r=e.mutation,i=e.variables,a=e.optimisticResponse,o=e.updateQueries,s=e.refetchQueries,u=void 0===s?[]:s,c=e.awaitRefetchQueries,l=void 0!==c&&c,f=e.update,d=e.onQueryUpdated,h=e.fetchPolicy,p=void 0===h?(null===(t=this.defaultOptions.mutate)||void 0===t?void 0:t.fetchPolicy)||"network-only":h,b=e.errorPolicy,m=void 0===b?(null===(n=this.defaultOptions.mutate)||void 0===n?void 0:n.errorPolicy)||"none":b,g=e.keepRootFields,v=e.context;return(0,en.mG)(this,void 0,void 0,function(){var e,t,n,s,c,h;return(0,en.Jh)(this,function(b){switch(b.label){case 0:if(__DEV__?(0,Q.kG)(r,"mutation option is required. You must specify your GraphQL document in the mutation option."):(0,Q.kG)(r,15),__DEV__?(0,Q.kG)("network-only"===p||"no-cache"===p,"Mutations support only 'network-only' or 'no-cache' fetchPolicy strings. The default `network-only` behavior automatically writes mutation results to the cache. Passing `no-cache` skips the cache write."):(0,Q.kG)("network-only"===p||"no-cache"===p,16),e=this.generateMutationId(),n=(t=this.transform(r)).document,s=t.hasClientExports,r=this.cache.transformForLink(n),i=this.getVariables(r,i),!s)return[3,2];return[4,this.localState.addExportedVariables(r,i,v)];case 1:i=b.sent(),b.label=2;case 2:return c=this.mutationStore&&(this.mutationStore[e]={mutation:r,variables:i,loading:!0,error:null}),a&&this.markMutationOptimistic(a,{mutationId:e,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,updateQueries:o,update:f,keepRootFields:g}),this.broadcastQueries(),h=this,[2,new Promise(function(t,n){return nM(h.getObservableFromLink(r,(0,en.pi)((0,en.pi)({},v),{optimisticResponse:a}),i,!1),function(t){if(nO(t)&&"none"===m)throw new tN.cA({graphQLErrors:nA(t)});c&&(c.loading=!1,c.error=null);var n=(0,en.pi)({},t);return"function"==typeof u&&(u=u(n)),"ignore"===m&&nO(n)&&delete n.errors,h.markMutationResult({mutationId:e,result:n,document:r,variables:i,fetchPolicy:p,errorPolicy:m,context:v,update:f,updateQueries:o,awaitRefetchQueries:l,refetchQueries:u,removeOptimistic:a?e:void 0,onQueryUpdated:d,keepRootFields:g})}).subscribe({next:function(e){h.broadcastQueries(),"hasNext"in e&&!1!==e.hasNext||t(e)},error:function(t){c&&(c.loading=!1,c.error=t),a&&h.cache.removeOptimistic(e),h.broadcastQueries(),n(t instanceof tN.cA?t:new tN.cA({networkError:t}))}})})]}})})},e.prototype.markMutationResult=function(e,t){var n=this;void 0===t&&(t=this.cache);var r=e.result,i=[],a="no-cache"===e.fetchPolicy;if(!a&&r7(r,e.errorPolicy)){if(tU(r)||i.push({result:r.data,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}),tU(r)&&(0,tP.O)(r.incremental)){var o=t.diff({id:"ROOT_MUTATION",query:this.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0}),s=void 0;o.result&&(s=tG(o.result,r)),void 0!==s&&(r.data=s,i.push({result:s,dataId:"ROOT_MUTATION",query:e.document,variables:e.variables}))}var u=e.updateQueries;u&&this.queries.forEach(function(e,a){var o=e.observableQuery,s=o&&o.queryName;if(s&&ie.call(u,s)){var c,l=u[s],f=n.queries.get(a),d=f.document,h=f.variables,p=t.diff({query:d,variables:h,returnPartialData:!0,optimistic:!1}),b=p.result;if(p.complete&&b){var m=l(b,{mutationResult:r,queryName:d&&e3(d)||void 0,queryVariables:h});m&&i.push({result:m,dataId:"ROOT_QUERY",query:d,variables:h})}}})}if(i.length>0||e.refetchQueries||e.update||e.onQueryUpdated||e.removeOptimistic){var c=[];if(this.refetchQueries({updateCache:function(t){a||i.forEach(function(e){return t.write(e)});var o=e.update,s=!t$(r)||tU(r)&&!r.hasNext;if(o){if(!a){var u=t.diff({id:"ROOT_MUTATION",query:n.transform(e.document).asQuery,variables:e.variables,optimistic:!1,returnPartialData:!0});u.complete&&("incremental"in(r=(0,en.pi)((0,en.pi)({},r),{data:u.result}))&&delete r.incremental,"hasNext"in r&&delete r.hasNext)}s&&o(t,r,{context:e.context,variables:e.variables})}a||e.keepRootFields||!s||t.modify({id:"ROOT_MUTATION",fields:function(e,t){var n=t.fieldName,r=t.DELETE;return"__typename"===n?e:r}})},include:e.refetchQueries,optimistic:!1,removeOptimistic:e.removeOptimistic,onQueryUpdated:e.onQueryUpdated||null}).forEach(function(e){return c.push(e)}),e.awaitRefetchQueries||e.onQueryUpdated)return Promise.all(c).then(function(){return r})}return Promise.resolve(r)},e.prototype.markMutationOptimistic=function(e,t){var n=this,r="function"==typeof e?e(t.variables):e;return this.cache.recordOptimisticTransaction(function(e){try{n.markMutationResult((0,en.pi)((0,en.pi)({},t),{result:{data:r}}),e)}catch(i){__DEV__&&Q.kG.error(i)}},t.mutationId)},e.prototype.fetchQuery=function(e,t,n){return this.fetchQueryObservable(e,t,n).promise},e.prototype.getQueryStore=function(){var e=Object.create(null);return this.queries.forEach(function(t,n){e[n]={variables:t.variables,networkStatus:t.networkStatus,networkError:t.networkError,graphQLErrors:t.graphQLErrors}}),e},e.prototype.resetErrors=function(e){var t=this.queries.get(e);t&&(t.networkError=void 0,t.graphQLErrors=[])},e.prototype.transform=function(e){var t=this.transformCache;if(!t.has(e)){var n=this.cache.transformDocument(e),r=nY(n),i=this.localState.clientQuery(n),a=r&&this.localState.serverQuery(r),o={document:n,hasClientExports:tm(n),hasForcedResolvers:this.localState.shouldForceResolvers(n),clientQuery:i,serverQuery:a,defaultVars:e8(e2(n)),asQuery:(0,en.pi)((0,en.pi)({},n),{definitions:n.definitions.map(function(e){return"OperationDefinition"===e.kind&&"query"!==e.operation?(0,en.pi)((0,en.pi)({},e),{operation:"query"}):e})})},s=function(e){e&&!t.has(e)&&t.set(e,o)};s(e),s(n),s(i),s(a)}return t.get(e)},e.prototype.getVariables=function(e,t){return(0,en.pi)((0,en.pi)({},this.transform(e).defaultVars),t)},e.prototype.watchQuery=function(e){void 0===(e=(0,en.pi)((0,en.pi)({},e),{variables:this.getVariables(e.query,e.variables)})).notifyOnNetworkStatusChange&&(e.notifyOnNetworkStatusChange=!1);var t=new r8(this),n=new n3({queryManager:this,queryInfo:t,options:e});return this.queries.set(n.queryId,t),t.init({document:n.query,observableQuery:n,variables:n.variables}),n},e.prototype.query=function(e,t){var n=this;return void 0===t&&(t=this.generateQueryId()),__DEV__?(0,Q.kG)(e.query,"query option is required. You must specify your GraphQL document in the query option."):(0,Q.kG)(e.query,17),__DEV__?(0,Q.kG)("Document"===e.query.kind,'You must wrap the query string in a "gql" tag.'):(0,Q.kG)("Document"===e.query.kind,18),__DEV__?(0,Q.kG)(!e.returnPartialData,"returnPartialData option only supported on watchQuery."):(0,Q.kG)(!e.returnPartialData,19),__DEV__?(0,Q.kG)(!e.pollInterval,"pollInterval option only supported on watchQuery."):(0,Q.kG)(!e.pollInterval,20),this.fetchQuery(t,e).finally(function(){return n.stopQuery(t)})},e.prototype.generateQueryId=function(){return String(this.queryIdCounter++)},e.prototype.generateRequestId=function(){return this.requestIdCounter++},e.prototype.generateMutationId=function(){return String(this.mutationIdCounter++)},e.prototype.stopQueryInStore=function(e){this.stopQueryInStoreNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryInStoreNoBroadcast=function(e){var t=this.queries.get(e);t&&t.stop()},e.prototype.clearStore=function(e){return void 0===e&&(e={discardWatches:!0}),this.cancelPendingFetches(__DEV__?new Q.ej("Store reset while query was in flight (not completed in link chain)"):new Q.ej(21)),this.queries.forEach(function(e){e.observableQuery?e.networkStatus=nZ.I.loading:e.stop()}),this.mutationStore&&(this.mutationStore=Object.create(null)),this.cache.reset(e)},e.prototype.getObservableQueries=function(e){var t=this;void 0===e&&(e="active");var n=new Map,r=new Map,i=new Set;return Array.isArray(e)&&e.forEach(function(e){"string"==typeof e?r.set(e,!1):eN(e)?r.set(t.transform(e).document,!1):(0,eO.s)(e)&&e.query&&i.add(e)}),this.queries.forEach(function(t,i){var a=t.observableQuery,o=t.document;if(a){if("all"===e){n.set(i,a);return}var s=a.queryName;if("standby"===a.options.fetchPolicy||"active"===e&&!a.hasObservers())return;("active"===e||s&&r.has(s)||o&&r.has(o))&&(n.set(i,a),s&&r.set(s,!0),o&&r.set(o,!0))}}),i.size&&i.forEach(function(e){var r=nG("legacyOneTimeQuery"),i=t.getQuery(r).init({document:e.query,variables:e.variables}),a=new n3({queryManager:t,queryInfo:i,options:(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"network-only"})});(0,Q.kG)(a.queryId===r),i.setObservableQuery(a),n.set(r,a)}),__DEV__&&r.size&&r.forEach(function(e,t){!e&&__DEV__&&Q.kG.warn("Unknown query ".concat("string"==typeof t?"named ":"").concat(JSON.stringify(t,null,2)," requested in refetchQueries options.include array"))}),n},e.prototype.reFetchObservableQueries=function(e){var t=this;void 0===e&&(e=!1);var n=[];return this.getObservableQueries(e?"all":"active").forEach(function(r,i){var a=r.options.fetchPolicy;r.resetLastResults(),(e||"standby"!==a&&"cache-only"!==a)&&n.push(r.refetch()),t.getQuery(i).setDiff(null)}),this.broadcastQueries(),Promise.all(n)},e.prototype.setObservableQuery=function(e){this.getQuery(e.queryId).setObservableQuery(e)},e.prototype.startGraphQLSubscription=function(e){var t=this,n=e.query,r=e.fetchPolicy,i=e.errorPolicy,a=e.variables,o=e.context,s=void 0===o?{}:o;n=this.transform(n).document,a=this.getVariables(n,a);var u=function(e){return t.getObservableFromLink(n,s,e).map(function(a){"no-cache"!==r&&(r7(a,i)&&t.cache.write({query:n,result:a.data,dataId:"ROOT_SUBSCRIPTION",variables:e}),t.broadcastQueries());var o=nO(a),s=(0,tN.ls)(a);if(o||s){var u={};throw o&&(u.graphQLErrors=a.errors),s&&(u.protocolErrors=a.extensions[tN.YG]),new tN.cA(u)}return a})};if(this.transform(n).hasClientExports){var c=this.localState.addExportedVariables(n,a,s).then(u);return new eT(function(e){var t=null;return c.then(function(n){return t=n.subscribe(e)},e.error),function(){return t&&t.unsubscribe()}})}return u(a)},e.prototype.stopQuery=function(e){this.stopQueryNoBroadcast(e),this.broadcastQueries()},e.prototype.stopQueryNoBroadcast=function(e){this.stopQueryInStoreNoBroadcast(e),this.removeQuery(e)},e.prototype.removeQuery=function(e){this.fetchCancelFns.delete(e),this.queries.has(e)&&(this.getQuery(e).stop(),this.queries.delete(e))},e.prototype.broadcastQueries=function(){this.onBroadcast&&this.onBroadcast(),this.queries.forEach(function(e){return e.notify()})},e.prototype.getLocalState=function(){return this.localState},e.prototype.getObservableFromLink=function(e,t,n,r){var i,a,o=this;void 0===r&&(r=null!==(i=null==t?void 0:t.queryDeduplication)&&void 0!==i?i:this.queryDeduplication);var s=this.transform(e).serverQuery;if(s){var u=this,c=u.inFlightLinkObservables,l=u.link,f={query:s,variables:n,operationName:e3(s)||void 0,context:this.prepareContext((0,en.pi)((0,en.pi)({},t),{forceFetch:!r}))};if(t=f.context,r){var d=c.get(s)||new Map;c.set(s,d);var h=nx(n);if(!(a=d.get(h))){var p=new nq([np(l,f)]);d.set(h,a=p),p.beforeNext(function(){d.delete(h)&&d.size<1&&c.delete(s)})}}else a=new nq([np(l,f)])}else a=new nq([eT.of({data:{}})]),t=this.prepareContext(t);var b=this.transform(e).clientQuery;return b&&(a=nM(a,function(e){return o.localState.runResolvers({document:b,remoteResult:e,context:t,variables:n})})),a},e.prototype.getResultsFromLink=function(e,t,n){var r=e.lastRequestId=this.generateRequestId(),i=this.cache.transformForLink(this.transform(e.document).document);return nM(this.getObservableFromLink(i,n.context,n.variables),function(a){var o=nA(a),s=o.length>0;if(r>=e.lastRequestId){if(s&&"none"===n.errorPolicy)throw e.markError(new tN.cA({graphQLErrors:o}));e.markResult(a,i,n,t),e.markReady()}var u={data:a.data,loading:!1,networkStatus:nZ.I.ready};return s&&"ignore"!==n.errorPolicy&&(u.errors=o,u.networkStatus=nZ.I.error),u},function(t){var n=(0,tN.MS)(t)?t:new tN.cA({networkError:t});throw r>=e.lastRequestId&&e.markError(n),n})},e.prototype.fetchQueryObservable=function(e,t,n){return this.fetchConcastWithInfo(e,t,n).concast},e.prototype.fetchConcastWithInfo=function(e,t,n){var r,i,a=this;void 0===n&&(n=nZ.I.loading);var o=this.transform(t.query).document,s=this.getVariables(o,t.variables),u=this.getQuery(e),c=this.defaultOptions.watchQuery,l=t.fetchPolicy,f=void 0===l?c&&c.fetchPolicy||"cache-first":l,d=t.errorPolicy,h=void 0===d?c&&c.errorPolicy||"none":d,p=t.returnPartialData,b=void 0!==p&&p,m=t.notifyOnNetworkStatusChange,g=void 0!==m&&m,v=t.context,y=void 0===v?{}:v,w=Object.assign({},t,{query:o,variables:s,fetchPolicy:f,errorPolicy:h,returnPartialData:b,notifyOnNetworkStatusChange:g,context:y}),_=function(e){w.variables=e;var r=a.fetchQueryByPolicy(u,w,n);return"standby"!==w.fetchPolicy&&r.sources.length>0&&u.observableQuery&&u.observableQuery.applyNextFetchPolicy("after-fetch",t),r},E=function(){return a.fetchCancelFns.delete(e)};if(this.fetchCancelFns.set(e,function(e){E(),setTimeout(function(){return r.cancel(e)})}),this.transform(w.query).hasClientExports)r=new nq(this.localState.addExportedVariables(w.query,w.variables,w.context).then(_).then(function(e){return e.sources})),i=!0;else{var S=_(w.variables);i=S.fromLink,r=new nq(S.sources)}return r.promise.then(E,E),{concast:r,fromLink:i}},e.prototype.refetchQueries=function(e){var t=this,n=e.updateCache,r=e.include,i=e.optimistic,a=void 0!==i&&i,o=e.removeOptimistic,s=void 0===o?a?nG("refetchQueries"):void 0:o,u=e.onQueryUpdated,c=new Map;r&&this.getObservableQueries(r).forEach(function(e,n){c.set(n,{oq:e,lastDiff:t.getQuery(n).getDiff()})});var l=new Map;return n&&this.cache.batch({update:n,optimistic:a&&s||!1,removeOptimistic:s,onWatchUpdated:function(e,t,n){var r=e.watcher instanceof r8&&e.watcher.observableQuery;if(r){if(u){c.delete(r.queryId);var i=u(r,t,n);return!0===i&&(i=r.refetch()),!1!==i&&l.set(r,i),i}null!==u&&c.set(r.queryId,{oq:r,lastDiff:n,diff:t})}}}),c.size&&c.forEach(function(e,n){var r,i=e.oq,a=e.lastDiff,o=e.diff;if(u){if(!o){var s=i.queryInfo;s.reset(),o=s.getDiff()}r=u(i,o,a)}u&&!0!==r||(r=i.refetch()),!1!==r&&l.set(i,r),n.indexOf("legacyOneTimeQuery")>=0&&t.stopQueryNoBroadcast(n)}),s&&this.cache.removeOptimistic(s),l},e.prototype.fetchQueryByPolicy=function(e,t,n){var r=this,i=t.query,a=t.variables,o=t.fetchPolicy,s=t.refetchWritePolicy,u=t.errorPolicy,c=t.returnPartialData,l=t.context,f=t.notifyOnNetworkStatusChange,d=e.networkStatus;e.init({document:this.transform(i).document,variables:a,networkStatus:n});var h=function(){return e.getDiff(a)},p=function(t,n){void 0===n&&(n=e.networkStatus||nZ.I.loading);var o=t.result;!__DEV__||c||(0,nm.D)(o,{})||n6(t.missing);var s=function(e){return eT.of((0,en.pi)({data:e,loading:(0,nZ.O)(n),networkStatus:n},t.complete?null:{partial:!0}))};return o&&r.transform(i).hasForcedResolvers?r.localState.runResolvers({document:i,remoteResult:{data:o},context:l,variables:a,onlyRunForcedResolvers:!0}).then(function(e){return s(e.data||void 0)}):"none"===u&&n===nZ.I.refetch&&Array.isArray(t.missing)?s(void 0):s(o)},b="no-cache"===o?0:n===nZ.I.refetch&&"merge"!==s?1:2,m=function(){return r.getResultsFromLink(e,b,{variables:a,context:l,fetchPolicy:o,errorPolicy:u})},g=f&&"number"==typeof d&&d!==n&&(0,nZ.O)(n);switch(o){default:case"cache-first":var v=h();if(v.complete)return{fromLink:!1,sources:[p(v,e.markReady())]};if(c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-and-network":var v=h();if(v.complete||c||g)return{fromLink:!0,sources:[p(v),m()]};return{fromLink:!0,sources:[m()]};case"cache-only":return{fromLink:!1,sources:[p(h(),e.markReady())]};case"network-only":if(g)return{fromLink:!0,sources:[p(h()),m()]};return{fromLink:!0,sources:[m()]};case"no-cache":if(g)return{fromLink:!0,sources:[p(e.getDiff()),m(),]};return{fromLink:!0,sources:[m()]};case"standby":return{fromLink:!1,sources:[]}}},e.prototype.getQuery=function(e){return e&&!this.queries.has(e)&&this.queries.set(e,new r8(this,e)),this.queries.get(e)},e.prototype.prepareContext=function(e){void 0===e&&(e={});var t=this.localState.prepareContext(e);return(0,en.pi)((0,en.pi)({},t),{clientAwareness:this.clientAwareness})},e}(),ir=__webpack_require__(14012),ii=!1,ia=function(){function e(e){var t=this;this.resetStoreCallbacks=[],this.clearStoreCallbacks=[];var n=e.uri,r=e.credentials,i=e.headers,a=e.cache,o=e.ssrMode,s=void 0!==o&&o,u=e.ssrForceFetchDelay,c=void 0===u?0:u,l=e.connectToDevTools,f=void 0===l?"object"==typeof window&&!window.__APOLLO_CLIENT__&&__DEV__:l,d=e.queryDeduplication,h=void 0===d||d,p=e.defaultOptions,b=e.assumeImmutableResults,m=void 0!==b&&b,g=e.resolvers,v=e.typeDefs,y=e.fragmentMatcher,w=e.name,_=e.version,E=e.link;if(E||(E=n?new nh({uri:n,credentials:r,headers:i}):ta.empty()),!a)throw __DEV__?new Q.ej("To initialize Apollo Client, you must specify a 'cache' property in the options object. \nFor more information, please visit: https://go.apollo.dev/c/docs"):new Q.ej(9);if(this.link=E,this.cache=a,this.disableNetworkFetches=s||c>0,this.queryDeduplication=h,this.defaultOptions=p||Object.create(null),this.typeDefs=v,c&&setTimeout(function(){return t.disableNetworkFetches=!1},c),this.watchQuery=this.watchQuery.bind(this),this.query=this.query.bind(this),this.mutate=this.mutate.bind(this),this.resetStore=this.resetStore.bind(this),this.reFetchObservableQueries=this.reFetchObservableQueries.bind(this),f&&"object"==typeof window&&(window.__APOLLO_CLIENT__=this),!ii&&f&&__DEV__&&(ii=!0,"undefined"!=typeof window&&window.document&&window.top===window.self&&!window.__APOLLO_DEVTOOLS_GLOBAL_HOOK__)){var S=window.navigator,k=S&&S.userAgent,x=void 0;"string"==typeof k&&(k.indexOf("Chrome/")>-1?x="https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm":k.indexOf("Firefox/")>-1&&(x="https://addons.mozilla.org/en-US/firefox/addon/apollo-developer-tools/")),x&&__DEV__&&Q.kG.log("Download the Apollo DevTools for a better development experience: "+x)}this.version=nb,this.localState=new r4({cache:a,client:this,resolvers:g,fragmentMatcher:y}),this.queryManager=new it({cache:this.cache,link:this.link,defaultOptions:this.defaultOptions,queryDeduplication:h,ssrMode:s,clientAwareness:{name:w,version:_},localState:this.localState,assumeImmutableResults:m,onBroadcast:f?function(){t.devToolsHookCb&&t.devToolsHookCb({action:{},state:{queries:t.queryManager.getQueryStore(),mutations:t.queryManager.mutationStore||{}},dataWithOptimisticResults:t.cache.extract(!0)})}:void 0})}return e.prototype.stop=function(){this.queryManager.stop()},e.prototype.watchQuery=function(e){return this.defaultOptions.watchQuery&&(e=(0,ir.J)(this.defaultOptions.watchQuery,e)),this.disableNetworkFetches&&("network-only"===e.fetchPolicy||"cache-and-network"===e.fetchPolicy)&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.watchQuery(e)},e.prototype.query=function(e){return this.defaultOptions.query&&(e=(0,ir.J)(this.defaultOptions.query,e)),__DEV__?(0,Q.kG)("cache-and-network"!==e.fetchPolicy,"The cache-and-network fetchPolicy does not work with client.query, because client.query can only return a single result. Please use client.watchQuery to receive multiple results from the cache and the network, or consider using a different fetchPolicy, such as cache-first or network-only."):(0,Q.kG)("cache-and-network"!==e.fetchPolicy,10),this.disableNetworkFetches&&"network-only"===e.fetchPolicy&&(e=(0,en.pi)((0,en.pi)({},e),{fetchPolicy:"cache-first"})),this.queryManager.query(e)},e.prototype.mutate=function(e){return this.defaultOptions.mutate&&(e=(0,ir.J)(this.defaultOptions.mutate,e)),this.queryManager.mutate(e)},e.prototype.subscribe=function(e){return this.queryManager.startGraphQLSubscription(e)},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!1),this.cache.readQuery(e,t)},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!1),this.cache.readFragment(e,t)},e.prototype.writeQuery=function(e){var t=this.cache.writeQuery(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.writeFragment=function(e){var t=this.cache.writeFragment(e);return!1!==e.broadcast&&this.queryManager.broadcastQueries(),t},e.prototype.__actionHookForDevTools=function(e){this.devToolsHookCb=e},e.prototype.__requestRaw=function(e){return np(this.link,e)},e.prototype.resetStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!1})}).then(function(){return Promise.all(e.resetStoreCallbacks.map(function(e){return e()}))}).then(function(){return e.reFetchObservableQueries()})},e.prototype.clearStore=function(){var e=this;return Promise.resolve().then(function(){return e.queryManager.clearStore({discardWatches:!0})}).then(function(){return Promise.all(e.clearStoreCallbacks.map(function(e){return e()}))})},e.prototype.onResetStore=function(e){var t=this;return this.resetStoreCallbacks.push(e),function(){t.resetStoreCallbacks=t.resetStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.onClearStore=function(e){var t=this;return this.clearStoreCallbacks.push(e),function(){t.clearStoreCallbacks=t.clearStoreCallbacks.filter(function(t){return t!==e})}},e.prototype.reFetchObservableQueries=function(e){return this.queryManager.reFetchObservableQueries(e)},e.prototype.refetchQueries=function(e){var t=this.queryManager.refetchQueries(e),n=[],r=[];t.forEach(function(e,t){n.push(t),r.push(e)});var i=Promise.all(r);return i.queries=n,i.results=r,i.catch(function(e){__DEV__&&Q.kG.debug("In client.refetchQueries, Promise.all promise rejected with error ".concat(e))}),i},e.prototype.getObservableQueries=function(e){return void 0===e&&(e="active"),this.queryManager.getObservableQueries(e)},e.prototype.extract=function(e){return this.cache.extract(e)},e.prototype.restore=function(e){return this.cache.restore(e)},e.prototype.addResolvers=function(e){this.localState.addResolvers(e)},e.prototype.setResolvers=function(e){this.localState.setResolvers(e)},e.prototype.getResolvers=function(){return this.localState.getResolvers()},e.prototype.setLocalStateFragmentMatcher=function(e){this.localState.setFragmentMatcher(e)},e.prototype.setLink=function(e){this.link=this.queryManager.link=e},e}(),io=function(){function e(){this.getFragmentDoc=rZ(eA)}return e.prototype.batch=function(e){var t,n=this,r="string"==typeof e.optimistic?e.optimistic:!1===e.optimistic?null:void 0;return this.performTransaction(function(){return t=e.update(n)},r),t},e.prototype.recordOptimisticTransaction=function(e,t){this.performTransaction(e,t)},e.prototype.transformDocument=function(e){return e},e.prototype.transformForLink=function(e){return e},e.prototype.identify=function(e){},e.prototype.gc=function(){return[]},e.prototype.modify=function(e){return!1},e.prototype.readQuery=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{rootId:e.id||"ROOT_QUERY",optimistic:t}))},e.prototype.readFragment=function(e,t){return void 0===t&&(t=!!e.optimistic),this.read((0,en.pi)((0,en.pi)({},e),{query:this.getFragmentDoc(e.fragment,e.fragmentName),rootId:e.id,optimistic:t}))},e.prototype.writeQuery=function(e){var t=e.id,n=e.data,r=(0,en._T)(e,["id","data"]);return this.write(Object.assign(r,{dataId:t||"ROOT_QUERY",result:n}))},e.prototype.writeFragment=function(e){var t=e.id,n=e.data,r=e.fragment,i=e.fragmentName,a=(0,en._T)(e,["id","data","fragment","fragmentName"]);return this.write(Object.assign(a,{query:this.getFragmentDoc(r,i),dataId:t,result:n}))},e.prototype.updateQuery=function(e,t){return this.batch({update:function(n){var r=n.readQuery(e),i=t(r);return null==i?r:(n.writeQuery((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e.prototype.updateFragment=function(e,t){return this.batch({update:function(n){var r=n.readFragment(e),i=t(r);return null==i?r:(n.writeFragment((0,en.pi)((0,en.pi)({},e),{data:i})),i)}})},e}(),is=function(e){function t(n,r,i,a){var o,s=e.call(this,n)||this;if(s.message=n,s.path=r,s.query=i,s.variables=a,Array.isArray(s.path)){s.missing=s.message;for(var u=s.path.length-1;u>=0;--u)s.missing=((o={})[s.path[u]]=s.missing,o)}else s.missing=s.path;return s.__proto__=t.prototype,s}return(0,en.ZT)(t,e),t}(Error),iu=__webpack_require__(10542),ic=Object.prototype.hasOwnProperty;function il(e){return null==e}function id(e,t){var n=e.__typename,r=e.id,i=e._id;if("string"==typeof n&&(t&&(t.keyObject=il(r)?il(i)?void 0:{_id:i}:{id:r}),il(r)&&!il(i)&&(r=i),!il(r)))return"".concat(n,":").concat("number"==typeof r||"string"==typeof r?r:JSON.stringify(r))}var ih={dataIdFromObject:id,addTypename:!0,resultCaching:!0,canonizeResults:!1};function ip(e){return(0,n1.o)(ih,e)}function ib(e){var t=e.canonizeResults;return void 0===t?ih.canonizeResults:t}function im(e,t){return eD(t)?e.get(t.__ref,"__typename"):t&&t.__typename}var ig=/^[_a-z][_0-9a-z]*/i;function iv(e){var t=e.match(ig);return t?t[0]:e}function iy(e,t,n){return!!(0,eO.s)(t)&&((0,tP.k)(t)?t.every(function(t){return iy(e,t,n)}):e.selections.every(function(e){if(eQ(e)&&td(e,n)){var r=eX(e);return ic.call(t,r)&&(!e.selectionSet||iy(e.selectionSet,t[r],n))}return!0}))}function iw(e){return(0,eO.s)(e)&&!eD(e)&&!(0,tP.k)(e)}function i_(){return new tB}function iE(e,t){var n=eL(e4(e));return{fragmentMap:n,lookupFragment:function(e){var r=n[e];return!r&&t&&(r=t.lookup(e)),r||null}}}var iS=Object.create(null),ik=function(){return iS},ix=Object.create(null),iT=function(){function e(e,t){var n=this;this.policies=e,this.group=t,this.data=Object.create(null),this.rootIds=Object.create(null),this.refs=Object.create(null),this.getFieldValue=function(e,t){return(0,iu.J)(eD(e)?n.get(e.__ref,t):e&&e[t])},this.canRead=function(e){return eD(e)?n.has(e.__ref):"object"==typeof e},this.toReference=function(e,t){if("string"==typeof e)return eI(e);if(eD(e))return e;var r=n.policies.identify(e)[0];if(r){var i=eI(r);return t&&n.merge(r,e),i}}}return e.prototype.toObject=function(){return(0,en.pi)({},this.data)},e.prototype.has=function(e){return void 0!==this.lookup(e,!0)},e.prototype.get=function(e,t){if(this.group.depend(e,t),ic.call(this.data,e)){var n=this.data[e];if(n&&ic.call(n,t))return n[t]}return"__typename"===t&&ic.call(this.policies.rootTypenamesById,e)?this.policies.rootTypenamesById[e]:this instanceof iL?this.parent.get(e,t):void 0},e.prototype.lookup=function(e,t){return(t&&this.group.depend(e,"__exists"),ic.call(this.data,e))?this.data[e]:this instanceof iL?this.parent.lookup(e,t):this.policies.rootTypenamesById[e]?Object.create(null):void 0},e.prototype.merge=function(e,t){var n,r=this;eD(e)&&(e=e.__ref),eD(t)&&(t=t.__ref);var i="string"==typeof e?this.lookup(n=e):e,a="string"==typeof t?this.lookup(n=t):t;if(a){__DEV__?(0,Q.kG)("string"==typeof n,"store.merge expects a string ID"):(0,Q.kG)("string"==typeof n,1);var o=new tB(iI).merge(i,a);if(this.data[n]=o,o!==i&&(delete this.refs[n],this.group.caching)){var s=Object.create(null);i||(s.__exists=1),Object.keys(a).forEach(function(e){if(!i||i[e]!==o[e]){s[e]=1;var t=iv(e);t===e||r.policies.hasKeyArgs(o.__typename,t)||(s[t]=1),void 0!==o[e]||r instanceof iL||delete o[e]}}),s.__typename&&!(i&&i.__typename)&&this.policies.rootTypenamesById[n]===o.__typename&&delete s.__typename,Object.keys(s).forEach(function(e){return r.group.dirty(n,e)})}}},e.prototype.modify=function(e,t){var n=this,r=this.lookup(e);if(r){var i=Object.create(null),a=!1,o=!0,s={DELETE:iS,INVALIDATE:ix,isReference:eD,toReference:this.toReference,canRead:this.canRead,readField:function(t,r){return n.policies.readField("string"==typeof t?{fieldName:t,from:r||eI(e)}:t,{store:n})}};if(Object.keys(r).forEach(function(u){var c=iv(u),l=r[u];if(void 0!==l){var f="function"==typeof t?t:t[u]||t[c];if(f){var d=f===ik?iS:f((0,iu.J)(l),(0,en.pi)((0,en.pi)({},s),{fieldName:c,storeFieldName:u,storage:n.getStorage(e,u)}));d===ix?n.group.dirty(e,u):(d===iS&&(d=void 0),d!==l&&(i[u]=d,a=!0,l=d))}void 0!==l&&(o=!1)}}),a)return this.merge(e,i),o&&(this instanceof iL?this.data[e]=void 0:delete this.data[e],this.group.dirty(e,"__exists")),!0}return!1},e.prototype.delete=function(e,t,n){var r,i=this.lookup(e);if(i){var a=this.getFieldValue(i,"__typename"),o=t&&n?this.policies.getStoreFieldName({typename:a,fieldName:t,args:n}):t;return this.modify(e,o?((r={})[o]=ik,r):ik)}return!1},e.prototype.evict=function(e,t){var n=!1;return e.id&&(ic.call(this.data,e.id)&&(n=this.delete(e.id,e.fieldName,e.args)),this instanceof iL&&this!==t&&(n=this.parent.evict(e,t)||n),(e.fieldName||n)&&this.group.dirty(e.id,e.fieldName||"__exists")),n},e.prototype.clear=function(){this.replace(null)},e.prototype.extract=function(){var e=this,t=this.toObject(),n=[];return this.getRootIdSet().forEach(function(t){ic.call(e.policies.rootTypenamesById,t)||n.push(t)}),n.length&&(t.__META={extraRootIds:n.sort()}),t},e.prototype.replace=function(e){var t=this;if(Object.keys(this.data).forEach(function(n){e&&ic.call(e,n)||t.delete(n)}),e){var n=e.__META,r=(0,en._T)(e,["__META"]);Object.keys(r).forEach(function(e){t.merge(e,r[e])}),n&&n.extraRootIds.forEach(this.retain,this)}},e.prototype.retain=function(e){return this.rootIds[e]=(this.rootIds[e]||0)+1},e.prototype.release=function(e){if(this.rootIds[e]>0){var t=--this.rootIds[e];return t||delete this.rootIds[e],t}return 0},e.prototype.getRootIdSet=function(e){return void 0===e&&(e=new Set),Object.keys(this.rootIds).forEach(e.add,e),this instanceof iL?this.parent.getRootIdSet(e):Object.keys(this.policies.rootTypenamesById).forEach(e.add,e),e},e.prototype.gc=function(){var e=this,t=this.getRootIdSet(),n=this.toObject();t.forEach(function(r){ic.call(n,r)&&(Object.keys(e.findChildRefIds(r)).forEach(t.add,t),delete n[r])});var r=Object.keys(n);if(r.length){for(var i=this;i instanceof iL;)i=i.parent;r.forEach(function(e){return i.delete(e)})}return r},e.prototype.findChildRefIds=function(e){if(!ic.call(this.refs,e)){var t=this.refs[e]=Object.create(null),n=this.data[e];if(!n)return t;var r=new Set([n]);r.forEach(function(e){eD(e)&&(t[e.__ref]=!0),(0,eO.s)(e)&&Object.keys(e).forEach(function(t){var n=e[t];(0,eO.s)(n)&&r.add(n)})})}return this.refs[e]},e.prototype.makeCacheKey=function(){return this.group.keyMaker.lookupArray(arguments)},e}(),iM=function(){function e(e,t){void 0===t&&(t=null),this.caching=e,this.parent=t,this.d=null,this.resetCaching()}return e.prototype.resetCaching=function(){this.d=this.caching?rW():null,this.keyMaker=new n_(t_.mr)},e.prototype.depend=function(e,t){if(this.d){this.d(iO(e,t));var n=iv(t);n!==t&&this.d(iO(e,n)),this.parent&&this.parent.depend(e,t)}},e.prototype.dirty=function(e,t){this.d&&this.d.dirty(iO(e,t),"__exists"===t?"forget":"setDirty")},e}();function iO(e,t){return t+"#"+e}function iA(e,t){iD(e)&&e.group.depend(t,"__exists")}!function(e){var t=function(e){function t(t){var n=t.policies,r=t.resultCaching,i=void 0===r||r,a=t.seed,o=e.call(this,n,new iM(i))||this;return o.stump=new iC(o),o.storageTrie=new n_(t_.mr),a&&o.replace(a),o}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,t){return this.stump.addLayer(e,t)},t.prototype.removeLayer=function(){return this},t.prototype.getStorage=function(){return this.storageTrie.lookupArray(arguments)},t}(e);e.Root=t}(iT||(iT={}));var iL=function(e){function t(t,n,r,i){var a=e.call(this,n.policies,i)||this;return a.id=t,a.parent=n,a.replay=r,a.group=i,r(a),a}return(0,en.ZT)(t,e),t.prototype.addLayer=function(e,n){return new t(e,this,n,this.group)},t.prototype.removeLayer=function(e){var t=this,n=this.parent.removeLayer(e);return e===this.id?(this.group.caching&&Object.keys(this.data).forEach(function(e){var r=t.data[e],i=n.lookup(e);i?r?r!==i&&Object.keys(r).forEach(function(n){(0,nm.D)(r[n],i[n])||t.group.dirty(e,n)}):(t.group.dirty(e,"__exists"),Object.keys(i).forEach(function(n){t.group.dirty(e,n)})):t.delete(e)}),n):n===this.parent?this:n.addLayer(this.id,this.replay)},t.prototype.toObject=function(){return(0,en.pi)((0,en.pi)({},this.parent.toObject()),this.data)},t.prototype.findChildRefIds=function(t){var n=this.parent.findChildRefIds(t);return ic.call(this.data,t)?(0,en.pi)((0,en.pi)({},n),e.prototype.findChildRefIds.call(this,t)):n},t.prototype.getStorage=function(){for(var e=this.parent;e.parent;)e=e.parent;return e.getStorage.apply(e,arguments)},t}(iT),iC=function(e){function t(t){return e.call(this,"EntityStore.Stump",t,function(){},new iM(t.group.caching,t.group))||this}return(0,en.ZT)(t,e),t.prototype.removeLayer=function(){return this},t.prototype.merge=function(){return this.parent.merge.apply(this.parent,arguments)},t}(iL);function iI(e,t,n){var r=e[n],i=t[n];return(0,nm.D)(r,i)?r:i}function iD(e){return!!(e instanceof iT&&e.group.caching)}function iN(e){return[e.selectionSet,e.objectOrReference,e.context,e.context.canonizeResults,]}var iP=function(){function e(e){var t=this;this.knownResults=new(t_.mr?WeakMap:Map),this.config=(0,n1.o)(e,{addTypename:!1!==e.addTypename,canonizeResults:ib(e)}),this.canon=e.canon||new nk,this.executeSelectionSet=rZ(function(e){var n,r=e.context.canonizeResults,i=iN(e);i[3]=!r;var a=(n=t.executeSelectionSet).peek.apply(n,i);return a?r?(0,en.pi)((0,en.pi)({},a),{result:t.canon.admit(a.result)}):a:(iA(e.context.store,e.enclosingRef.__ref),t.execSelectionSetImpl(e))},{max:this.config.resultCacheMaxSize,keyArgs:iN,makeCacheKey:function(e,t,n,r){if(iD(n.store))return n.store.makeCacheKey(e,eD(t)?t.__ref:t,n.varString,r)}}),this.executeSubSelectedArray=rZ(function(e){return iA(e.context.store,e.enclosingRef.__ref),t.execSubSelectedArrayImpl(e)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var t=e.field,n=e.array,r=e.context;if(iD(r.store))return r.store.makeCacheKey(t,n,r.varString)}})}return e.prototype.resetCanon=function(){this.canon=new nk},e.prototype.diffQueryAgainstStore=function(e){var t,n=e.store,r=e.query,i=e.rootId,a=void 0===i?"ROOT_QUERY":i,o=e.variables,s=e.returnPartialData,u=void 0===s||s,c=e.canonizeResults,l=void 0===c?this.config.canonizeResults:c,f=this.config.cache.policies;o=(0,en.pi)((0,en.pi)({},e8(e5(r))),o);var d=eI(a),h=this.executeSelectionSet({selectionSet:e9(r).selectionSet,objectOrReference:d,enclosingRef:d,context:(0,en.pi)({store:n,query:r,policies:f,variables:o,varString:nx(o),canonizeResults:l},iE(r,this.config.fragments))});if(h.missing&&(t=[new is(iR(h.missing),h.missing,r,o)],!u))throw t[0];return{result:h.result,complete:!t,missing:t}},e.prototype.isFresh=function(e,t,n,r){if(iD(r.store)&&this.knownResults.get(e)===n){var i=this.executeSelectionSet.peek(n,t,r,this.canon.isKnown(e));if(i&&e===i.result)return!0}return!1},e.prototype.execSelectionSetImpl=function(e){var t,n=this,r=e.selectionSet,i=e.objectOrReference,a=e.enclosingRef,o=e.context;if(eD(i)&&!o.policies.rootTypenamesById[i.__ref]&&!o.store.has(i.__ref))return{result:this.canon.empty,missing:"Dangling reference to missing ".concat(i.__ref," object")};var s=o.variables,u=o.policies,c=o.store.getFieldValue(i,"__typename"),l=[],f=new tB;function d(e,n){var r;return e.missing&&(t=f.merge(t,((r={})[n]=e.missing,r))),e.result}this.config.addTypename&&"string"==typeof c&&!u.rootIdsByTypename[c]&&l.push({__typename:c});var h=new Set(r.selections);h.forEach(function(e){var r,p;if(td(e,s)){if(eQ(e)){var b=u.readField({fieldName:e.name.value,field:e,variables:o.variables,from:i},o),m=eX(e);void 0===b?nj.added(e)||(t=f.merge(t,((r={})[m]="Can't find field '".concat(e.name.value,"' on ").concat(eD(i)?i.__ref+" object":"object "+JSON.stringify(i,null,2)),r))):(0,tP.k)(b)?b=d(n.executeSubSelectedArray({field:e,array:b,enclosingRef:a,context:o}),m):e.selectionSet?null!=b&&(b=d(n.executeSelectionSet({selectionSet:e.selectionSet,objectOrReference:b,enclosingRef:eD(b)?b:a,context:o}),m)):o.canonizeResults&&(b=n.canon.pass(b)),void 0!==b&&l.push(((p={})[m]=b,p))}else{var g=eC(e,o.lookupFragment);if(!g&&e.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(e.name.value)):new Q.ej(5);g&&u.fragmentMatches(g,c)&&g.selectionSet.selections.forEach(h.add,h)}}});var p={result:tF(l),missing:t},b=o.canonizeResults?this.canon.admit(p):(0,iu.J)(p);return b.result&&this.knownResults.set(b.result,r),b},e.prototype.execSubSelectedArrayImpl=function(e){var t,n=this,r=e.field,i=e.array,a=e.enclosingRef,o=e.context,s=new tB;function u(e,n){var r;return e.missing&&(t=s.merge(t,((r={})[n]=e.missing,r))),e.result}return r.selectionSet&&(i=i.filter(o.store.canRead)),i=i.map(function(e,t){return null===e?null:(0,tP.k)(e)?u(n.executeSubSelectedArray({field:r,array:e,enclosingRef:a,context:o}),t):r.selectionSet?u(n.executeSelectionSet({selectionSet:r.selectionSet,objectOrReference:e,enclosingRef:eD(e)?e:a,context:o}),t):(__DEV__&&ij(o.store,r,e),e)}),{result:o.canonizeResults?this.canon.admit(i):i,missing:t}},e}();function iR(e){try{JSON.stringify(e,function(e,t){if("string"==typeof t)throw t;return t})}catch(t){return t}}function ij(e,t,n){if(!t.selectionSet){var r=new Set([n]);r.forEach(function(n){(0,eO.s)(n)&&(__DEV__?(0,Q.kG)(!eD(n),"Missing selection set for object of type ".concat(im(e,n)," returned for query field ").concat(t.name.value)):(0,Q.kG)(!eD(n),6),Object.values(n).forEach(r.add,r))})}}function iF(e){var t=nG("stringifyForDisplay");return JSON.stringify(e,function(e,n){return void 0===n?t:n}).split(JSON.stringify(t)).join("")}var iY=Object.create(null);function iB(e){var t=JSON.stringify(e);return iY[t]||(iY[t]=Object.create(null))}function iU(e){var t=iB(e);return t.keyFieldsFn||(t.keyFieldsFn=function(t,n){var r=function(e,t){return n.readField(t,e)},i=n.keyObject=i$(e,function(e){var i=iW(n.storeObject,e,r);return void 0===i&&t!==n.storeObject&&ic.call(t,e[0])&&(i=iW(t,e,iG)),__DEV__?(0,Q.kG)(void 0!==i,"Missing field '".concat(e.join("."),"' while extracting keyFields from ").concat(JSON.stringify(t))):(0,Q.kG)(void 0!==i,2),i});return"".concat(n.typename,":").concat(JSON.stringify(i))})}function iH(e){var t=iB(e);return t.keyArgsFn||(t.keyArgsFn=function(t,n){var r=n.field,i=n.variables,a=n.fieldName,o=JSON.stringify(i$(e,function(e){var n=e[0],a=n.charAt(0);if("@"===a){if(r&&(0,tP.O)(r.directives)){var o=n.slice(1),s=r.directives.find(function(e){return e.name.value===o}),u=s&&eZ(s,i);return u&&iW(u,e.slice(1))}return}if("$"===a){var c=n.slice(1);if(i&&ic.call(i,c)){var l=e.slice(0);return l[0]=c,iW(i,l)}return}if(t)return iW(t,e)}));return(t||"{}"!==o)&&(a+=":"+o),a})}function i$(e,t){var n=new tB;return iz(e).reduce(function(e,r){var i,a=t(r);if(void 0!==a){for(var o=r.length-1;o>=0;--o)a=((i={})[r[o]]=a,i);e=n.merge(e,a)}return e},Object.create(null))}function iz(e){var t=iB(e);if(!t.paths){var n=t.paths=[],r=[];e.forEach(function(t,i){(0,tP.k)(t)?(iz(t).forEach(function(e){return n.push(r.concat(e))}),r.length=0):(r.push(t),(0,tP.k)(e[i+1])||(n.push(r.slice(0)),r.length=0))})}return t.paths}function iG(e,t){return e[t]}function iW(e,t,n){return n=n||iG,iK(t.reduce(function e(t,r){return(0,tP.k)(t)?t.map(function(t){return e(t,r)}):t&&n(t,r)},e))}function iK(e){return(0,eO.s)(e)?(0,tP.k)(e)?e.map(iK):i$(Object.keys(e).sort(),function(t){return iW(e,t)}):e}function iV(e){return void 0!==e.args?e.args:e.field?eZ(e.field,e.variables):null}eK.setStringify(nx);var iq=function(){},iZ=function(e,t){return t.fieldName},iX=function(e,t,n){return(0,n.mergeObjects)(e,t)},iJ=function(e,t){return t},iQ=function(){function e(e){this.config=e,this.typePolicies=Object.create(null),this.toBeAdded=Object.create(null),this.supertypeMap=new Map,this.fuzzySubtypes=new Map,this.rootIdsByTypename=Object.create(null),this.rootTypenamesById=Object.create(null),this.usingPossibleTypes=!1,this.config=(0,en.pi)({dataIdFromObject:id},e),this.cache=this.config.cache,this.setRootTypename("Query"),this.setRootTypename("Mutation"),this.setRootTypename("Subscription"),e.possibleTypes&&this.addPossibleTypes(e.possibleTypes),e.typePolicies&&this.addTypePolicies(e.typePolicies)}return e.prototype.identify=function(e,t){var n,r,i=this,a=t&&(t.typename||(null===(n=t.storeObject)||void 0===n?void 0:n.__typename))||e.__typename;if(a===this.rootTypenamesById.ROOT_QUERY)return["ROOT_QUERY"];for(var o=t&&t.storeObject||e,s=(0,en.pi)((0,en.pi)({},t),{typename:a,storeObject:o,readField:t&&t.readField||function(){var e=i0(arguments,o);return i.readField(e,{store:i.cache.data,variables:e.variables})}}),u=a&&this.getTypePolicy(a),c=u&&u.keyFn||this.config.dataIdFromObject;c;){var l=c((0,en.pi)((0,en.pi)({},e),o),s);if((0,tP.k)(l))c=iU(l);else{r=l;break}}return r=r?String(r):void 0,s.keyObject?[r,s.keyObject]:[r]},e.prototype.addTypePolicies=function(e){var t=this;Object.keys(e).forEach(function(n){var r=e[n],i=r.queryType,a=r.mutationType,o=r.subscriptionType,s=(0,en._T)(r,["queryType","mutationType","subscriptionType"]);i&&t.setRootTypename("Query",n),a&&t.setRootTypename("Mutation",n),o&&t.setRootTypename("Subscription",n),ic.call(t.toBeAdded,n)?t.toBeAdded[n].push(s):t.toBeAdded[n]=[s]})},e.prototype.updateTypePolicy=function(e,t){var n=this,r=this.getTypePolicy(e),i=t.keyFields,a=t.fields;function o(e,t){e.merge="function"==typeof t?t:!0===t?iX:!1===t?iJ:e.merge}o(r,t.merge),r.keyFn=!1===i?iq:(0,tP.k)(i)?iU(i):"function"==typeof i?i:r.keyFn,a&&Object.keys(a).forEach(function(t){var r=n.getFieldPolicy(e,t,!0),i=a[t];if("function"==typeof i)r.read=i;else{var s=i.keyArgs,u=i.read,c=i.merge;r.keyFn=!1===s?iZ:(0,tP.k)(s)?iH(s):"function"==typeof s?s:r.keyFn,"function"==typeof u&&(r.read=u),o(r,c)}r.read&&r.merge&&(r.keyFn=r.keyFn||iZ)})},e.prototype.setRootTypename=function(e,t){void 0===t&&(t=e);var n="ROOT_"+e.toUpperCase(),r=this.rootTypenamesById[n];t!==r&&(__DEV__?(0,Q.kG)(!r||r===e,"Cannot change root ".concat(e," __typename more than once")):(0,Q.kG)(!r||r===e,3),r&&delete this.rootIdsByTypename[r],this.rootIdsByTypename[t]=n,this.rootTypenamesById[n]=t)},e.prototype.addPossibleTypes=function(e){var t=this;this.usingPossibleTypes=!0,Object.keys(e).forEach(function(n){t.getSupertypeSet(n,!0),e[n].forEach(function(e){t.getSupertypeSet(e,!0).add(n);var r=e.match(ig);r&&r[0]===e||t.fuzzySubtypes.set(e,RegExp(e))})})},e.prototype.getTypePolicy=function(e){var t=this;if(!ic.call(this.typePolicies,e)){var n=this.typePolicies[e]=Object.create(null);n.fields=Object.create(null);var r=this.supertypeMap.get(e);r&&r.size&&r.forEach(function(e){var r=t.getTypePolicy(e),i=r.fields;Object.assign(n,(0,en._T)(r,["fields"])),Object.assign(n.fields,i)})}var i=this.toBeAdded[e];return i&&i.length&&i.splice(0).forEach(function(n){t.updateTypePolicy(e,n)}),this.typePolicies[e]},e.prototype.getFieldPolicy=function(e,t,n){if(e){var r=this.getTypePolicy(e).fields;return r[t]||n&&(r[t]=Object.create(null))}},e.prototype.getSupertypeSet=function(e,t){var n=this.supertypeMap.get(e);return!n&&t&&this.supertypeMap.set(e,n=new Set),n},e.prototype.fragmentMatches=function(e,t,n,r){var i=this;if(!e.typeCondition)return!0;if(!t)return!1;var a=e.typeCondition.name.value;if(t===a)return!0;if(this.usingPossibleTypes&&this.supertypeMap.has(a))for(var o=this.getSupertypeSet(t,!0),s=[o],u=function(e){var t=i.getSupertypeSet(e,!1);t&&t.size&&0>s.indexOf(t)&&s.push(t)},c=!!(n&&this.fuzzySubtypes.size),l=!1,f=0;f1?a:t}:(r=(0,en.pi)({},i),ic.call(r,"from")||(r.from=t)),__DEV__&&void 0===r.from&&__DEV__&&Q.kG.warn("Undefined 'from' passed to readField with arguments ".concat(iF(Array.from(e)))),void 0===r.variables&&(r.variables=n),r}function i2(e){return function(t,n){if((0,tP.k)(t)||(0,tP.k)(n))throw __DEV__?new Q.ej("Cannot automatically merge arrays"):new Q.ej(4);if((0,eO.s)(t)&&(0,eO.s)(n)){var r=e.getFieldValue(t,"__typename"),i=e.getFieldValue(n,"__typename");if(r&&i&&r!==i)return n;if(eD(t)&&iw(n))return e.merge(t.__ref,n),t;if(iw(t)&&eD(n))return e.merge(t,n.__ref),n;if(iw(t)&&iw(n))return(0,en.pi)((0,en.pi)({},t),n)}return n}}function i3(e,t,n){var r="".concat(t).concat(n),i=e.flavors.get(r);return i||e.flavors.set(r,i=e.clientOnly===t&&e.deferred===n?e:(0,en.pi)((0,en.pi)({},e),{clientOnly:t,deferred:n})),i}var i4=function(){function e(e,t,n){this.cache=e,this.reader=t,this.fragments=n}return e.prototype.writeToStore=function(e,t){var n=this,r=t.query,i=t.result,a=t.dataId,o=t.variables,s=t.overwrite,u=e2(r),c=i_();o=(0,en.pi)((0,en.pi)({},e8(u)),o);var l=(0,en.pi)((0,en.pi)({store:e,written:Object.create(null),merge:function(e,t){return c.merge(e,t)},variables:o,varString:nx(o)},iE(r,this.fragments)),{overwrite:!!s,incomingById:new Map,clientOnly:!1,deferred:!1,flavors:new Map}),f=this.processSelectionSet({result:i||Object.create(null),dataId:a,selectionSet:u.selectionSet,mergeTree:{map:new Map},context:l});if(!eD(f))throw __DEV__?new Q.ej("Could not identify object ".concat(JSON.stringify(i))):new Q.ej(7);return l.incomingById.forEach(function(t,r){var i=t.storeObject,a=t.mergeTree,o=t.fieldNodeSet,s=eI(r);if(a&&a.map.size){var u=n.applyMerges(a,s,i,l);if(eD(u))return;i=u}if(__DEV__&&!l.overwrite){var c=Object.create(null);o.forEach(function(e){e.selectionSet&&(c[e.name.value]=!0)});var f=function(e){return!0===c[iv(e)]},d=function(e){var t=a&&a.map.get(e);return Boolean(t&&t.info&&t.info.merge)};Object.keys(i).forEach(function(e){f(e)&&!d(e)&&at(s,i,e,l.store)})}e.merge(r,i)}),e.retain(f.__ref),f},e.prototype.processSelectionSet=function(e){var t=this,n=e.dataId,r=e.result,i=e.selectionSet,a=e.context,o=e.mergeTree,s=this.cache.policies,u=Object.create(null),c=n&&s.rootTypenamesById[n]||eJ(r,i,a.fragmentMap)||n&&a.store.get(n,"__typename");"string"==typeof c&&(u.__typename=c);var l=function(){var e=i0(arguments,u,a.variables);if(eD(e.from)){var t=a.incomingById.get(e.from.__ref);if(t){var n=s.readField((0,en.pi)((0,en.pi)({},e),{from:t.storeObject}),a);if(void 0!==n)return n}}return s.readField(e,a)},f=new Set;this.flattenFields(i,r,a,c).forEach(function(e,n){var i,a=r[eX(n)];if(f.add(n),void 0!==a){var d=s.getStoreFieldName({typename:c,fieldName:n.name.value,field:n,variables:e.variables}),h=i6(o,d),p=t.processFieldValue(a,n,n.selectionSet?i3(e,!1,!1):e,h),b=void 0;n.selectionSet&&(eD(p)||iw(p))&&(b=l("__typename",p));var m=s.getMergeFunction(c,n.name.value,b);m?h.info={field:n,typename:c,merge:m}:i7(o,d),u=e.merge(u,((i={})[d]=p,i))}else __DEV__&&!e.clientOnly&&!e.deferred&&!nj.added(n)&&!s.getReadFunction(c,n.name.value)&&__DEV__&&Q.kG.error("Missing field '".concat(eX(n),"' while writing result ").concat(JSON.stringify(r,null,2)).substring(0,1e3))});try{var d=s.identify(r,{typename:c,selectionSet:i,fragmentMap:a.fragmentMap,storeObject:u,readField:l}),h=d[0],p=d[1];n=n||h,p&&(u=a.merge(u,p))}catch(b){if(!n)throw b}if("string"==typeof n){var m=eI(n),g=a.written[n]||(a.written[n]=[]);if(g.indexOf(i)>=0||(g.push(i),this.reader&&this.reader.isFresh(r,m,i,a)))return m;var v=a.incomingById.get(n);return v?(v.storeObject=a.merge(v.storeObject,u),v.mergeTree=i9(v.mergeTree,o),f.forEach(function(e){return v.fieldNodeSet.add(e)})):a.incomingById.set(n,{storeObject:u,mergeTree:i8(o)?void 0:o,fieldNodeSet:f}),m}return u},e.prototype.processFieldValue=function(e,t,n,r){var i=this;return t.selectionSet&&null!==e?(0,tP.k)(e)?e.map(function(e,a){var o=i.processFieldValue(e,t,n,i6(r,a));return i7(r,a),o}):this.processSelectionSet({result:e,selectionSet:t.selectionSet,context:n,mergeTree:r}):__DEV__?nJ(e):e},e.prototype.flattenFields=function(e,t,n,r){void 0===r&&(r=eJ(t,e,n.fragmentMap));var i=new Map,a=this.cache.policies,o=new n_(!1);return function e(s,u){var c=o.lookup(s,u.clientOnly,u.deferred);c.visited||(c.visited=!0,s.selections.forEach(function(o){if(td(o,n.variables)){var s=u.clientOnly,c=u.deferred;if(!(s&&c)&&(0,tP.O)(o.directives)&&o.directives.forEach(function(e){var t=e.name.value;if("client"===t&&(s=!0),"defer"===t){var r=eZ(e,n.variables);r&&!1===r.if||(c=!0)}}),eQ(o)){var l=i.get(o);l&&(s=s&&l.clientOnly,c=c&&l.deferred),i.set(o,i3(n,s,c))}else{var f=eC(o,n.lookupFragment);if(!f&&o.kind===nL.h.FRAGMENT_SPREAD)throw __DEV__?new Q.ej("No fragment named ".concat(o.name.value)):new Q.ej(8);f&&a.fragmentMatches(f,r,t,n.variables)&&e(f.selectionSet,i3(n,s,c))}}}))}(e,n),i},e.prototype.applyMerges=function(e,t,n,r,i){var a=this;if(e.map.size&&!eD(n)){var o,s,u=!(0,tP.k)(n)&&(eD(t)||iw(t))?t:void 0,c=n;u&&!i&&(i=[eD(u)?u.__ref:u]);var l=function(e,t){return(0,tP.k)(e)?"number"==typeof t?e[t]:void 0:r.store.getFieldValue(e,String(t))};e.map.forEach(function(e,t){var n=l(u,t),o=l(c,t);if(void 0!==o){i&&i.push(t);var f=a.applyMerges(e,n,o,r,i);f!==o&&(s=s||new Map).set(t,f),i&&(0,Q.kG)(i.pop()===t)}}),s&&(n=(0,tP.k)(c)?c.slice(0):(0,en.pi)({},c),s.forEach(function(e,t){n[t]=e}))}return e.info?this.cache.policies.runMergeFunction(t,n,e.info,r,i&&(o=r.store).getStorage.apply(o,i)):n},e}(),i5=[];function i6(e,t){var n=e.map;return n.has(t)||n.set(t,i5.pop()||{map:new Map}),n.get(t)}function i9(e,t){if(e===t||!t||i8(t))return e;if(!e||i8(e))return t;var n=e.info&&t.info?(0,en.pi)((0,en.pi)({},e.info),t.info):e.info||t.info,r=e.map.size&&t.map.size,i=r?new Map:e.map.size?e.map:t.map,a={info:n,map:i};if(r){var o=new Set(t.map.keys());e.map.forEach(function(e,n){a.map.set(n,i9(e,t.map.get(n))),o.delete(n)}),o.forEach(function(n){a.map.set(n,i9(t.map.get(n),e.map.get(n)))})}return a}function i8(e){return!e||!(e.info||e.map.size)}function i7(e,t){var n=e.map,r=n.get(t);r&&i8(r)&&(i5.push(r),n.delete(t))}var ae=new Set;function at(e,t,n,r){var i=function(e){var t=r.getFieldValue(e,n);return"object"==typeof t&&t},a=i(e);if(a){var o=i(t);if(!(!o||eD(a)||(0,nm.D)(a,o)||Object.keys(a).every(function(e){return void 0!==r.getFieldValue(o,e)}))){var s=r.getFieldValue(e,"__typename")||r.getFieldValue(t,"__typename"),u=iv(n),c="".concat(s,".").concat(u);if(!ae.has(c)){ae.add(c);var l=[];(0,tP.k)(a)||(0,tP.k)(o)||[a,o].forEach(function(e){var t=r.getFieldValue(e,"__typename");"string"!=typeof t||l.includes(t)||l.push(t)}),__DEV__&&Q.kG.warn("Cache data may be lost when replacing the ".concat(u," field of a ").concat(s," object.\n\nThis could cause additional (usually avoidable) network requests to fetch data that were otherwise cached.\n\nTo address this problem (which is not a bug in Apollo Client), ").concat(l.length?"either ensure all objects of type "+l.join(" and ")+" have an ID or a custom merge function, or ":"","define a custom merge function for the ").concat(c," field, so InMemoryCache can safely merge these objects:\n\n existing: ").concat(JSON.stringify(a).slice(0,1e3),"\n incoming: ").concat(JSON.stringify(o).slice(0,1e3),"\n\nFor more information about these options, please refer to the documentation:\n\n * Ensuring entity objects have IDs: https://go.apollo.dev/c/generating-unique-identifiers\n * Defining custom merge functions: https://go.apollo.dev/c/merging-non-normalized-objects\n"))}}}}var an=function(e){function t(t){void 0===t&&(t={});var n=e.call(this)||this;return n.watches=new Set,n.typenameDocumentCache=new Map,n.makeVar=r2,n.txCount=0,n.config=ip(t),n.addTypename=!!n.config.addTypename,n.policies=new iQ({cache:n,dataIdFromObject:n.config.dataIdFromObject,possibleTypes:n.config.possibleTypes,typePolicies:n.config.typePolicies}),n.init(),n}return(0,en.ZT)(t,e),t.prototype.init=function(){var e=this.data=new iT.Root({policies:this.policies,resultCaching:this.config.resultCaching});this.optimisticData=e.stump,this.resetResultCache()},t.prototype.resetResultCache=function(e){var t=this,n=this.storeReader,r=this.config.fragments;this.storeWriter=new i4(this,this.storeReader=new iP({cache:this,addTypename:this.addTypename,resultCacheMaxSize:this.config.resultCacheMaxSize,canonizeResults:ib(this.config),canon:e?void 0:n&&n.canon,fragments:r}),r),this.maybeBroadcastWatch=rZ(function(e,n){return t.broadcastWatch(e,n)},{max:this.config.resultCacheMaxSize,makeCacheKey:function(e){var n=e.optimistic?t.optimisticData:t.data;if(iD(n)){var r=e.optimistic,i=e.id,a=e.variables;return n.makeCacheKey(e.query,e.callback,nx({optimistic:r,id:i,variables:a}))}}}),new Set([this.data.group,this.optimisticData.group,]).forEach(function(e){return e.resetCaching()})},t.prototype.restore=function(e){return this.init(),e&&this.data.replace(e),this},t.prototype.extract=function(e){return void 0===e&&(e=!1),(e?this.optimisticData:this.data).extract()},t.prototype.read=function(e){var t=e.returnPartialData,n=void 0!==t&&t;try{return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,config:this.config,returnPartialData:n})).result||null}catch(r){if(r instanceof is)return null;throw r}},t.prototype.write=function(e){try{return++this.txCount,this.storeWriter.writeToStore(this.data,e)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.modify=function(e){if(ic.call(e,"id")&&!e.id)return!1;var t=e.optimistic?this.optimisticData:this.data;try{return++this.txCount,t.modify(e.id||"ROOT_QUERY",e.fields)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.diff=function(e){return this.storeReader.diffQueryAgainstStore((0,en.pi)((0,en.pi)({},e),{store:e.optimistic?this.optimisticData:this.data,rootId:e.id||"ROOT_QUERY",config:this.config}))},t.prototype.watch=function(e){var t=this;return this.watches.size||r0(this),this.watches.add(e),e.immediate&&this.maybeBroadcastWatch(e),function(){t.watches.delete(e)&&!t.watches.size&&r1(t),t.maybeBroadcastWatch.forget(e)}},t.prototype.gc=function(e){nx.reset();var t=this.optimisticData.gc();return e&&!this.txCount&&(e.resetResultCache?this.resetResultCache(e.resetResultIdentities):e.resetResultIdentities&&this.storeReader.resetCanon()),t},t.prototype.retain=function(e,t){return(t?this.optimisticData:this.data).retain(e)},t.prototype.release=function(e,t){return(t?this.optimisticData:this.data).release(e)},t.prototype.identify=function(e){if(eD(e))return e.__ref;try{return this.policies.identify(e)[0]}catch(t){__DEV__&&Q.kG.warn(t)}},t.prototype.evict=function(e){if(!e.id){if(ic.call(e,"id"))return!1;e=(0,en.pi)((0,en.pi)({},e),{id:"ROOT_QUERY"})}try{return++this.txCount,this.optimisticData.evict(e,this.data)}finally{--this.txCount||!1===e.broadcast||this.broadcastWatches()}},t.prototype.reset=function(e){var t=this;return this.init(),nx.reset(),e&&e.discardWatches?(this.watches.forEach(function(e){return t.maybeBroadcastWatch.forget(e)}),this.watches.clear(),r1(this)):this.broadcastWatches(),Promise.resolve()},t.prototype.removeOptimistic=function(e){var t=this.optimisticData.removeLayer(e);t!==this.optimisticData&&(this.optimisticData=t,this.broadcastWatches())},t.prototype.batch=function(e){var t,n=this,r=e.update,i=e.optimistic,a=void 0===i||i,o=e.removeOptimistic,s=e.onWatchUpdated,u=function(e){var i=n,a=i.data,o=i.optimisticData;++n.txCount,e&&(n.data=n.optimisticData=e);try{return t=r(n)}finally{--n.txCount,n.data=a,n.optimisticData=o}},c=new Set;return s&&!this.txCount&&this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e){return c.add(e),!1}})),"string"==typeof a?this.optimisticData=this.optimisticData.addLayer(a,u):!1===a?u(this.data):u(),"string"==typeof o&&(this.optimisticData=this.optimisticData.removeLayer(o)),s&&c.size?(this.broadcastWatches((0,en.pi)((0,en.pi)({},e),{onWatchUpdated:function(e,t){var n=s.call(this,e,t);return!1!==n&&c.delete(e),n}})),c.size&&c.forEach(function(e){return n.maybeBroadcastWatch.dirty(e)})):this.broadcastWatches(e),t},t.prototype.performTransaction=function(e,t){return this.batch({update:e,optimistic:t||null!==t})},t.prototype.transformDocument=function(e){if(this.addTypename){var t=this.typenameDocumentCache.get(e);return t||(t=nj(e),this.typenameDocumentCache.set(e,t),this.typenameDocumentCache.set(t,t)),t}return e},t.prototype.transformForLink=function(e){var t=this.config.fragments;return t?t.transform(e):e},t.prototype.broadcastWatches=function(e){var t=this;this.txCount||this.watches.forEach(function(n){return t.maybeBroadcastWatch(n,e)})},t.prototype.broadcastWatch=function(e,t){var n=e.lastDiff,r=this.diff(e);(!t||(e.optimistic&&"string"==typeof t.optimistic&&(r.fromOptimisticTransaction=!0),!t.onWatchUpdated||!1!==t.onWatchUpdated.call(this,e,r,n)))&&(n&&(0,nm.D)(n.result,r.result)||e.callback(e.lastDiff=r,n))},t}(io),ar={possibleTypes:{ApproveJobProposalSpecPayload:["ApproveJobProposalSpecSuccess","JobAlreadyExistsError","NotFoundError"],BridgePayload:["Bridge","NotFoundError"],CancelJobProposalSpecPayload:["CancelJobProposalSpecSuccess","NotFoundError"],ChainPayload:["Chain","NotFoundError"],CreateAPITokenPayload:["CreateAPITokenSuccess","InputErrors"],CreateBridgePayload:["CreateBridgeSuccess"],CreateCSAKeyPayload:["CSAKeyExistsError","CreateCSAKeySuccess"],CreateFeedsManagerChainConfigPayload:["CreateFeedsManagerChainConfigSuccess","InputErrors","NotFoundError"],CreateFeedsManagerPayload:["CreateFeedsManagerSuccess","InputErrors","NotFoundError","SingleFeedsManagerError"],CreateJobPayload:["CreateJobSuccess","InputErrors"],CreateOCR2KeyBundlePayload:["CreateOCR2KeyBundleSuccess"],CreateOCRKeyBundlePayload:["CreateOCRKeyBundleSuccess"],CreateP2PKeyPayload:["CreateP2PKeySuccess"],DeleteAPITokenPayload:["DeleteAPITokenSuccess","InputErrors"],DeleteBridgePayload:["DeleteBridgeConflictError","DeleteBridgeInvalidNameError","DeleteBridgeSuccess","NotFoundError"],DeleteCSAKeyPayload:["DeleteCSAKeySuccess","NotFoundError"],DeleteFeedsManagerChainConfigPayload:["DeleteFeedsManagerChainConfigSuccess","NotFoundError"],DeleteJobPayload:["DeleteJobSuccess","NotFoundError"],DeleteOCR2KeyBundlePayload:["DeleteOCR2KeyBundleSuccess","NotFoundError"],DeleteOCRKeyBundlePayload:["DeleteOCRKeyBundleSuccess","NotFoundError"],DeleteP2PKeyPayload:["DeleteP2PKeySuccess","NotFoundError"],DeleteVRFKeyPayload:["DeleteVRFKeySuccess","NotFoundError"],DismissJobErrorPayload:["DismissJobErrorSuccess","NotFoundError"],Error:["CSAKeyExistsError","DeleteBridgeConflictError","DeleteBridgeInvalidNameError","InputError","JobAlreadyExistsError","NotFoundError","RunJobCannotRunError","SingleFeedsManagerError"],EthTransactionPayload:["EthTransaction","NotFoundError"],FeaturesPayload:["Features"],FeedsManagerPayload:["FeedsManager","NotFoundError"],GetSQLLoggingPayload:["SQLLogging"],GlobalLogLevelPayload:["GlobalLogLevel"],JobPayload:["Job","NotFoundError"],JobProposalPayload:["JobProposal","NotFoundError"],JobRunPayload:["JobRun","NotFoundError"],JobSpec:["BlockHeaderFeederSpec","BlockhashStoreSpec","BootstrapSpec","CronSpec","DirectRequestSpec","FluxMonitorSpec","GatewaySpec","KeeperSpec","OCR2Spec","OCRSpec","VRFSpec","WebhookSpec"],NodePayload:["Node","NotFoundError"],PaginatedPayload:["BridgesPayload","ChainsPayload","EthTransactionAttemptsPayload","EthTransactionsPayload","JobRunsPayload","JobsPayload","NodesPayload"],RejectJobProposalSpecPayload:["NotFoundError","RejectJobProposalSpecSuccess"],RunJobPayload:["NotFoundError","RunJobCannotRunError","RunJobSuccess"],SetGlobalLogLevelPayload:["InputErrors","SetGlobalLogLevelSuccess"],SetSQLLoggingPayload:["SetSQLLoggingSuccess"],SetServicesLogLevelsPayload:["InputErrors","SetServicesLogLevelsSuccess"],UpdateBridgePayload:["NotFoundError","UpdateBridgeSuccess"],UpdateFeedsManagerChainConfigPayload:["InputErrors","NotFoundError","UpdateFeedsManagerChainConfigSuccess"],UpdateFeedsManagerPayload:["InputErrors","NotFoundError","UpdateFeedsManagerSuccess"],UpdateJobProposalSpecDefinitionPayload:["NotFoundError","UpdateJobProposalSpecDefinitionSuccess"],UpdatePasswordPayload:["InputErrors","UpdatePasswordSuccess"],VRFKeyPayload:["NotFoundError","VRFKeySuccess"]}};let ai=ar;var aa=(r=void 0,location.origin),ao=new nh({uri:"".concat(aa,"/query"),credentials:"include"}),as=new ia({cache:new an({possibleTypes:ai.possibleTypes}),link:ao});if(a.Z.locale(o),u().defaultFormat="YYYY-MM-DD h:mm:ss A","undefined"!=typeof document){var au,ac,al=f().hydrate;ac=X,al(c.createElement(et,{client:as},c.createElement(d.zj,null,c.createElement(i.MuiThemeProvider,{theme:J.r},c.createElement(ac,null)))),document.getElementById("root"))}})()})(); \ No newline at end of file diff --git a/core/web/assets/main.74b124ef5d2ef3614139.js.gz b/core/web/assets/main.74b124ef5d2ef3614139.js.gz new file mode 100644 index 00000000000..667a96c1ef3 Binary files /dev/null and b/core/web/assets/main.74b124ef5d2ef3614139.js.gz differ diff --git a/core/web/assets/main.b0b6f79f7f4a94560e37.js.gz b/core/web/assets/main.b0b6f79f7f4a94560e37.js.gz deleted file mode 100644 index c505ea9eead..00000000000 Binary files a/core/web/assets/main.b0b6f79f7f4a94560e37.js.gz and /dev/null differ diff --git a/core/web/auth/auth_test.go b/core/web/auth/auth_test.go index f0b4e5068fb..2ac6473ed2e 100644 --- a/core/web/auth/auth_test.go +++ b/core/web/auth/auth_test.go @@ -2,6 +2,7 @@ package auth_test import ( "fmt" + "io" "net/http" "net/http/httptest" "testing" @@ -75,7 +76,7 @@ func TestAuthenticateByToken_Success(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) req.Header.Set(webauth.APIKey, key) req.Header.Set(webauth.APISecret, secret) router.ServeHTTP(w, req) @@ -96,7 +97,7 @@ func TestAuthenticateByToken_AuthFailed(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) req.Header.Set(webauth.APIKey, "bad-key") req.Header.Set(webauth.APISecret, "bad-secret") router.ServeHTTP(w, req) @@ -122,7 +123,7 @@ func TestAuthenticateByToken_RejectsBlankAccessKey(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) req.Header.Set(webauth.APIKey, key) req.Header.Set(webauth.APISecret, secret) router.ServeHTTP(w, req) @@ -143,7 +144,7 @@ func TestRequireAuth_NoneRequired(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) router.ServeHTTP(w, req) assert.True(t, called) @@ -161,7 +162,7 @@ func TestRequireAuth_AuthFailed(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) router.ServeHTTP(w, req) assert.False(t, called) @@ -179,7 +180,7 @@ func TestRequireAuth_LastAuthSuccess(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) router.ServeHTTP(w, req) assert.True(t, called) @@ -197,7 +198,7 @@ func TestRequireAuth_Error(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) router.ServeHTTP(w, req) assert.False(t, called) @@ -504,3 +505,10 @@ func TestRBAC_Routemap_ViewOnly(t *testing.T) { }) } } + +func mustRequest(t *testing.T, method, url string, body io.Reader) *http.Request { + ctx := testutils.Context(t) + req, err := http.NewRequestWithContext(ctx, method, url, body) + require.NoError(t, err) + return req +} diff --git a/core/web/auth/gql_test.go b/core/web/auth/gql_test.go index 4f3f8e27baf..f3d085c71f8 100644 --- a/core/web/auth/gql_test.go +++ b/core/web/auth/gql_test.go @@ -37,7 +37,7 @@ func Test_AuthenticateGQL_Unauthenticated(t *testing.T) { }) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) r.ServeHTTP(w, req) } @@ -63,7 +63,7 @@ func Test_AuthenticateGQL_Authenticated(t *testing.T) { sessionORM.On("AuthorizedUserWithSession", sessionID).Return(clsessions.User{Email: cltest.APIEmailAdmin, Role: clsessions.UserRoleAdmin}, nil) w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/", nil) + req := mustRequest(t, "GET", "/", nil) cookie := cltest.MustGenerateSessionCookie(t, sessionID) req.AddCookie(cookie) diff --git a/core/web/build_info_controller_test.go b/core/web/build_info_controller_test.go index e2d2cb0e631..5a2b88fa0dc 100644 --- a/core/web/build_info_controller_test.go +++ b/core/web/build_info_controller_test.go @@ -32,12 +32,15 @@ func TestBuildInfoController_Show_APICredentials(t *testing.T) { func TestBuildInfoController_Show_NoCredentials(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := clhttptest.NewTestLocalOnlyHTTPClient() url := app.Server.URL + "/v2/build_info" - resp, err := client.Get(url) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) require.Equal(t, http.StatusUnauthorized, resp.StatusCode) } diff --git a/core/web/chains_controller.go b/core/web/chains_controller.go index e547cf0150e..61c8d1dc84d 100644 --- a/core/web/chains_controller.go +++ b/core/web/chains_controller.go @@ -45,7 +45,7 @@ func newChainsController[R jsonapi.EntityNamer](network relay.Network, chainStat newResource func(types.ChainStatus) R, lggr logger.Logger, auditLogger audit.AuditLogger) *chainsController[R] { return &chainsController[R]{ network: network, - resourceName: string(network) + "_chain", + resourceName: network + "_chain", chainStats: chainStats, errNotEnabled: errNotEnabled, newResource: newResource, @@ -79,7 +79,7 @@ func (cc *chainsController[R]) Show(c *gin.Context) { jsonAPIError(c, http.StatusBadRequest, cc.errNotEnabled) return } - relayID := relay.ID{Network: cc.network, ChainID: relay.ChainID(c.Param("ID"))} + relayID := relay.ID{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_keys_controller_test.go b/core/web/cosmos_keys_controller_test.go index af421416388..3b777de7b7c 100644 --- a/core/web/cosmos_keys_controller_test.go +++ b/core/web/cosmos_keys_controller_test.go @@ -5,10 +5,10 @@ import ( "net/http" "testing" + "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/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" diff --git a/core/web/dkgencrypt_keys_controller_test.go b/core/web/dkgencrypt_keys_controller_test.go index 41d7eb4a752..7100cbbb1cd 100644 --- a/core/web/dkgencrypt_keys_controller_test.go +++ b/core/web/dkgencrypt_keys_controller_test.go @@ -8,10 +8,10 @@ import ( "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/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/web/dkgsign_keys_controller_test.go b/core/web/dkgsign_keys_controller_test.go index 611c5b3ef0a..ed67d71a0d5 100644 --- a/core/web/dkgsign_keys_controller_test.go +++ b/core/web/dkgsign_keys_controller_test.go @@ -8,10 +8,10 @@ import ( "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/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) diff --git a/core/web/eth_keys_controller.go b/core/web/eth_keys_controller.go index d99992c0f56..fe76e8863ef 100644 --- a/core/web/eth_keys_controller.go +++ b/core/web/eth_keys_controller.go @@ -11,6 +11,7 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -19,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" "github.com/ethereum/go-ethereum/common" @@ -393,7 +393,7 @@ func (ekc *ETHKeysController) getLinkBalance(ctx context.Context, state ethkey.S // gets the key specific max gas price from the chain config and sets it on the // resource. func (ekc *ETHKeysController) setKeyMaxGasPriceWei(price *assets.Wei) presenters.NewETHKeyOption { - return presenters.SetETHKeyMaxGasPriceWei(utils.NewBig(price.ToInt())) + return presenters.SetETHKeyMaxGasPriceWei(ubig.New(price.ToInt())) } func (ekc *ETHKeysController) getKeyMaxGasPriceWei(state ethkey.State, keyAddress common.Address) *assets.Wei { diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index d0ad27262f2..739af5820c9 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -16,6 +16,7 @@ import ( "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/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" webpresenters "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -411,10 +412,12 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { }) assert.NoError(t, err) - var count int - err = app.GetSqlxDB().Get(&count, `SELECT count(*) FROM evm.txes WHERE from_address = $1 AND state = 'fatal_error'`, addr) + db := app.GetSqlxDB() + txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg.Database()) + + txes, err := txStore.FindTxesByFromAddressAndState(testutils.Context(t), addr, "fatal_error") require.NoError(t, err) - assert.Equal(t, 0, count) + require.Len(t, txes, 0) client := app.NewHTTPClient(nil) chainURL := url.URL{Path: "/v2/keys/evm/chain"} @@ -437,10 +440,12 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String()) assert.Equal(t, false, updatedKey.Disabled) - var s string - err = app.GetSqlxDB().Get(&s, `SELECT error FROM evm.txes WHERE from_address = $1 AND state = 'fatal_error'`, addr) + txes, err = txStore.FindTxesByFromAddressAndState(testutils.Context(t), addr, "fatal_error") require.NoError(t, err) - assert.Equal(t, "abandoned", s) + require.Len(t, txes, 1) + + tx := txes[0] + assert.Equal(t, "abandoned", tx.Error.String) } func TestETHKeysController_ChainFailure_InvalidAbandon(t *testing.T) { diff --git a/core/web/evm_chains_controller_test.go b/core/web/evm_chains_controller_test.go index 3d5a4e3eedd..ea3d5476cec 100644 --- a/core/web/evm_chains_controller_test.go +++ b/core/web/evm_chains_controller_test.go @@ -12,12 +12,12 @@ import ( "github.com/stretchr/testify/require" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + 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/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -25,7 +25,7 @@ import ( func Test_EVMChainsController_Show(t *testing.T) { t.Parallel() - validId := utils.NewBig(testutils.NewRandomEVMChainID()) + validId := ubig.New(testutils.NewRandomEVMChainID()) testCases := []struct { name string @@ -111,9 +111,9 @@ func Test_EVMChainsController_Index(t *testing.T) { }) configuredChains := evmcfg.EVMConfigs{ - {ChainID: utils.NewBig(chainIDs[0]), Chain: evmcfg.Defaults(nil)}, + {ChainID: ubig.New(chainIDs[0]), Chain: evmcfg.Defaults(nil)}, { - ChainID: utils.NewBig(chainIDs[1]), + ChainID: ubig.New(chainIDs[1]), Chain: evmcfg.Defaults(nil, &evmcfg.Chain{ RPCBlockQueryDelay: ptr[uint16](13), GasEstimator: evmcfg.GasEstimator{ @@ -126,7 +126,7 @@ func Test_EVMChainsController_Index(t *testing.T) { }), }, { - ChainID: utils.NewBig(chainIDs[2]), + ChainID: ubig.New(chainIDs[2]), Chain: evmcfg.Defaults(nil, &evmcfg.Chain{ RPCBlockQueryDelay: ptr[uint16](5), GasEstimator: evmcfg.GasEstimator{ diff --git a/core/web/evm_forwarders_controller.go b/core/web/evm_forwarders_controller.go index 6228723506d..56d1285c88e 100644 --- a/core/web/evm_forwarders_controller.go +++ b/core/web/evm_forwarders_controller.go @@ -8,10 +8,10 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/stringutils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -43,7 +43,7 @@ func (cc *EVMForwardersController) Index(c *gin.Context, size, page, offset int) // TrackEVMForwarderRequest is a JSONAPI request for creating an EVM forwarder. type TrackEVMForwarderRequest struct { - EVMChainID *utils.Big `json:"evmChainId"` + EVMChainID *ubig.Big `json:"evmChainId"` Address common.Address `json:"address"` } diff --git a/core/web/evm_forwarders_controller_test.go b/core/web/evm_forwarders_controller_test.go index 31e49f20ecc..031a1a61c03 100644 --- a/core/web/evm_forwarders_controller_test.go +++ b/core/web/evm_forwarders_controller_test.go @@ -11,11 +11,12 @@ import ( "github.com/stretchr/testify/require" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "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/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -42,7 +43,7 @@ func setupEVMForwardersControllerTest(t *testing.T, overrideFn func(c *chainlink func Test_EVMForwardersController_Track(t *testing.T) { t.Parallel() - chainId := utils.NewBig(testutils.NewRandomEVMChainID()) + chainId := big.New(testutils.NewRandomEVMChainID()) controller := setupEVMForwardersControllerTest(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM = evmcfg.EVMConfigs{ {ChainID: chainId, Enabled: ptr(true), Chain: evmcfg.Defaults(chainId)}, @@ -79,7 +80,7 @@ func Test_EVMForwardersController_Track(t *testing.T) { func Test_EVMForwardersController_Index(t *testing.T) { t.Parallel() - chainId := utils.NewBig(testutils.NewRandomEVMChainID()) + chainId := big.New(testutils.NewRandomEVMChainID()) controller := setupEVMForwardersControllerTest(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM = evmcfg.EVMConfigs{ {ChainID: chainId, Enabled: ptr(true), Chain: evmcfg.Defaults(chainId)}, diff --git a/core/web/evm_transfer_controller.go b/core/web/evm_transfer_controller.go index 6ab621661a6..4a1bf46feea 100644 --- a/core/web/evm_transfer_controller.go +++ b/core/web/evm_transfer_controller.go @@ -13,11 +13,11 @@ import ( commontxmgr "github.com/smartcontractkit/chainlink/v2/common/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" "github.com/gin-gonic/gin" diff --git a/core/web/evm_transfer_controller_test.go b/core/web/evm_transfer_controller_test.go index c41219e1894..86d6b4618aa 100644 --- a/core/web/evm_transfer_controller_test.go +++ b/core/web/evm_transfer_controller_test.go @@ -10,16 +10,21 @@ import ( "testing" "time" + "github.com/jmoiron/sqlx" + + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + 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/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -55,7 +60,7 @@ func TestTransfersController_CreateSuccess_From(t *testing.T) { FromAddress: key.Address, Amount: amount, SkipWaitTxAttempt: true, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -68,7 +73,7 @@ func TestTransfersController_CreateSuccess_From(t *testing.T) { assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Len(t, errors.Errors, 0) - cltest.AssertCount(t, app.GetSqlxDB(), "evm.txes", 1) + validateTxCount(t, app.GetSqlxDB(), 1) } func TestTransfersController_CreateSuccess_From_WEI(t *testing.T) { @@ -96,7 +101,7 @@ func TestTransfersController_CreateSuccess_From_WEI(t *testing.T) { FromAddress: key.Address, Amount: amount, SkipWaitTxAttempt: true, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -109,7 +114,7 @@ func TestTransfersController_CreateSuccess_From_WEI(t *testing.T) { assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Len(t, errors.Errors, 0) - cltest.AssertCount(t, app.GetSqlxDB(), "evm.txes", 1) + validateTxCount(t, app.GetSqlxDB(), 1) } func TestTransfersController_CreateSuccess_From_BalanceMonitorDisabled(t *testing.T) { @@ -142,7 +147,7 @@ func TestTransfersController_CreateSuccess_From_BalanceMonitorDisabled(t *testin FromAddress: key.Address, Amount: amount, SkipWaitTxAttempt: true, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -155,7 +160,7 @@ func TestTransfersController_CreateSuccess_From_BalanceMonitorDisabled(t *testin assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Len(t, errors.Errors, 0) - cltest.AssertCount(t, app.GetSqlxDB(), "evm.txes", 1) + validateTxCount(t, app.GetSqlxDB(), 1) } func TestTransfersController_TransferZeroAddressError(t *testing.T) { @@ -172,7 +177,7 @@ func TestTransfersController_TransferZeroAddressError(t *testing.T) { DestinationAddress: common.HexToAddress("0xFA01FA015C8A5332987319823728982379128371"), FromAddress: common.HexToAddress("0x0000000000000000000000000000000000000000"), Amount: amount, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -207,7 +212,7 @@ func TestTransfersController_TransferBalanceToLowError(t *testing.T) { DestinationAddress: common.HexToAddress("0xFA01FA015C8A5332987319823728982379128371"), Amount: amount, AllowHigherAmounts: false, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -245,7 +250,7 @@ func TestTransfersController_TransferBalanceToLowError_ZeroBalance(t *testing.T) DestinationAddress: common.HexToAddress("0xFA01FA015C8A5332987319823728982379128371"), Amount: amount, AllowHigherAmounts: false, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, app.Config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -288,10 +293,10 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { config := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.Mode = ptr("FixedPrice") - c.EVM[0].ChainID = (*utils.Big)(testutils.FixtureChainID) + c.EVM[0].ChainID = (*ubig.Big)(testutils.FixtureChainID) // NOTE: FallbackPollInterval is used in this test to quickly create TxAttempts // Testing triggers requires committing transactions and does not work with transactional tests - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(time.Second) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(time.Second) }) app := cltest.NewApplicationWithConfigAndKey(t, config, ethClient, key) @@ -308,7 +313,7 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { FromAddress: key.Address, Amount: amount, WaitAttemptTimeout: &timeout, - EVMChainID: utils.NewBig(evmtest.MustGetDefaultChainID(t, config.EVMConfigs())), + EVMChainID: ubig.New(evmtest.MustGetDefaultChainID(t, config.EVMConfigs())), } body, err := json.Marshal(&request) @@ -323,7 +328,7 @@ func TestTransfersController_CreateSuccess_eip1559(t *testing.T) { err = web.ParseJSONAPIResponse(cltest.ParseResponseBody(t, resp), &resource) assert.NoError(t, err) - cltest.AssertCount(t, app.GetSqlxDB(), "evm.txes", 1) + validateTxCount(t, app.GetSqlxDB(), 1) // check returned data assert.NotEmpty(t, resource.Hash) @@ -393,3 +398,12 @@ func TestTransfersController_FindTxAttempt(t *testing.T) { assert.ErrorContains(t, err, "context canceled") }) } + +func validateTxCount(t *testing.T, db *sqlx.DB, count int) { + cfg := pgtest.NewQConfig(false) + txStore := txmgr.NewTxStore(db, logger.TestLogger(t), cfg) + + txes, err := txStore.GetAllTxes(testutils.Context(t)) + require.NoError(t, err) + require.Len(t, txes, count) +} diff --git a/core/web/gui_assets_test.go b/core/web/gui_assets_test.go index 137b1231984..810aa40ca05 100644 --- a/core/web/gui_assets_test.go +++ b/core/web/gui_assets_test.go @@ -44,7 +44,9 @@ func TestGuiAssets_DefaultIndexHtml_OK(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() - resp, err := client.Get(app.Server.URL + tc.path) + req, err := http.NewRequestWithContext(testutils.Context(t), "GET", app.Server.URL+tc.path, nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) cltest.AssertServerResponse(t, resp, http.StatusOK) }) @@ -75,7 +77,9 @@ func TestGuiAssets_DefaultIndexHtml_NotFound(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() - resp, err := client.Get(app.Server.URL + tc.path) + req, err := http.NewRequestWithContext(testutils.Context(t), "GET", app.Server.URL+tc.path, nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) cltest.AssertServerResponse(t, resp, http.StatusNotFound) }) @@ -94,13 +98,17 @@ func TestGuiAssets_DefaultIndexHtml_RateLimited(t *testing.T) { // Make calls equal to the rate limit rateLimit := 20 for i := 0; i < rateLimit; i++ { - resp, err := client.Get(app.Server.URL + "/") + req, err := http.NewRequestWithContext(testutils.Context(t), "GET", app.Server.URL+"/", nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) cltest.AssertServerResponse(t, resp, http.StatusOK) } // Last request fails - resp, err := client.Get(app.Server.URL + "/") + req, err := http.NewRequestWithContext(testutils.Context(t), "GET", app.Server.URL+"/", nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) assert.Equal(t, http.StatusTooManyRequests, resp.StatusCode) } @@ -115,7 +123,7 @@ func TestGuiAssets_AssetsFS(t *testing.T) { recorder := httptest.NewRecorder() c, _ := gin.CreateTestContext(recorder) var err error - c.Request, err = http.NewRequest("GET", "http://localhost:6688/fixtures/operator_ui/assets/main.js", nil) + c.Request, err = http.NewRequestWithContext(c, "GET", "http://localhost:6688/fixtures/operator_ui/assets/main.js", nil) require.NoError(t, err) handler(c) @@ -123,7 +131,7 @@ func TestGuiAssets_AssetsFS(t *testing.T) { recorder = httptest.NewRecorder() c, _ = gin.CreateTestContext(recorder) - c.Request, err = http.NewRequest("GET", "http://localhost:6688/fixtures/operator_ui/assets/kinda_main.js", nil) + c.Request, err = http.NewRequestWithContext(c, "GET", "http://localhost:6688/fixtures/operator_ui/assets/kinda_main.js", nil) require.NoError(t, err) handler(c) @@ -134,7 +142,7 @@ func TestGuiAssets_AssetsFS(t *testing.T) { recorder := httptest.NewRecorder() c, _ := gin.CreateTestContext(recorder) var err error - c.Request, err = http.NewRequest("GET", "http://localhost:6688/fixtures/operator_ui/assets/main.js", nil) + c.Request, err = http.NewRequestWithContext(c, "GET", "http://localhost:6688/fixtures/operator_ui/assets/main.js", nil) require.NoError(t, err) c.Request.Header.Set("Accept-Encoding", "gzip") handler(c) @@ -144,7 +152,7 @@ func TestGuiAssets_AssetsFS(t *testing.T) { recorder = httptest.NewRecorder() c, _ = gin.CreateTestContext(recorder) - c.Request, err = http.NewRequest("GET", "http://localhost:6688/fixtures/operator_ui/assets/kinda_main.js", nil) + c.Request, err = http.NewRequestWithContext(c, "GET", "http://localhost:6688/fixtures/operator_ui/assets/kinda_main.js", nil) require.NoError(t, err) c.Request.Header.Set("Accept-Encoding", "gzip") handler(c) diff --git a/core/web/health_controller.go b/core/web/health_controller.go index d6a7edb2340..7ab07291b58 100644 --- a/core/web/health_controller.go +++ b/core/web/health_controller.go @@ -1,9 +1,15 @@ package web import ( + "bytes" + "fmt" + "io" "net/http" + "slices" + "strings" "github.com/gin-gonic/gin" + "golang.org/x/exp/maps" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -70,13 +76,12 @@ func (hc *HealthController) Health(c *gin.Context) { healthy, errors := checker.IsHealthy() if !healthy { - status = http.StatusServiceUnavailable + status = http.StatusMultiStatus } c.Status(status) checks := make([]presenters.Check, 0, len(errors)) - for name, err := range errors { status := HealthStatusPassing var output string @@ -94,6 +99,188 @@ func (hc *HealthController) Health(c *gin.Context) { }) } - // return a json description of all the checks - jsonAPIResponse(c, checks, "checks") + switch c.NegotiateFormat(gin.MIMEJSON, gin.MIMEHTML, gin.MIMEPlain) { + case gin.MIMEJSON: + break // default + + case gin.MIMEHTML: + if err := newCheckTree(checks).WriteHTMLTo(c.Writer); err != nil { + hc.App.GetLogger().Errorw("Failed to write HTML health report", "err", err) + c.AbortWithStatus(http.StatusInternalServerError) + } + return + + case gin.MIMEPlain: + if err := writeTextTo(c.Writer, checks); err != nil { + hc.App.GetLogger().Errorw("Failed to write plaintext health report", "err", err) + c.AbortWithStatus(http.StatusInternalServerError) + } + return + } + + slices.SortFunc(checks, presenters.CmpCheckName) + jsonAPIResponseWithStatus(c, checks, "checks", status) +} + +func writeTextTo(w io.Writer, checks []presenters.Check) error { + slices.SortFunc(checks, presenters.CmpCheckName) + for _, ch := range checks { + status := "?" + switch ch.Status { + case HealthStatusPassing: + status = "-" + case HealthStatusFailing: + status = "!" + } + if _, err := fmt.Fprintf(w, "%s%s\n", status, ch.Name); err != nil { + return err + } + if ch.Output != "" { + if _, err := fmt.Fprintf(newLinePrefixWriter(w, "\t"), "\t%s", ch.Output); err != nil { + return err + } + if _, err := fmt.Fprintln(w); err != nil { + return err + } + } + } + return nil +} + +type checkNode struct { + Name string // full + Status string + Output string + + Subs checkTree +} + +type checkTree map[string]checkNode + +func newCheckTree(checks []presenters.Check) checkTree { + slices.SortFunc(checks, presenters.CmpCheckName) + root := make(checkTree) + for _, c := range checks { + parts := strings.Split(c.Name, ".") + node := root + for _, short := range parts[:len(parts)-1] { + n, ok := node[short] + if !ok { + n = checkNode{Subs: make(checkTree)} + node[short] = n + } + node = n.Subs + } + p := parts[len(parts)-1] + node[p] = checkNode{ + Name: c.Name, + Status: c.Status, + Output: c.Output, + Subs: make(checkTree), + } + } + return root +} + +func (t checkTree) WriteHTMLTo(w io.Writer) error { + if _, err := io.WriteString(w, ``); err != nil { + return err + } + return t.writeHTMLTo(newLinePrefixWriter(w, "")) +} + +func (t checkTree) writeHTMLTo(w *linePrefixWriter) error { + keys := maps.Keys(t) + slices.Sort(keys) + for _, short := range keys { + node := t[short] + if _, err := io.WriteString(w, ` +
`); err != nil { + return err + } + var expand string + if node.Output == "" && len(node.Subs) == 0 { + expand = ` class="noexpand"` + } + if _, err := fmt.Fprintf(w, ` + %s`, node.Name, expand, node.Status, short); err != nil { + return err + } + if node.Output != "" { + if _, err := w.WriteRawLinef("
%s
", node.Output); err != nil { + return err + } + } + if len(node.Subs) > 0 { + if err := node.Subs.writeHTMLTo(w.new(" ")); err != nil { + return err + } + } + if _, err := io.WriteString(w, "\n
"); err != nil { + return err + } + } + return nil +} + +type linePrefixWriter struct { + w io.Writer + prefix string + prefixB []byte +} + +func newLinePrefixWriter(w io.Writer, prefix string) *linePrefixWriter { + prefix = "\n" + prefix + return &linePrefixWriter{w: w, prefix: prefix, prefixB: []byte(prefix)} +} + +func (w *linePrefixWriter) new(prefix string) *linePrefixWriter { + prefix = w.prefix + prefix + return &linePrefixWriter{w: w.w, prefix: prefix, prefixB: []byte(prefix)} +} + +func (w *linePrefixWriter) Write(b []byte) (int, error) { + return w.w.Write(bytes.ReplaceAll(b, []byte("\n"), w.prefixB)) +} + +func (w *linePrefixWriter) WriteString(s string) (n int, err error) { + return io.WriteString(w.w, strings.ReplaceAll(s, "\n", w.prefix)) +} + +// WriteRawLinef writes a new newline with prefix, followed by s without modification. +func (w *linePrefixWriter) WriteRawLinef(s string, args ...any) (n int, err error) { + return fmt.Fprintf(w.w, w.prefix+s, args...) } diff --git a/core/web/health_controller_test.go b/core/web/health_controller_test.go index d380b279d00..547186e33fb 100644 --- a/core/web/health_controller_test.go +++ b/core/web/health_controller_test.go @@ -1,15 +1,20 @@ package web_test import ( + "bytes" + _ "embed" + "encoding/json" + "io" "net/http" "testing" + "github.com/gin-gonic/gin" + "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" "github.com/smartcontractkit/chainlink/v2/core/services/mocks" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestHealthController_Readyz(t *testing.T) { @@ -47,3 +52,82 @@ func TestHealthController_Readyz(t *testing.T) { }) } } + +func TestHealthController_Health_status(t *testing.T) { + var tt = []struct { + name string + ready bool + status int + }{ + { + name: "not ready", + ready: false, + status: http.StatusMultiStatus, + }, + { + name: "ready", + ready: true, + status: http.StatusOK, + }, + } + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + app := cltest.NewApplicationWithKey(t) + healthChecker := new(mocks.Checker) + healthChecker.On("Start").Return(nil).Once() + healthChecker.On("IsHealthy").Return(tc.ready, nil).Once() + healthChecker.On("Close").Return(nil).Once() + + app.HealthChecker = healthChecker + require.NoError(t, app.Start(testutils.Context(t))) + + client := app.NewHTTPClient(nil) + resp, cleanup := client.Get("/health") + t.Cleanup(cleanup) + assert.Equal(t, tc.status, resp.StatusCode) + }) + } +} + +var ( + //go:embed testdata/body/health.json + bodyJSON string + //go:embed testdata/body/health.html + bodyHTML string + //go:embed testdata/body/health.txt + bodyTXT string +) + +func TestHealthController_Health_body(t *testing.T) { + for _, tc := range []struct { + name string + path string + headers map[string]string + expBody string + }{ + {"default", "/health", nil, bodyJSON}, + {"json", "/health", map[string]string{"Accept": gin.MIMEJSON}, bodyJSON}, + {"html", "/health", map[string]string{"Accept": gin.MIMEHTML}, bodyHTML}, + {"text", "/health", map[string]string{"Accept": gin.MIMEPlain}, bodyTXT}, + {".txt", "/health.txt", nil, bodyTXT}, + } { + t.Run(tc.name, func(t *testing.T) { + app := cltest.NewApplicationWithKey(t) + require.NoError(t, app.Start(testutils.Context(t))) + + client := app.NewHTTPClient(nil) + resp, cleanup := client.Get(tc.path, tc.headers) + t.Cleanup(cleanup) + assert.Equal(t, http.StatusMultiStatus, resp.StatusCode) + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + if tc.expBody == bodyJSON { + // pretty print for comparison + var b bytes.Buffer + require.NoError(t, json.Indent(&b, body, "", " ")) + body = b.Bytes() + } + assert.Equal(t, tc.expBody, string(body)) + }) + } +} diff --git a/core/web/health_template_test.go b/core/web/health_template_test.go new file mode 100644 index 00000000000..fa9750fed22 --- /dev/null +++ b/core/web/health_template_test.go @@ -0,0 +1,53 @@ +package web + +import ( + "bytes" + _ "embed" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/web/presenters" +) + +var ( + //go:embed testdata/health.html + healthHTML string + + //go:embed testdata/health.txt + healthTXT string +) + +func checks() []presenters.Check { + const passing, failing = HealthStatusPassing, HealthStatusFailing + return []presenters.Check{ + {Name: "foo", Status: passing}, + {Name: "foo.bar", Status: failing, Output: "example error message"}, + {Name: "foo.bar.1", Status: passing}, + {Name: "foo.bar.1.A", Status: passing}, + {Name: "foo.bar.1.B", Status: passing}, + {Name: "foo.bar.2", Status: failing, Output: `error: +this is a multi-line error: +new line: +original error`}, + {Name: "foo.bar.2.A", Status: failing, Output: "failure!"}, + {Name: "foo.bar.2.B", Status: passing}, + {Name: "foo.baz", Status: passing}, + } + //TODO truncated error +} + +func Test_checkTree_WriteHTMLTo(t *testing.T) { + ct := newCheckTree(checks()) + var b bytes.Buffer + require.NoError(t, ct.WriteHTMLTo(&b)) + got := b.String() + require.Equalf(t, healthHTML, got, "got: %s", got) +} + +func Test_writeTextTo(t *testing.T) { + var b bytes.Buffer + require.NoError(t, writeTextTo(&b, checks())) + got := b.String() + require.Equalf(t, healthTXT, got, "got: %s", got) +} diff --git a/core/web/jobs_controller.go b/core/web/jobs_controller.go index 0f97e0b53d3..4e11f68097d 100644 --- a/core/web/jobs_controller.go +++ b/core/web/jobs_controller.go @@ -27,6 +27,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/pg" + "github.com/smartcontractkit/chainlink/v2/core/services/streams" "github.com/smartcontractkit/chainlink/v2/core/services/vrf/vrfcommon" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -250,6 +251,8 @@ func (jc *JobsController) validateJobSpec(tomlString string) (jb job.Job, status jb, err = ocrbootstrap.ValidatedBootstrapSpecToml(tomlString) case job.Gateway: jb, err = gateway.ValidatedGatewaySpec(tomlString) + case job.Stream: + jb, err = streams.ValidatedStreamSpec(tomlString) default: return jb, http.StatusUnprocessableEntity, errors.Errorf("unknown job type: %s", jobType) } diff --git a/core/web/jobs_controller_test.go b/core/web/jobs_controller_test.go index 2e3f3a83693..eec58c30571 100644 --- a/core/web/jobs_controller_test.go +++ b/core/web/jobs_controller_test.go @@ -17,14 +17,16 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" - p2ppeer "github.com/libp2p/go-libp2p-core/peer" + "github.com/hashicorp/consul/sdk/freeport" "github.com/pelletier/go-toml" + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-common/pkg/utils" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -34,9 +36,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/vrfkey" "github.com/smartcontractkit/chainlink/v2/core/services/pg" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/tomlutils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -47,8 +49,8 @@ func TestJobsController_Create_ValidationFailure_OffchainReportingSpec(t *testin contractAddress = cltest.NewEIP55Address() ) - peerID, err := p2ppeer.Decode(configtest.DefaultPeerID) - require.NoError(t, err) + var peerID ragep2ptypes.PeerID + require.NoError(t, peerID.UnmarshalText([]byte(configtest.DefaultPeerID))) randomBytes := testutils.Random32Byte() var tt = []struct { @@ -138,12 +140,17 @@ func TestJobController_Create_HappyPath(t *testing.T) { app, client := setupJobsControllerTests(t) b1, b2 := setupBridges(t, app.GetSqlxDB(), app.GetConfig().Database()) require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) - pks, err := app.KeyStore.VRF().GetAll() - require.NoError(t, err) - require.Len(t, pks, 1) - k, err := app.KeyStore.P2P().GetAll() - require.NoError(t, err) - require.Len(t, k, 1) + var pks []vrfkey.KeyV2 + var k []p2pkey.KeyV2 + { + var err error + pks, err = app.KeyStore.VRF().GetAll() + require.NoError(t, err) + require.Len(t, pks, 1) + k, err = app.KeyStore.P2P().GetAll() + require.NoError(t, err) + require.Len(t, k, 1) + } jorm := app.JobORM() var tt = []struct { @@ -173,7 +180,7 @@ func TestJobController_Create_HappyPath(t *testing.T) { require.NotNil(t, resource.OffChainReportingSpec) assert.Equal(t, nameAndExternalJobID, jb.Name.ValueOrZero()) - assert.Equal(t, jb.OCROracleSpec.P2PBootstrapPeers, resource.OffChainReportingSpec.P2PBootstrapPeers) + assert.Equal(t, jb.OCROracleSpec.P2PV2Bootstrappers, resource.OffChainReportingSpec.P2PV2Bootstrappers) assert.Equal(t, jb.OCROracleSpec.IsBootstrapPeer, resource.OffChainReportingSpec.IsBootstrapPeer) assert.Equal(t, jb.OCROracleSpec.EncryptedOCRKeyBundleID, resource.OffChainReportingSpec.EncryptedOCRKeyBundleID) assert.Equal(t, jb.OCROracleSpec.TransmitterAddress, resource.OffChainReportingSpec.TransmitterAddress) @@ -359,6 +366,26 @@ func TestJobController_Create_HappyPath(t *testing.T) { assert.Equal(t, jb.VRFSpec.CoordinatorAddress.Hex(), resource.VRFSpec.CoordinatorAddress.Hex()) }, }, + { + name: "stream", + tomlTemplate: func(_ string) string { + return testspecs.GenerateStreamSpec(testspecs.StreamSpecParams{Name: "ETH/USD"}).Toml() + }, + assertion: func(t *testing.T, nameAndExternalJobID string, r *http.Response) { + require.Equal(t, http.StatusOK, r.StatusCode) + resp := cltest.ParseResponseBody(t, r) + resource := presenters.JobResource{} + err := web.ParseJSONAPIResponse(resp, &resource) + require.NoError(t, err) + + jb, err := jorm.FindJob(testutils.Context(t), mustInt32FromString(t, resource.ID)) + require.NoError(t, err) + require.NotNil(t, jb.PipelineSpec) + + assert.NotNil(t, resource.PipelineSpec.DotDAGSource) + assert.Equal(t, jb.Name.ValueOrZero(), resource.Name) + }, + }, } for _, tc := range tt { c := tc @@ -379,6 +406,7 @@ func TestJobController_Create_HappyPath(t *testing.T) { 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{}, app.GetConfig().Database()) _, submitBridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) @@ -511,7 +539,8 @@ func TestJobsController_Show_NonExistentID(t *testing.T) { func TestJobsController_Update_HappyPath(t *testing.T) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = &cltest.DefaultP2PPeerID }) app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) @@ -571,15 +600,17 @@ func TestJobsController_Update_HappyPath(t *testing.T) { } func TestJobsController_Update_NonExistentID(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.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = &cltest.DefaultP2PPeerID }) app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) _, bridge2 := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) @@ -599,7 +630,7 @@ func TestJobsController_Update_NonExistentID(t *testing.T) { require.NoError(t, err) jb.OCROracleSpec = &ocrSpec jb.OCROracleSpec.TransmitterAddress = &app.Keys[0].EIP55Address - err = app.AddJobV2(testutils.Context(t), &jb) + err = app.AddJobV2(ctx, &jb) require.NoError(t, err) // test Calling update on the job id with changed values should succeed. @@ -621,7 +652,7 @@ func TestJobsController_Update_NonExistentID(t *testing.T) { func runOCRJobSpecAssertions(t *testing.T, ocrJobSpecFromFileDB job.Job, ocrJobSpecFromServer presenters.JobResource) { ocrJobSpecFromFile := ocrJobSpecFromFileDB.OCROracleSpec assert.Equal(t, ocrJobSpecFromFile.ContractAddress, ocrJobSpecFromServer.OffChainReportingSpec.ContractAddress) - assert.Equal(t, ocrJobSpecFromFile.P2PBootstrapPeers, ocrJobSpecFromServer.OffChainReportingSpec.P2PBootstrapPeers) + assert.Equal(t, ocrJobSpecFromFile.P2PV2Bootstrappers, ocrJobSpecFromServer.OffChainReportingSpec.P2PV2Bootstrappers) assert.Equal(t, ocrJobSpecFromFile.IsBootstrapPeer, ocrJobSpecFromServer.OffChainReportingSpec.IsBootstrapPeer) assert.Equal(t, ocrJobSpecFromFile.EncryptedOCRKeyBundleID, ocrJobSpecFromServer.OffChainReportingSpec.EncryptedOCRKeyBundleID) assert.Equal(t, ocrJobSpecFromFile.TransmitterAddress, ocrJobSpecFromServer.OffChainReportingSpec.TransmitterAddress) @@ -658,7 +689,8 @@ func setupBridges(t *testing.T, db *sqlx.DB, cfg pg.QConfig) (b1, b2 string) { func setupJobsControllerTests(t *testing.T) (ta *cltest.TestApplication, cc cltest.HTTPClientCleaner) { cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = &cltest.DefaultP2PPeerID }) ec := setupEthClientForControllerTests(t) @@ -681,15 +713,17 @@ func setupEthClientForControllerTests(t *testing.T) *evmclimocks.Client { } func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication, cltest.HTTPClientCleaner, job.Job, int32, job.Job, int32) { + ctx := testutils.Context(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = &cltest.DefaultP2PPeerID }) app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) require.NoError(t, app.KeyStore.OCR().Add(cltest.DefaultOCRKey)) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) _, bridge := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) _, bridge2 := cltest.MustCreateBridge(t, app.GetSqlxDB(), cltest.BridgeOpts{}, app.GetConfig().Database()) @@ -705,7 +739,7 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication require.NoError(t, err) jb.OCROracleSpec = &ocrSpec jb.OCROracleSpec.TransmitterAddress = &app.Keys[0].EIP55Address - err = app.AddJobV2(testutils.Context(t), &jb) + err = app.AddJobV2(ctx, &jb) require.NoError(t, err) drSpec := fmt.Sprintf(` @@ -726,7 +760,7 @@ func setupJobSpecsControllerTestsWithJobs(t *testing.T) (*cltest.TestApplication erejb, err := directrequest.ValidatedDirectRequestSpec(drSpec) require.NoError(t, err) - err = app.AddJobV2(testutils.Context(t), &erejb) + err = app.AddJobV2(ctx, &erejb) require.NoError(t, err) return app, client, jb, jb.ID, erejb, erejb.ID diff --git a/core/web/loader/chain.go b/core/web/loader/chain.go index c91c2f02a3b..a12fef3d590 100644 --- a/core/web/loader/chain.go +++ b/core/web/loader/chain.go @@ -20,7 +20,7 @@ func (b *chainBatcher) loadByIDs(_ context.Context, keys dataloader.Keys) []*dat // Collect the keys to search for var chainIDs []relay.ChainID for ix, key := range keys { - chainIDs = append(chainIDs, relay.ChainID(key.String())) + chainIDs = append(chainIDs, key.String()) keyOrder[key.String()] = ix } diff --git a/core/web/loader/loader_test.go b/core/web/loader/loader_test.go index 9bd1feb05bf..a039834997e 100644 --- a/core/web/loader/loader_test.go +++ b/core/web/loader/loader_test.go @@ -17,6 +17,8 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtxmgrmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" coremocks "github.com/smartcontractkit/chainlink/v2/core/internal/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" @@ -26,7 +28,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" jobORMMocks "github.com/smartcontractkit/chainlink/v2/core/services/job/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestLoader_Chains(t *testing.T) { @@ -35,9 +36,9 @@ func TestLoader_Chains(t *testing.T) { app := coremocks.NewApplication(t) ctx := InjectDataloader(testutils.Context(t), app) - one := utils.NewBigI(1) + one := ubig.NewI(1) chain := toml.EVMConfig{ChainID: one, Chain: toml.Defaults(one)} - two := utils.NewBigI(2) + two := ubig.NewI(2) chain2 := toml.EVMConfig{ChainID: two, Chain: toml.Defaults(two)} evmORM := evmtest.NewTestConfigs(&chain, &chain2) app.On("EVMORM").Return(evmORM) diff --git a/core/web/loader/node.go b/core/web/loader/node.go index ef8e363d9f3..3d229813101 100644 --- a/core/web/loader/node.go +++ b/core/web/loader/node.go @@ -23,7 +23,7 @@ func (b *nodeBatcher) loadByChainIDs(ctx context.Context, keys dataloader.Keys) evmrelayIDs := make([]relay.ID, 0, len(keys)) for ix, key := range keys { - rid := relay.ID{Network: relay.EVM, ChainID: relay.ChainID(key.String())} + rid := relay.ID{Network: relay.EVM, ChainID: key.String()} evmrelayIDs = append(evmrelayIDs, rid) keyOrder[key.String()] = ix } diff --git a/core/web/log_controller_test.go b/core/web/log_controller_test.go index dbb95361b98..28c54b72450 100644 --- a/core/web/log_controller_test.go +++ b/core/web/log_controller_test.go @@ -43,8 +43,8 @@ func TestLogController_GetLogConfig(t *testing.T) { client := app.NewHTTPClient(nil) - resp, err := client.HTTPClient.Get("/v2/log") - require.NoError(t, err) + resp, clean := client.Get("/v2/log") + t.Cleanup(clean) svcLogConfig := presenters.ServiceLogConfigResource{} cltest.AssertServerResponse(t, resp, http.StatusOK) diff --git a/core/web/loop_registry_test.go b/core/web/loop_registry_test.go index 94e2bc856d6..93eda32d0e8 100644 --- a/core/web/loop_registry_test.go +++ b/core/web/loop_registry_test.go @@ -7,6 +7,7 @@ import ( "net/http" "testing" + "github.com/hashicorp/consul/sdk/freeport" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/common/model" @@ -61,10 +62,10 @@ func (m *mockLoopImpl) run() { } func TestLoopRegistry(t *testing.T) { - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = &cltest.DefaultP2PPeerID }) app := cltest.NewApplicationWithConfigAndKey(t, cfg, cltest.DefaultP2PKey) diff --git a/core/web/ocr2_keys_controller_test.go b/core/web/ocr2_keys_controller_test.go index c7549cd2da5..815ae3ac20b 100644 --- a/core/web/ocr2_keys_controller_test.go +++ b/core/web/ocr2_keys_controller_test.go @@ -5,11 +5,11 @@ import ( "net/http" "testing" + "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/services/keystore/chaintype" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" diff --git a/core/web/ocr_keys_controller_test.go b/core/web/ocr_keys_controller_test.go index ebb671bc1e2..31422f47c0c 100644 --- a/core/web/ocr_keys_controller_test.go +++ b/core/web/ocr_keys_controller_test.go @@ -4,10 +4,10 @@ import ( "net/http" "testing" + "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/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" diff --git a/core/web/p2p_keys_controller.go b/core/web/p2p_keys_controller.go index c81400615b0..bbe9d83f741 100644 --- a/core/web/p2p_keys_controller.go +++ b/core/web/p2p_keys_controller.go @@ -29,6 +29,8 @@ func (p2pkc *P2PKeysController) Index(c *gin.Context) { jsonAPIResponse(c, presenters.NewP2PKeyResources(keys), "p2pKey") } +const keyType = "Ed25519" + // Create and return a P2P key // Example: // "POST /keys/p2p" @@ -44,7 +46,7 @@ func (p2pkc *P2PKeysController) Create(c *gin.Context) { "id": key.ID(), "p2pPublicKey": key.PublicKeyHex(), "p2pPeerID": key.PeerID(), - "p2pType": key.Type(), + "p2pType": keyType, }) jsonAPIResponse(c, presenters.NewP2PKeyResource(key), "p2pKey") } @@ -101,7 +103,7 @@ func (p2pkc *P2PKeysController) Import(c *gin.Context) { "id": key.ID(), "p2pPublicKey": key.PublicKeyHex(), "p2pPeerID": key.PeerID(), - "p2pType": key.Type(), + "p2pType": keyType, }) jsonAPIResponse(c, presenters.NewP2PKeyResource(key), "p2pKey") diff --git a/core/web/p2p_keys_controller_test.go b/core/web/p2p_keys_controller_test.go index af15e21a0f6..df6f556fcb8 100644 --- a/core/web/p2p_keys_controller_test.go +++ b/core/web/p2p_keys_controller_test.go @@ -5,11 +5,11 @@ import ( "net/http" "testing" + "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/services/keystore/keys/p2pkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" diff --git a/core/web/ping_controller_test.go b/core/web/ping_controller_test.go index 8e1862cd8c7..aa528ced534 100644 --- a/core/web/ping_controller_test.go +++ b/core/web/ping_controller_test.go @@ -55,7 +55,7 @@ func TestPingController_Show_ExternalInitiatorCredentials(t *testing.T) { require.NoError(t, err) url := app.Server.URL + "/v2/ping" - request, err := http.NewRequest("GET", url, nil) + request, err := http.NewRequestWithContext(testutils.Context(t), "GET", url, nil) require.NoError(t, err) request.Header.Set("Content-Type", web.MediaType) request.Header.Set("X-Chainlink-EA-AccessKey", eia.AccessKey) @@ -74,12 +74,15 @@ func TestPingController_Show_ExternalInitiatorCredentials(t *testing.T) { func TestPingController_Show_NoCredentials(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) client := clhttptest.NewTestLocalOnlyHTTPClient() url := app.Server.URL + "/v2/ping" - resp, err := client.Get(url) + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + require.NoError(t, err) + resp, err := client.Do(req) require.NoError(t, err) require.Equal(t, http.StatusUnauthorized, resp.StatusCode) } diff --git a/core/web/pipeline_runs_controller_test.go b/core/web/pipeline_runs_controller_test.go index c44ee9ae8da..3c57847d187 100644 --- a/core/web/pipeline_runs_controller_test.go +++ b/core/web/pipeline_runs_controller_test.go @@ -12,18 +12,19 @@ import ( "time" "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/pelletier/go-toml" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "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/job" "github.com/smartcontractkit/chainlink/v2/core/services/webhook" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" @@ -34,8 +35,8 @@ func TestPipelineRunsController_CreateWithBody_HappyPath(t *testing.T) { ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(2 * time.Second) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(2 * time.Second) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(10 * time.Millisecond) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) @@ -89,8 +90,8 @@ func TestPipelineRunsController_CreateNoBody_HappyPath(t *testing.T) { ethClient := cltest.NewEthMocksWithStartupAssertions(t) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.JobPipeline.HTTPRequest.DefaultTimeout = models.MustNewDuration(2 * time.Second) - c.Database.Listener.FallbackPollInterval = models.MustNewDuration(10 * time.Millisecond) + c.JobPipeline.HTTPRequest.DefaultTimeout = commonconfig.MustNewDuration(2 * time.Second) + c.Database.Listener.FallbackPollInterval = commonconfig.MustNewDuration(10 * time.Millisecond) }) app := cltest.NewApplicationWithConfig(t, cfg, ethClient) @@ -253,7 +254,8 @@ func setupPipelineRunsControllerTests(t *testing.T) (cltest.HTTPClientCleaner, i ethClient.On("PendingNonceAt", mock.Anything, mock.Anything).Return(uint64(0), nil) cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.OCR.Enabled = ptr(true) - c.P2P.V1.Enabled = ptr(true) + c.P2P.V2.Enabled = ptr(true) + c.P2P.V2.ListenAddresses = &[]string{fmt.Sprintf("127.0.0.1:%d", freeport.GetOne(t))} c.P2P.PeerID = &cltest.DefaultP2PPeerID c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) @@ -273,10 +275,7 @@ func setupPipelineRunsControllerTests(t *testing.T) (cltest.HTTPClientCleaner, i name = "%s" contractAddress = "%s" evmChainID = "0" - p2pBootstrapPeers = [ - "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju", - ] - p2pv2Bootstrappers = [] + p2pv2Bootstrappers = ["12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001"] keyBundleID = "%s" transmitterAddress = "%s" observationSource = """ diff --git a/core/web/presenters/check.go b/core/web/presenters/check.go index 52e4aa68005..4e1a2147a8c 100644 --- a/core/web/presenters/check.go +++ b/core/web/presenters/check.go @@ -1,5 +1,7 @@ package presenters +import "cmp" + type Check struct { JAID Name string `json:"name"` @@ -10,3 +12,7 @@ type Check struct { func (c Check) GetName() string { return "checks" } + +func CmpCheckName(a, b Check) int { + return cmp.Compare(a.Name, b.Name) +} diff --git a/core/web/presenters/eth_key.go b/core/web/presenters/eth_key.go index 3d952dabeda..d661d4334cd 100644 --- a/core/web/presenters/eth_key.go +++ b/core/web/presenters/eth_key.go @@ -5,22 +5,22 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // ETHKeyResource represents a ETH key JSONAPI resource. It holds the hex // representation of the address plus its ETH & LINK balances type ETHKeyResource struct { JAID - EVMChainID utils.Big `json:"evmChainID"` + EVMChainID big.Big `json:"evmChainID"` Address string `json:"address"` EthBalance *assets.Eth `json:"ethBalance"` LinkBalance *commonassets.Link `json:"linkBalance"` Disabled bool `json:"disabled"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - MaxGasPriceWei *utils.Big `json:"maxGasPriceWei"` + MaxGasPriceWei *big.Big `json:"maxGasPriceWei"` } // GetName implements the api2go EntityNamer interface @@ -69,7 +69,7 @@ func SetETHKeyLinkBalance(linkBalance *commonassets.Link) NewETHKeyOption { } } -func SetETHKeyMaxGasPriceWei(maxGasPriceWei *utils.Big) NewETHKeyOption { +func SetETHKeyMaxGasPriceWei(maxGasPriceWei *big.Big) NewETHKeyOption { return func(r *ETHKeyResource) { r.MaxGasPriceWei = maxGasPriceWei } diff --git a/core/web/presenters/eth_key_test.go b/core/web/presenters/eth_key_test.go index 85d005cf610..8be13de74a1 100644 --- a/core/web/presenters/eth_key_test.go +++ b/core/web/presenters/eth_key_test.go @@ -7,8 +7,8 @@ import ( commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/ethereum/go-ethereum/common" "github.com/manyminds/api2go/jsonapi" @@ -31,7 +31,7 @@ func TestETHKeyResource(t *testing.T) { state := ethkey.State{ ID: 1, - EVMChainID: *utils.NewBigI(42), + EVMChainID: *big.NewI(42), Address: eip55address, CreatedAt: now, UpdatedAt: now, @@ -41,12 +41,12 @@ func TestETHKeyResource(t *testing.T) { r := NewETHKeyResource(key, state, SetETHKeyEthBalance(assets.NewEth(1)), SetETHKeyLinkBalance(commonassets.NewLinkFromJuels(1)), - SetETHKeyMaxGasPriceWei(utils.NewBigI(12345)), + SetETHKeyMaxGasPriceWei(big.NewI(12345)), ) assert.Equal(t, assets.NewEth(1), r.EthBalance) assert.Equal(t, commonassets.NewLinkFromJuels(1), r.LinkBalance) - assert.Equal(t, utils.NewBigI(12345), r.MaxGasPriceWei) + assert.Equal(t, big.NewI(12345), r.MaxGasPriceWei) b, err := jsonapi.Marshal(r) require.NoError(t, err) diff --git a/core/web/presenters/eth_tx.go b/core/web/presenters/eth_tx.go index 2c2b5b90ff2..f944a99213f 100644 --- a/core/web/presenters/eth_tx.go +++ b/core/web/presenters/eth_tx.go @@ -8,7 +8,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // EthTxResource represents a Ethereum Transaction JSONAPI resource. @@ -25,7 +25,7 @@ type EthTxResource struct { SentAt string `json:"sentAt"` To *common.Address `json:"to"` Value string `json:"value"` - EVMChainID utils.Big `json:"evmChainID"` + EVMChainID big.Big `json:"evmChainID"` } // GetName implements the api2go EntityNamer interface @@ -50,7 +50,7 @@ func NewEthTxResource(tx txmgr.Tx) EthTxResource { } if tx.ChainID != nil { - r.EVMChainID = *utils.NewBig(tx.ChainID) + r.EVMChainID = *big.New(tx.ChainID) } return r } @@ -65,7 +65,7 @@ func NewEthTxResourceFromAttempt(txa txmgr.TxAttempt) EthTxResource { r.Hex = hexutil.Encode(txa.SignedRawTx) if txa.Tx.ChainID != nil { - r.EVMChainID = *utils.NewBig(txa.Tx.ChainID) + r.EVMChainID = *big.New(txa.Tx.ChainID) } if tx.Sequence != nil { diff --git a/core/web/presenters/evm_forwarder.go b/core/web/presenters/evm_forwarder.go index c91bfc088f1..43c27644850 100644 --- a/core/web/presenters/evm_forwarder.go +++ b/core/web/presenters/evm_forwarder.go @@ -6,14 +6,14 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) // EVMForwarderResource is an EVM forwarder JSONAPI resource. type EVMForwarderResource struct { JAID Address common.Address `json:"address"` - EVMChainID utils.Big `json:"evmChainId"` + EVMChainID big.Big `json:"evmChainId"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` } diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index dc5bf623330..d0a6cfb5ca9 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -8,7 +8,9 @@ import ( "gopkg.in/guregu/null.v4" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "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/keystore/keys/ethkey" @@ -16,7 +18,6 @@ import ( "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" ) // JobSpecType defines the the the spec type of the job @@ -49,7 +50,7 @@ type DirectRequestSpec struct { Initiator string `json:"initiator"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` } // NewDirectRequestSpec initializes a new DirectRequestSpec from a @@ -84,7 +85,7 @@ type FluxMonitorSpec struct { MinPayment *commonassets.Link `json:"minPayment"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` } // NewFluxMonitorSpec initializes a new DirectFluxMonitorSpec from a @@ -120,7 +121,6 @@ func NewFluxMonitorSpec(spec *job.FluxMonitorSpec) *FluxMonitorSpec { // OffChainReportingSpec defines the spec details of a OffChainReporting Job type OffChainReportingSpec struct { ContractAddress ethkey.EIP55Address `json:"contractAddress"` - P2PBootstrapPeers pq.StringArray `json:"p2pBootstrapPeers"` P2PV2Bootstrappers pq.StringArray `json:"p2pv2Bootstrappers"` IsBootstrapPeer bool `json:"isBootstrapPeer"` EncryptedOCRKeyBundleID *models.Sha256Hash `json:"keyBundleID"` @@ -132,7 +132,7 @@ type OffChainReportingSpec struct { ContractConfigConfirmations uint16 `json:"contractConfigConfirmations"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` DatabaseTimeout *models.Interval `json:"databaseTimeout"` ObservationGracePeriod *models.Interval `json:"observationGracePeriod"` ContractTransmitterTransmitTimeout *models.Interval `json:"contractTransmitterTransmitTimeout"` @@ -144,7 +144,6 @@ type OffChainReportingSpec struct { func NewOffChainReportingSpec(spec *job.OCROracleSpec) *OffChainReportingSpec { return &OffChainReportingSpec{ ContractAddress: spec.ContractAddress, - P2PBootstrapPeers: spec.P2PBootstrapPeers, P2PV2Bootstrappers: spec.P2PV2Bootstrappers, IsBootstrapPeer: spec.IsBootstrapPeer, EncryptedOCRKeyBundleID: spec.EncryptedOCRKeyBundleID, @@ -222,7 +221,7 @@ type KeeperSpec struct { FromAddress ethkey.EIP55Address `json:"fromAddress"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` } // NewKeeperSpec generates a new KeeperSpec from a job.KeeperSpec @@ -269,40 +268,46 @@ func NewCronSpec(spec *job.CronSpec) *CronSpec { type VRFSpec struct { BatchCoordinatorAddress *ethkey.EIP55Address `json:"batchCoordinatorAddress"` BatchFulfillmentEnabled bool `json:"batchFulfillmentEnabled"` + CustomRevertsPipelineEnabled *bool `json:"customRevertsPipelineEnabled,omitempty"` BatchFulfillmentGasMultiplier float64 `json:"batchFulfillmentGasMultiplier"` CoordinatorAddress ethkey.EIP55Address `json:"coordinatorAddress"` PublicKey secp256k1.PublicKey `json:"publicKey"` FromAddresses []ethkey.EIP55Address `json:"fromAddresses"` - PollPeriod models.Duration `json:"pollPeriod"` + PollPeriod commonconfig.Duration `json:"pollPeriod"` MinIncomingConfirmations uint32 `json:"confirmations"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` ChunkSize uint32 `json:"chunkSize"` - RequestTimeout models.Duration `json:"requestTimeout"` - BackoffInitialDelay models.Duration `json:"backoffInitialDelay"` - BackoffMaxDelay models.Duration `json:"backoffMaxDelay"` + RequestTimeout commonconfig.Duration `json:"requestTimeout"` + BackoffInitialDelay commonconfig.Duration `json:"backoffInitialDelay"` + BackoffMaxDelay commonconfig.Duration `json:"backoffMaxDelay"` GasLanePrice *assets.Wei `json:"gasLanePrice"` - VRFOwnerAddress *ethkey.EIP55Address `json:"vrfOwnerAddress"` + RequestedConfsDelay int64 `json:"requestedConfsDelay"` + VRFOwnerAddress *ethkey.EIP55Address `json:"vrfOwnerAddress,omitempty"` } func NewVRFSpec(spec *job.VRFSpec) *VRFSpec { return &VRFSpec{ - BatchCoordinatorAddress: spec.BatchCoordinatorAddress, - BatchFulfillmentEnabled: spec.BatchFulfillmentEnabled, - CoordinatorAddress: spec.CoordinatorAddress, - PublicKey: spec.PublicKey, - FromAddresses: spec.FromAddresses, - PollPeriod: models.MustMakeDuration(spec.PollPeriod), - MinIncomingConfirmations: spec.MinIncomingConfirmations, - CreatedAt: spec.CreatedAt, - UpdatedAt: spec.UpdatedAt, - EVMChainID: spec.EVMChainID, - ChunkSize: spec.ChunkSize, - RequestTimeout: models.MustMakeDuration(spec.RequestTimeout), - BackoffInitialDelay: models.MustMakeDuration(spec.BackoffInitialDelay), - BackoffMaxDelay: models.MustMakeDuration(spec.BackoffMaxDelay), - GasLanePrice: spec.GasLanePrice, + BatchCoordinatorAddress: spec.BatchCoordinatorAddress, + BatchFulfillmentEnabled: spec.BatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: float64(spec.BatchFulfillmentGasMultiplier), + CustomRevertsPipelineEnabled: &spec.CustomRevertsPipelineEnabled, + CoordinatorAddress: spec.CoordinatorAddress, + PublicKey: spec.PublicKey, + FromAddresses: spec.FromAddresses, + PollPeriod: *commonconfig.MustNewDuration(spec.PollPeriod), + MinIncomingConfirmations: spec.MinIncomingConfirmations, + CreatedAt: spec.CreatedAt, + UpdatedAt: spec.UpdatedAt, + EVMChainID: spec.EVMChainID, + ChunkSize: spec.ChunkSize, + RequestTimeout: *commonconfig.MustNewDuration(spec.RequestTimeout), + BackoffInitialDelay: *commonconfig.MustNewDuration(spec.BackoffInitialDelay), + BackoffMaxDelay: *commonconfig.MustNewDuration(spec.BackoffMaxDelay), + GasLanePrice: spec.GasLanePrice, + RequestedConfsDelay: spec.RequestedConfsDelay, + VRFOwnerAddress: spec.VRFOwnerAddress, } } @@ -319,7 +324,7 @@ type BlockhashStoreSpec struct { TrustedBlockhashStoreBatchSize int32 `json:"trustedBlockhashStoreBatchSize"` PollPeriod time.Duration `json:"pollPeriod"` RunTimeout time.Duration `json:"runTimeout"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` FromAddresses []ethkey.EIP55Address `json:"fromAddresses"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` @@ -355,7 +360,7 @@ type BlockHeaderFeederSpec struct { BatchBlockhashStoreAddress ethkey.EIP55Address `json:"batchBlockhashStoreAddress"` PollPeriod time.Duration `json:"pollPeriod"` RunTimeout time.Duration `json:"runTimeout"` - EVMChainID *utils.Big `json:"evmChainID"` + EVMChainID *big.Big `json:"evmChainID"` FromAddresses []ethkey.EIP55Address `json:"fromAddresses"` GetBlockhashesBatchSize uint16 `json:"getBlockhashesBatchSize"` StoreBlockhashesBatchSize uint16 `json:"storeBlockhashesBatchSize"` @@ -508,6 +513,8 @@ func NewJobResource(j job.Job) *JobResource { resource.BootstrapSpec = NewBootstrapSpec(j.BootstrapSpec) case job.Gateway: resource.GatewaySpec = NewGatewaySpec(j.GatewaySpec) + case job.Stream: + // no spec; nothing to do case job.LegacyGasStationServer, job.LegacyGasStationSidecar: // unsupported } diff --git a/core/web/presenters/job_test.go b/core/web/presenters/job_test.go index 7e997c899c5..b782452948b 100644 --- a/core/web/presenters/job_test.go +++ b/core/web/presenters/job_test.go @@ -14,12 +14,14 @@ import ( "gopkg.in/guregu/null.v4" "github.com/smartcontractkit/chainlink-common/pkg/assets" + evmassets "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "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/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" + "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -29,7 +31,7 @@ func TestJob(t *testing.T) { contractAddress, err := ethkey.NewEIP55Address("0x9E40733cC9df84636505f4e6Db28DCa0dC5D1bba") require.NoError(t, err) cronSchedule := "0 0 0 1 1 *" - evmChainID := utils.NewBigI(42) + evmChainID := big.NewI(42) fromAddress, err := ethkey.NewEIP55Address("0xa8037A20989AFcBC51798de9762b351D63ff462e") require.NoError(t, err) @@ -58,6 +60,7 @@ func TestJob(t *testing.T) { trustedBlockhashStoreBatchSize := int32(20) var specGasLimit uint32 = 1000 + vrfPubKey, _ := secp256k1.NewPublicKeyFromHex("0xede539e216e3a50e69d1c68aa9cc472085876c4002f6e1e6afee0ea63b50a78b00") testCases := []struct { name string @@ -212,7 +215,6 @@ func TestJob(t *testing.T) { ID: 1, OCROracleSpec: &job.OCROracleSpec{ ContractAddress: contractAddress, - P2PBootstrapPeers: pq.StringArray{"/dns4/chain.link/tcp/1234/p2p/xxx"}, P2PV2Bootstrappers: pq.StringArray{"xxx:5001"}, IsBootstrapPeer: true, EncryptedOCRKeyBundleID: &ocrKeyID, @@ -259,7 +261,6 @@ func TestJob(t *testing.T) { }, "offChainReportingOracleSpec": { "contractAddress": "%s", - "p2pBootstrapPeers": ["/dns4/chain.link/tcp/1234/p2p/xxx"], "p2pv2Bootstrappers": ["xxx:5001"], "isBootstrapPeer": true, "keyBundleID": "%s", @@ -471,6 +472,90 @@ func TestJob(t *testing.T) { } }`, }, + { + name: "vrf job spec", + job: job.Job{ + ID: 1, + Name: null.StringFrom("vrf_test"), + Type: job.VRF, + SchemaVersion: 1, + ExternalJobID: uuid.MustParse("0eec7e1d-d0d2-476c-a1a8-72dfb6633f47"), + VRFSpec: &job.VRFSpec{ + BatchCoordinatorAddress: &contractAddress, + BatchFulfillmentEnabled: true, + CustomRevertsPipelineEnabled: true, + MinIncomingConfirmations: 1, + CoordinatorAddress: contractAddress, + CreatedAt: timestamp, + UpdatedAt: timestamp, + EVMChainID: evmChainID, + FromAddresses: []ethkey.EIP55Address{fromAddress}, + PublicKey: vrfPubKey, + RequestedConfsDelay: 10, + ChunkSize: 25, + BatchFulfillmentGasMultiplier: 1, + GasLanePrice: evmassets.GWei(200), + VRFOwnerAddress: nil, + }, + PipelineSpec: &pipeline.Spec{ + ID: 1, + DotDagSource: "", + }, + }, + want: fmt.Sprintf(` + { + "data": { + "type": "jobs", + "id": "1", + "attributes": { + "name": "vrf_test", + "type": "vrf", + "schemaVersion": 1, + "maxTaskDuration": "0s", + "externalJobID": "0eec7e1d-d0d2-476c-a1a8-72dfb6633f47", + "directRequestSpec": null, + "fluxMonitorSpec": null, + "gasLimit": null, + "forwardingAllowed": false, + "cronSpec": null, + "offChainReportingOracleSpec": null, + "offChainReporting2OracleSpec": null, + "keeperSpec": null, + "vrfSpec": { + "batchCoordinatorAddress": "%s", + "batchFulfillmentEnabled": true, + "customRevertsPipelineEnabled": true, + "confirmations": 1, + "coordinatorAddress": "%s", + "createdAt": "2000-01-01T00:00:00Z", + "updatedAt": "2000-01-01T00:00:00Z", + "evmChainID": "42", + "fromAddresses": ["%s"], + "pollPeriod": "0s", + "publicKey": "%s", + "requestedConfsDelay": 10, + "requestTimeout": "0s", + "chunkSize": 25, + "batchFulfillmentGasMultiplier": 1, + "backoffInitialDelay": "0s", + "backoffMaxDelay": "0s", + "gasLanePrice": "200 gwei" + }, + "webhookSpec": null, + "blockhashStoreSpec": null, + "blockHeaderFeederSpec": null, + "bootstrapSpec": null, + "pipelineSpec": { + "id": 1, + "jobID": 0, + "dotDagSource": "" + }, + "gatewaySpec": null, + "errors": [] + } + } + }`, contractAddress, contractAddress, fromAddress, vrfPubKey.String()), + }, { name: "blockhash store spec", job: job.Job{ @@ -486,7 +571,7 @@ func TestJob(t *testing.T) { BlockhashStoreAddress: contractAddress, PollPeriod: 25 * time.Second, RunTimeout: 10 * time.Second, - EVMChainID: utils.NewBigI(4), + EVMChainID: big.NewI(4), FromAddresses: []ethkey.EIP55Address{fromAddress}, TrustedBlockhashStoreAddress: &trustedBlockhashStoreAddress, TrustedBlockhashStoreBatchSize: trustedBlockhashStoreBatchSize, @@ -566,7 +651,7 @@ func TestJob(t *testing.T) { BatchBlockhashStoreAddress: batchBHSAddress, PollPeriod: 25 * time.Second, RunTimeout: 10 * time.Second, - EVMChainID: utils.NewBigI(4), + EVMChainID: big.NewI(4), FromAddresses: []ethkey.EIP55Address{fromAddress}, GetBlockhashesBatchSize: 5, StoreBlockhashesBatchSize: 10, diff --git a/core/web/presenters/p2p_key_test.go b/core/web/presenters/p2p_key_test.go index 2d30f87fe18..4e7b4e954fd 100644 --- a/core/web/presenters/p2p_key_test.go +++ b/core/web/presenters/p2p_key_test.go @@ -1,7 +1,6 @@ package presenters import ( - "encoding/hex" "fmt" "testing" @@ -16,9 +15,6 @@ func TestP2PKeyResource(t *testing.T) { key := keystest.NewP2PKeyV2(t) peerID := key.PeerID() peerIDStr := peerID.String() - pubKey := key.GetPublic() - pubKeyBytes, err := pubKey.Raw() - require.NoError(t, err) r := NewP2PKeyResource(key) b, err := jsonapi.Marshal(r) @@ -34,7 +30,7 @@ func TestP2PKeyResource(t *testing.T) { "publicKey": "%s" } } - }`, key.ID(), peerIDStr, hex.EncodeToString(pubKeyBytes)) + }`, key.ID(), peerIDStr, key.PublicKeyHex()) assert.JSONEq(t, expected, string(b)) @@ -52,7 +48,7 @@ func TestP2PKeyResource(t *testing.T) { "publicKey": "%s" } } - }`, key.ID(), peerIDStr, hex.EncodeToString(pubKeyBytes)) + }`, key.ID(), peerIDStr, key.PublicKeyHex()) assert.JSONEq(t, expected, string(b)) } diff --git a/core/web/presenters/user.go b/core/web/presenters/user.go index 19ccff960ac..7598c8864be 100644 --- a/core/web/presenters/user.go +++ b/core/web/presenters/user.go @@ -32,7 +32,7 @@ func NewUserResource(u sessions.User) *UserResource { return &UserResource{ JAID: NewJAID(u.Email), Email: u.Email, - Role: sessions.UserRole(u.Role), + Role: u.Role, HasActiveApiToken: hasToken, CreatedAt: u.CreatedAt, UpdatedAt: u.UpdatedAt, diff --git a/core/web/replay_controller.go b/core/web/replay_controller.go index 5006b68c845..84c54e3836e 100644 --- a/core/web/replay_controller.go +++ b/core/web/replay_controller.go @@ -7,8 +7,8 @@ import ( "github.com/gin-gonic/gin" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type ReplayController struct { @@ -64,14 +64,14 @@ func (bdc *ReplayController) ReplayFromBlock(c *gin.Context) { response := ReplayResponse{ Message: "Replay started", - EVMChainID: utils.NewBig(chainID), + EVMChainID: big.New(chainID), } jsonAPIResponse(c, &response, "response") } type ReplayResponse struct { - Message string `json:"message"` - EVMChainID *utils.Big `json:"evmChainID"` + Message string `json:"message"` + EVMChainID *big.Big `json:"evmChainID"` } // GetID returns the jsonapi ID. diff --git a/core/web/resolver/chain_test.go b/core/web/resolver/chain_test.go index c3cafd329b4..700963cd4da 100644 --- a/core/web/resolver/chain_test.go +++ b/core/web/resolver/chain_test.go @@ -9,12 +9,12 @@ import ( "github.com/stretchr/testify/require" evmtoml "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" - "github.com/smartcontractkit/chainlink/v2/core/utils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) func TestResolver_Chains(t *testing.T) { var ( - chainID = *utils.NewBigI(1) + chainID = *big.NewI(1) query = ` query GetChains { chains { @@ -100,7 +100,7 @@ ResendAfterThreshold = '1h0m0s' func TestResolver_Chain(t *testing.T) { var ( - chainID = *utils.NewBigI(1) + chainID = *big.NewI(1) query = ` query GetChain { chain(id: "1") { diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index ea106a4b30c..1874e4c68e0 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -14,12 +14,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/mocks" "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/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) type mockEvmConfig struct { @@ -80,13 +80,13 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.MustEIP55Address(address.Hex()), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), }, } - chainID := *utils.NewBigI(12) + chainID := *big.NewI(12) linkAddr := common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") cfg := configtest.NewGeneralConfig(t, nil) @@ -139,13 +139,13 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.MustEIP55Address(address.Hex()), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), }, } - chainID := *utils.NewBigI(12) + chainID := *big.NewI(12) f.Mocks.legacyEVMChains.On("Get", states[0].EVMChainID.String()).Return(nil, evmrelay.ErrNoChains) f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) f.Mocks.ethKs.On("Get", keys[0].Address.Hex()).Return(keys[0], nil) @@ -225,7 +225,7 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.MustEIP55Address(address.Hex()), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), @@ -257,7 +257,7 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.MustEIP55Address(address.Hex()), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), @@ -288,13 +288,13 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.MustEIP55Address(address.Hex()), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), }, } - chainID := *utils.NewBigI(12) + chainID := *big.NewI(12) linkAddr := common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) @@ -342,13 +342,13 @@ func TestResolver_ETHKeys(t *testing.T) { states := []ethkey.State{ { Address: ethkey.EIP55AddressFromAddress(address), - EVMChainID: *utils.NewBigI(12), + EVMChainID: *big.NewI(12), Disabled: false, CreatedAt: f.Timestamp(), UpdatedAt: f.Timestamp(), }, } - chainID := *utils.NewBigI(12) + chainID := *big.NewI(12) linkAddr := common.HexToAddress("0x5431F5F973781809D18643b87B44921b11355d81") f.Mocks.ethKs.On("GetStatesForKeys", keys).Return(states, nil) diff --git a/core/web/resolver/eth_transaction_test.go b/core/web/resolver/eth_transaction_test.go index a719c838e81..238aa9d1679 100644 --- a/core/web/resolver/eth_transaction_test.go +++ b/core/web/resolver/eth_transaction_test.go @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/utils" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" ) func TestResolver_EthTransaction(t *testing.T) { @@ -54,7 +54,7 @@ func TestResolver_EthTransaction(t *testing.T) { "hash": "0x5431F5F973781809D18643b87B44921b11355d81", } hash := common.HexToHash("0x5431F5F973781809D18643b87B44921b11355d81") - chainID := *utils.NewBigI(22) + chainID := *ubig.NewI(22) gError := errors.New("error") testCases := []GQLTestCase{ diff --git a/core/web/resolver/mutation.go b/core/web/resolver/mutation.go index 990a6c08058..996b3859a55 100644 --- a/core/web/resolver/mutation.go +++ b/core/web/resolver/mutation.go @@ -640,12 +640,13 @@ func (r *Resolver) CreateP2PKey(ctx context.Context) (*CreateP2PKeyPayloadResolv return nil, err } + const keyType = "Ed25519" r.App.GetAuditLogger().Audit(audit.KeyCreated, map[string]interface{}{ "type": "p2p", "id": key.ID(), "p2pPublicKey": key.PublicKeyHex(), "p2pPeerID": key.PeerID(), - "p2pType": key.Type(), + "p2pType": keyType, }) return NewCreateP2PKeyPayload(key), nil diff --git a/core/web/resolver/node_test.go b/core/web/resolver/node_test.go index 24a31b986f1..7f4e69ac4ae 100644 --- a/core/web/resolver/node_test.go +++ b/core/web/resolver/node_test.go @@ -6,18 +6,18 @@ import ( gqlerrors "github.com/graph-gophers/graphql-go/errors" "github.com/pkg/errors" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/types" "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/services/chainlink" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestResolver_Nodes(t *testing.T) { t.Parallel() var ( - chainID = *utils.NewBigI(1) + chainID = *big.NewI(1) query = ` query GetNodes { @@ -124,8 +124,8 @@ func Test_NodeQuery(t *testing.T) { f.App.On("EVMORM").Return(f.Mocks.evmORM) f.Mocks.evmORM.PutChains(toml.EVMConfig{Nodes: []*toml.Node{{ Name: &name, - WSURL: models.MustParseURL("ws://some-url"), - HTTPURL: models.MustParseURL("http://some-url"), + WSURL: commonconfig.MustParseURL("ws://some-url"), + HTTPURL: commonconfig.MustParseURL("http://some-url"), Order: ptr(int32(11)), }}}) }, diff --git a/core/web/resolver/spec.go b/core/web/resolver/spec.go index c9ee5199229..b1cb32783f9 100644 --- a/core/web/resolver/spec.go +++ b/core/web/resolver/spec.go @@ -421,17 +421,6 @@ func (r *OCRSpecResolver) ObservationTimeout() *string { return &timeout } -// P2PBootstrapPeers resolves the spec's p2p bootstrap peers -func (r *OCRSpecResolver) P2PBootstrapPeers() *[]string { - if len(r.spec.P2PBootstrapPeers) == 0 { - return nil - } - - peers := []string(r.spec.P2PBootstrapPeers) - - return &peers -} - // P2PV2Bootstrappers resolves the OCR1 spec's p2pv2 bootstrappers func (r *OCRSpecResolver) P2PV2Bootstrappers() *[]string { if len(r.spec.P2PV2Bootstrappers) == 0 { @@ -532,7 +521,7 @@ func (r *OCR2SpecResolver) P2PV2Bootstrappers() *[]string { // Relay resolves the spec's relay func (r *OCR2SpecResolver) Relay() string { - return string(r.spec.Relay) + return r.spec.Relay } // RelayConfig resolves the spec's relay config @@ -652,6 +641,11 @@ func (r *VRFSpecResolver) BatchFulfillmentGasMultiplier() float64 { return float64(r.spec.BatchFulfillmentGasMultiplier) } +// CustomRevertsPipelineEnabled resolves the spec's custom reverts pipeline enabled flag. +func (r *VRFSpecResolver) CustomRevertsPipelineEnabled() *bool { + return &r.spec.CustomRevertsPipelineEnabled +} + // ChunkSize resolves the spec's chunk size. func (r *VRFSpecResolver) ChunkSize() int32 { return int32(r.spec.ChunkSize) @@ -905,7 +899,7 @@ func (r *BootstrapSpecResolver) ContractID() string { // Relay resolves the spec's relay func (r *BootstrapSpecResolver) Relay() string { - return string(r.spec.Relay) + return r.spec.Relay } // RelayConfig resolves the spec's relay config diff --git a/core/web/resolver/spec_test.go b/core/web/resolver/spec_test.go index 4de66f1dcb1..828e8538071 100644 --- a/core/web/resolver/spec_test.go +++ b/core/web/resolver/spec_test.go @@ -13,13 +13,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + 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/keystore/keys/ethkey" "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" ) // Specs are only embedded on the job and are not fetchable by it's own id, so @@ -95,7 +95,7 @@ func TestResolver_DirectRequestSpec(t *testing.T) { DirectRequestSpec: &job.DirectRequestSpec{ ContractAddress: contractAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), MinIncomingConfirmations: clnull.NewUint32(1, true), MinContractPayment: commonassets.NewLinkFromJuels(1000), Requesters: models.AddressCollection{requesterAddress}, @@ -160,13 +160,13 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { FluxMonitorSpec: &job.FluxMonitorSpec{ ContractAddress: contractAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), DrumbeatEnabled: false, IdleTimerDisabled: false, - IdleTimerPeriod: time.Duration(1 * time.Hour), + IdleTimerPeriod: 1 * time.Hour, MinPayment: commonassets.NewLinkFromJuels(1000), PollTimerDisabled: false, - PollTimerPeriod: time.Duration(1 * time.Minute), + PollTimerPeriod: 1 * time.Minute, }, }, nil) }, @@ -227,15 +227,15 @@ func TestResolver_FluxMonitorSpec(t *testing.T) { FluxMonitorSpec: &job.FluxMonitorSpec{ ContractAddress: contractAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), DrumbeatEnabled: true, - DrumbeatRandomDelay: time.Duration(1 * time.Second), + DrumbeatRandomDelay: 1 * time.Second, DrumbeatSchedule: "CRON_TZ=UTC 0 0 1 1 *", IdleTimerDisabled: true, - IdleTimerPeriod: time.Duration(1 * time.Hour), + IdleTimerPeriod: 1 * time.Hour, MinPayment: commonassets.NewLinkFromJuels(1000), PollTimerDisabled: true, - PollTimerPeriod: time.Duration(1 * time.Minute), + PollTimerPeriod: 1 * time.Minute, }, }, nil) }, @@ -310,7 +310,7 @@ func TestResolver_KeeperSpec(t *testing.T) { KeeperSpec: &job.KeeperSpec{ ContractAddress: contractAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), FromAddress: ethkey.EIP55AddressFromAddress(fromAddress), }, }, nil) @@ -381,11 +381,10 @@ func TestResolver_OCRSpec(t *testing.T) { ObservationGracePeriod: models.NewInterval(4 * time.Second), ContractTransmitterTransmitTimeout: models.NewInterval(555 * time.Millisecond), CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), IsBootstrapPeer: false, EncryptedOCRKeyBundleID: &keyBundleID, ObservationTimeout: models.Interval(2 * time.Minute), - P2PBootstrapPeers: pq.StringArray{"/dns4/test.com/tcp/2001/p2pkey"}, P2PV2Bootstrappers: pq.StringArray{"12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw@localhost:5001"}, TransmitterAddress: &transmitterAddress, }, @@ -411,7 +410,6 @@ func TestResolver_OCRSpec(t *testing.T) { isBootstrapPeer keyBundleID observationTimeout - p2pBootstrapPeers p2pv2Bootstrappers transmitterAddress } @@ -438,7 +436,6 @@ func TestResolver_OCRSpec(t *testing.T) { "isBootstrapPeer": false, "keyBundleID": "f5bf259689b26f1374efb3c9a9868796953a0f814bb2d39b968d0e61b58620a5", "observationTimeout": "2m0s", - "p2pBootstrapPeers": ["/dns4/test.com/tcp/2001/p2pkey"], "p2pv2Bootstrappers": ["12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw@localhost:5001"], "transmitterAddress": "0x3cCad4715152693fE3BC4460591e3D3Fbd071b42" } @@ -584,10 +581,11 @@ func TestResolver_VRFSpec(t *testing.T) { VRFSpec: &job.VRFSpec{ BatchCoordinatorAddress: &batchCoordinatorAddress, BatchFulfillmentEnabled: true, + CustomRevertsPipelineEnabled: true, MinIncomingConfirmations: 1, CoordinatorAddress: coordinatorAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), FromAddresses: []ethkey.EIP55Address{fromAddress1, fromAddress2}, PollPeriod: 1 * time.Minute, PublicKey: pubKey, @@ -620,6 +618,7 @@ func TestResolver_VRFSpec(t *testing.T) { batchCoordinatorAddress batchFulfillmentEnabled batchFulfillmentGasMultiplier + customRevertsPipelineEnabled chunkSize backoffInitialDelay backoffMaxDelay @@ -647,6 +646,7 @@ func TestResolver_VRFSpec(t *testing.T) { "batchCoordinatorAddress": "0x0ad9FE7a58216242a8475ca92F222b0640E26B63", "batchFulfillmentEnabled": true, "batchFulfillmentGasMultiplier": 1, + "customRevertsPipelineEnabled": true, "chunkSize": 25, "backoffInitialDelay": "1m0s", "backoffMaxDelay": "1h0m0s", @@ -748,7 +748,7 @@ func TestResolver_BlockhashStoreSpec(t *testing.T) { CoordinatorV2Address: &coordinatorV2Address, CoordinatorV2PlusAddress: &coordinatorV2PlusAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), FromAddresses: []ethkey.EIP55Address{fromAddress1, fromAddress2}, PollPeriod: 1 * time.Minute, RunTimeout: 37 * time.Second, @@ -852,7 +852,7 @@ func TestResolver_BlockHeaderFeederSpec(t *testing.T) { CoordinatorV2Address: &coordinatorV2Address, CoordinatorV2PlusAddress: &coordinatorV2PlusAddress, CreatedAt: f.Timestamp(), - EVMChainID: utils.NewBigI(42), + EVMChainID: ubig.NewI(42), FromAddresses: []ethkey.EIP55Address{fromAddress}, PollPeriod: 1 * time.Minute, RunTimeout: 37 * time.Second, diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index 2531e7c281d..148f6b24ff5 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -40,8 +40,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false @@ -161,19 +159,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -240,3 +225,6 @@ TLSCertPath = '' LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' + +[Mercury.TLS] +CertFile = '' diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index e98f8602a0c..67ddbb33efd 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -40,8 +40,6 @@ MaxBatchSize = 4321 SendInterval = '1m0s' SendTimeout = '5s' UseBatchSend = true -URL = '' -ServerPubKey = '' [[TelemetryIngress.Endpoints]] Network = 'EVM' @@ -167,19 +165,6 @@ OutgoingMessageBufferSize = 17 PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' TraceLogging = true -[P2P.V1] -Enabled = true -AnnounceIP = '1.2.3.4' -AnnouncePort = 1234 -BootstrapCheckInterval = '1m0s' -DefaultBootstrapPeers = ['foo', 'bar', 'should', 'these', 'be', 'typed'] -DHTAnnouncementCounterUserPrefix = 4321 -DHTLookupInterval = 9 -ListenIP = '4.3.2.1' -ListenPort = 9 -NewStreamTimeout = '1s' -PeerstoreWriteInterval = '1m0s' - [P2P.V2] Enabled = false AnnounceAddresses = ['a', 'b', 'c'] @@ -251,6 +236,9 @@ LatestReportTTL = '1m40s' MaxStaleAge = '1m41s' LatestReportDeadline = '1m42s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' Enabled = false diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index 74d83035cd5..bd64ae04812 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -40,8 +40,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = true @@ -161,19 +159,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -241,6 +226,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/core/web/router.go b/core/web/router.go index 28bd4f2170c..6401622e192 100644 --- a/core/web/router.go +++ b/core/web/router.go @@ -32,6 +32,7 @@ import ( mgin "github.com/ulule/limiter/v3/drivers/middleware/gin" "github.com/ulule/limiter/v3/drivers/store/memory" "github.com/unrolled/secure" + "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -60,6 +61,7 @@ func NewRouter(app chainlink.Application, prometheus *ginprom.Prometheus) (*gin. tls := config.WebServer().TLS() engine.Use( + otelgin.Middleware("chainlink-web-routes"), limits.RequestSizeLimiter(config.WebServer().HTTPMaxSize()), loggerFunc(app.GetLogger()), gin.Recovery(), @@ -215,6 +217,9 @@ func healthRoutes(app chainlink.Application, r *gin.RouterGroup) { hc := HealthController{app} r.GET("/readyz", hc.Readyz) r.GET("/health", hc.Health) + r.GET("/health.txt", func(context *gin.Context) { + context.Request.Header.Set("Accept", gin.MIMEPlain) + }, hc.Health) } func loopRoutes(app chainlink.Application, r *gin.RouterGroup) { diff --git a/core/web/router_test.go b/core/web/router_test.go index 18177a1ac28..bb371318468 100644 --- a/core/web/router_test.go +++ b/core/web/router_test.go @@ -20,14 +20,18 @@ import ( ) func TestTokenAuthRequired_NoCredentials(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) defer ts.Close() - resp, err := http.Post(ts.URL+"/v2/jobs/", web.MediaType, bytes.NewBufferString("{}")) + req, err := http.NewRequestWithContext(ctx, "POST", ts.URL+"/v2/jobs/", bytes.NewBufferString("{}")) + require.NoError(t, err) + req.Header.Set("Content-Type", web.MediaType) + resp, err := http.DefaultClient.Do(req) require.NoError(t, err) assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) @@ -49,8 +53,9 @@ func TestTokenAuthRequired_SessionCredentials(t *testing.T) { } func TestTokenAuthRequired_TokenCredentials(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) @@ -67,7 +72,7 @@ func TestTokenAuthRequired_TokenCredentials(t *testing.T) { err = app.BridgeORM().CreateExternalInitiator(ea) require.NoError(t, err) - request, err := http.NewRequest("GET", ts.URL+"/v2/ping/", bytes.NewBufferString("{}")) + request, err := http.NewRequestWithContext(ctx, "GET", ts.URL+"/v2/ping/", bytes.NewBufferString("{}")) require.NoError(t, err) request.Header.Set("Content-Type", web.MediaType) request.Header.Set("X-Chainlink-EA-AccessKey", eia.AccessKey) @@ -81,8 +86,9 @@ func TestTokenAuthRequired_TokenCredentials(t *testing.T) { } func TestTokenAuthRequired_BadTokenCredentials(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) @@ -99,7 +105,7 @@ func TestTokenAuthRequired_BadTokenCredentials(t *testing.T) { err = app.BridgeORM().CreateExternalInitiator(ea) require.NoError(t, err) - request, err := http.NewRequest("GET", ts.URL+"/v2/ping/", bytes.NewBufferString("{}")) + request, err := http.NewRequestWithContext(ctx, "GET", ts.URL+"/v2/ping/", bytes.NewBufferString("{}")) require.NoError(t, err) request.Header.Set("Content-Type", web.MediaType) request.Header.Set("X-Chainlink-EA-AccessKey", eia.AccessKey) @@ -113,8 +119,9 @@ func TestTokenAuthRequired_BadTokenCredentials(t *testing.T) { } func TestSessions_RateLimited(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) @@ -124,7 +131,7 @@ func TestSessions_RateLimited(t *testing.T) { input := `{"email":"brute@force.com", "password": "wrongpassword"}` for i := 0; i < 5; i++ { - request, err := http.NewRequest("POST", ts.URL+"/sessions", bytes.NewBufferString(input)) + request, err := http.NewRequestWithContext(ctx, "POST", ts.URL+"/sessions", bytes.NewBufferString(input)) require.NoError(t, err) resp, err := client.Do(request) @@ -132,7 +139,7 @@ func TestSessions_RateLimited(t *testing.T) { assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) } - request, err := http.NewRequest("POST", ts.URL+"/sessions", bytes.NewBufferString(input)) + request, err := http.NewRequestWithContext(ctx, "POST", ts.URL+"/sessions", bytes.NewBufferString(input)) require.NoError(t, err) resp, err := client.Do(request) @@ -141,8 +148,9 @@ func TestSessions_RateLimited(t *testing.T) { } func TestRouter_LargePOSTBody(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) @@ -151,7 +159,7 @@ func TestRouter_LargePOSTBody(t *testing.T) { client := clhttptest.NewTestLocalOnlyHTTPClient() body := string(make([]byte, 70000)) - request, err := http.NewRequest("POST", ts.URL+"/sessions", bytes.NewBufferString(body)) + request, err := http.NewRequestWithContext(ctx, "POST", ts.URL+"/sessions", bytes.NewBufferString(body)) require.NoError(t, err) resp, err := client.Do(request) @@ -160,13 +168,16 @@ func TestRouter_LargePOSTBody(t *testing.T) { } func TestRouter_GinHelmetHeaders(t *testing.T) { + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) router := web.Router(t, app, nil) ts := httptest.NewServer(router) defer ts.Close() - res, err := http.Get(ts.URL) + req, err := http.NewRequestWithContext(ctx, "GET", ts.URL, nil) + require.NoError(t, err) + res, err := http.DefaultClient.Do(req) require.NoError(t, err) for _, tt := range []struct { HelmetName string diff --git a/core/web/schema/type/spec.graphql b/core/web/schema/type/spec.graphql index 98203a1870e..5e24f7c3fa8 100644 --- a/core/web/schema/type/spec.graphql +++ b/core/web/schema/type/spec.graphql @@ -60,7 +60,6 @@ type OCRSpec { isBootstrapPeer: Boolean! keyBundleID: String observationTimeout: String - p2pBootstrapPeers: [String!] p2pv2Bootstrappers: [String!] transmitterAddress: String databaseTimeout: String! @@ -98,6 +97,7 @@ type VRFSpec { batchCoordinatorAddress: String batchFulfillmentEnabled: Boolean! batchFulfillmentGasMultiplier: Float! + customRevertsPipelineEnabled: Boolean chunkSize: Int! backoffInitialDelay: String! backoffMaxDelay: String! diff --git a/core/web/sessions_controller_test.go b/core/web/sessions_controller_test.go index c2950caf3d1..9f883ef54b8 100644 --- a/core/web/sessions_controller_test.go +++ b/core/web/sessions_controller_test.go @@ -22,6 +22,7 @@ import ( func TestSessionsController_Create(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) @@ -44,7 +45,7 @@ func TestSessionsController_Create(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { body := fmt.Sprintf(`{"email":"%s","password":"%s"}`, test.email, test.password) - request, err := http.NewRequest("POST", app.Server.URL+"/sessions", bytes.NewBufferString(body)) + request, err := http.NewRequestWithContext(ctx, "POST", app.Server.URL+"/sessions", bytes.NewBufferString(body)) assert.NoError(t, err) resp, err := client.Do(request) assert.NoError(t, err) @@ -86,8 +87,9 @@ func mustInsertSession(t *testing.T, q pg.Q, session *sessions.Session) { func TestSessionsController_Create_ReapSessions(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) - require.NoError(t, app.Start(testutils.Context(t))) + require.NoError(t, app.Start(ctx)) user := cltest.MustRandomUser(t) require.NoError(t, app.AuthenticationProvider().CreateUser(&user)) @@ -99,7 +101,10 @@ func TestSessionsController_Create_ReapSessions(t *testing.T) { mustInsertSession(t, q, &staleSession) body := fmt.Sprintf(`{"email":"%s","password":"%s"}`, user.Email, cltest.Password) - resp, err := http.Post(app.Server.URL+"/sessions", "application/json", bytes.NewBufferString(body)) + req, err := http.NewRequestWithContext(ctx, "POST", app.Server.URL+"/sessions", bytes.NewBufferString(body)) + assert.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + resp, err := http.DefaultClient.Do(req) assert.NoError(t, err) defer func() { assert.NoError(t, resp.Body.Close()) }() @@ -119,6 +124,7 @@ func TestSessionsController_Create_ReapSessions(t *testing.T) { func TestSessionsController_Destroy(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) app := cltest.NewApplicationEVMDisabled(t) require.NoError(t, app.Start(testutils.Context(t))) @@ -143,7 +149,7 @@ func TestSessionsController_Destroy(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { cookie := cltest.MustGenerateSessionCookie(t, test.sessionID) - request, err := http.NewRequest("DELETE", app.Server.URL+"/sessions", nil) + request, err := http.NewRequestWithContext(ctx, "DELETE", app.Server.URL+"/sessions", nil) assert.NoError(t, err) request.AddCookie(cookie) @@ -163,6 +169,7 @@ func TestSessionsController_Destroy(t *testing.T) { func TestSessionsController_Destroy_ReapSessions(t *testing.T) { t.Parallel() + ctx := testutils.Context(t) client := clhttptest.NewTestLocalOnlyHTTPClient() app := cltest.NewApplicationEVMDisabled(t) @@ -183,7 +190,7 @@ func TestSessionsController_Destroy_ReapSessions(t *testing.T) { staleSession.LastUsed = time.Now().Add(-cltest.MustParseDuration(t, "241h")) mustInsertSession(t, q, &staleSession) - request, err := http.NewRequest("DELETE", app.Server.URL+"/sessions", nil) + request, err := http.NewRequestWithContext(ctx, "DELETE", app.Server.URL+"/sessions", nil) assert.NoError(t, err) request.AddCookie(cookie) diff --git a/core/web/solana_keys_controller_test.go b/core/web/solana_keys_controller_test.go index 3dfbcfd252a..94b11207c92 100644 --- a/core/web/solana_keys_controller_test.go +++ b/core/web/solana_keys_controller_test.go @@ -5,10 +5,10 @@ import ( "net/http" "testing" + "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/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" diff --git a/core/web/solana_transfer_controller.go b/core/web/solana_transfer_controller.go index f9a2c627932..70218080a87 100644 --- a/core/web/solana_transfer_controller.go +++ b/core/web/solana_transfer_controller.go @@ -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: relay.ChainID(tr.SolanaChainID)} + relayerID := relay.ID{Network: relay.Solana, ChainID: tr.SolanaChainID} relayer, err := relayers.Get(relayerID) if err != nil { if errors.Is(err, chainlink.ErrNoSuchRelayer) { diff --git a/core/web/starknet_keys_controller_test.go b/core/web/starknet_keys_controller_test.go index a633b4f16c9..9215fb8f9c5 100644 --- a/core/web/starknet_keys_controller_test.go +++ b/core/web/starknet_keys_controller_test.go @@ -5,10 +5,10 @@ import ( "net/http" "testing" + "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/utils" "github.com/smartcontractkit/chainlink/v2/core/web" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" diff --git a/core/web/testdata/body/health.html b/core/web/testdata/body/health.html new file mode 100644 index 00000000000..d1b208f4a0d --- /dev/null +++ b/core/web/testdata/body/health.html @@ -0,0 +1,101 @@ + +
+ EVM +
+ 0 +
+ BalanceMonitor +
+
+ HeadBroadcaster +
+
+ HeadTracker +
+ HeadListener +
Listener is not connected
+
+
+
+ LogBroadcaster +
+
+ Txm +
+ BlockHistoryEstimator +
+
+ Broadcaster +
+
+ Confirmer +
+
+ WrappedEvmEstimator +
+
+
+
+
+ JobSpawner +
+
+ Mailbox +
+ Monitor +
+
+
+ Mercury +
+ WSRPCPool +
+ CacheSet +
+
+
+
+ PipelineORM +
+
+ PipelineRunner +
+
+ PromReporter +
+
+ TelemetryManager +
\ No newline at end of file diff --git a/core/web/testdata/body/health.json b/core/web/testdata/body/health.json new file mode 100644 index 00000000000..3c0117de7ec --- /dev/null +++ b/core/web/testdata/body/health.json @@ -0,0 +1,175 @@ +{ + "data": [ + { + "type": "checks", + "id": "EVM.0", + "attributes": { + "name": "EVM.0", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.BalanceMonitor", + "attributes": { + "name": "EVM.0.BalanceMonitor", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.HeadBroadcaster", + "attributes": { + "name": "EVM.0.HeadBroadcaster", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.HeadTracker", + "attributes": { + "name": "EVM.0.HeadTracker", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.HeadTracker.HeadListener", + "attributes": { + "name": "EVM.0.HeadTracker.HeadListener", + "status": "failing", + "output": "Listener is not connected" + } + }, + { + "type": "checks", + "id": "EVM.0.LogBroadcaster", + "attributes": { + "name": "EVM.0.LogBroadcaster", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.Txm", + "attributes": { + "name": "EVM.0.Txm", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.Txm.BlockHistoryEstimator", + "attributes": { + "name": "EVM.0.Txm.BlockHistoryEstimator", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.Txm.Broadcaster", + "attributes": { + "name": "EVM.0.Txm.Broadcaster", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.Txm.Confirmer", + "attributes": { + "name": "EVM.0.Txm.Confirmer", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.0.Txm.WrappedEvmEstimator", + "attributes": { + "name": "EVM.0.Txm.WrappedEvmEstimator", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "JobSpawner", + "attributes": { + "name": "JobSpawner", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Mailbox.Monitor", + "attributes": { + "name": "Mailbox.Monitor", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Mercury.WSRPCPool", + "attributes": { + "name": "Mercury.WSRPCPool", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Mercury.WSRPCPool.CacheSet", + "attributes": { + "name": "Mercury.WSRPCPool.CacheSet", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PipelineORM", + "attributes": { + "name": "PipelineORM", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PipelineRunner", + "attributes": { + "name": "PipelineRunner", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PromReporter", + "attributes": { + "name": "PromReporter", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "TelemetryManager", + "attributes": { + "name": "TelemetryManager", + "status": "passing", + "output": "" + } + } + ] +} \ No newline at end of file diff --git a/core/web/testdata/body/health.txt b/core/web/testdata/body/health.txt new file mode 100644 index 00000000000..59f63c26413 --- /dev/null +++ b/core/web/testdata/body/health.txt @@ -0,0 +1,20 @@ +-EVM.0 +-EVM.0.BalanceMonitor +-EVM.0.HeadBroadcaster +-EVM.0.HeadTracker +!EVM.0.HeadTracker.HeadListener + Listener is not connected +-EVM.0.LogBroadcaster +-EVM.0.Txm +-EVM.0.Txm.BlockHistoryEstimator +-EVM.0.Txm.Broadcaster +-EVM.0.Txm.Confirmer +-EVM.0.Txm.WrappedEvmEstimator +-JobSpawner +-Mailbox.Monitor +-Mercury.WSRPCPool +-Mercury.WSRPCPool.CacheSet +-PipelineORM +-PipelineRunner +-PromReporter +-TelemetryManager diff --git a/core/web/testdata/health.html b/core/web/testdata/health.html new file mode 100644 index 00000000000..3c007bef96f --- /dev/null +++ b/core/web/testdata/health.html @@ -0,0 +1,67 @@ + +
+ foo +
+ bar +
example error message
+
+ 1 +
+ A +
+
+ B +
+
+
+ 2 +
error:
+this is a multi-line error:
+new line:
+original error
+
+ A +
failure!
+
+
+ B +
+
+
+
+ baz +
+
\ No newline at end of file diff --git a/core/web/testdata/health.txt b/core/web/testdata/health.txt new file mode 100644 index 00000000000..f155d6c0212 --- /dev/null +++ b/core/web/testdata/health.txt @@ -0,0 +1,15 @@ +-foo +!foo.bar + example error message +-foo.bar.1 +-foo.bar.1.A +-foo.bar.1.B +!foo.bar.2 + error: + this is a multi-line error: + new line: + original error +!foo.bar.2.A + failure! +-foo.bar.2.B +-foo.baz diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a74a199231f..19e50b87a23 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -13,6 +13,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 +## 2.9.1 - 2024-03-07 + +### Changed + +- `eth_call` RPC requests are now sent with both `input` and `data` fields to increase compatibility with servers that recognize only one. +- GasEstimator will now include Type `0x3` (Blob) transactions in the gas calculations to estimate it more accurately. + +## 2.9.0 - 2024-02-22 + +### Added + +- `chainlink health` CLI command and HTML `/health` endpoint, to provide human-readable views of the underlying JSON health data. +- New job type `stream` to represent streamspecs. This job type is not yet used anywhere but will be required for Data Streams V1. +- Environment variables `CL_MEDIAN_ENV`, `CL_SOLANA_ENV`, and `CL_STARKNET_ENV` for setting environment variables in LOOP Plugins with an `.env` file. + ``` + echo "Foo=Bar" >> median.env + echo "Baz=Val" >> median.env + CL_MEDIAN_ENV="median.env" + ``` + +### Fixed + +- Fixed the encoding used for transactions when resending in batches + +### Removed + +- `P2P.V1` is no longer supported and must not be set in TOML configuration in order to boot. Use `P2P.V2` instead. If you are using both, `V1` can simply be removed. +- Removed `TelemetryIngress.URL` and `TelemetryIngress.ServerPubKey` from TOML configuration, these fields are replaced by `[[TelemetryIngress.Endpoints]]`: +```toml + [[TelemetryIngress.Endpoints]] + Network = '...' # e.g. EVM. Solana, Starknet, Cosmos + ChainID = '...' # e.g. 1, 5, devnet, mainnet-beta + URL = '...' + ServerPubKey = '...' +``` + ## 2.8.0 - 2024-01-24 ### Added @@ -59,7 +95,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Two new prom metrics for mercury, nops should consider adding alerting on these: - `mercury_insufficient_blocks_count` - `mercury_zero_blocks_count` - +- Added new `Mercury.TLS` TOML config field `CertFile` for configuring transport credentials when the node acts as a client and initiates a TLS handshake. + ### Changed - `PromReporter` no longer directly reads txm related status from the db, and instead uses the txStore API. diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 3568abe7a0e..2c98a41c7bf 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -244,8 +244,6 @@ LeaseRefreshInterval determines how often to refresh the lease lock. Also contro [TelemetryIngress] UniConn = true # Default Logging = false # Default -ServerPubKey = 'test-pub-key' # Example -URL = 'https://prom.test' # Example BufferSize = 100 # Default MaxBatchSize = 50 # Default SendInterval = '500ms' # Default @@ -266,18 +264,6 @@ Logging = false # Default ``` Logging toggles verbose logging of the raw telemetry messages being sent. -### ServerPubKey -```toml -ServerPubKey = 'test-pub-key' # Example -``` -ServerPubKey is the public key of the telemetry server. This field will be removed in a furture version - -### URL -```toml -URL = 'https://prom.test' # Example -``` -URL is where to send telemetry. This field will be removed in a furture version - ### BufferSize ```toml BufferSize = 100 # Default @@ -1109,13 +1095,7 @@ OutgoingMessageBufferSize = 10 # Default PeerID = '12D3KooWMoejJznyDuEk5aX6GvbjaG12UzeornPCBNzMRqdwrFJw' # Example TraceLogging = false # Default ``` -P2P supports multiple networking stack versions. You may configure `[P2P.V1]`, `[P2P.V2]`, or both to run simultaneously. -If both are configured, then for each link with another peer, V2 networking will be preferred. If V2 does not work, the link will -automatically fall back to V1. If V2 starts working again later, it will automatically be preferred again. This is useful -for migrating networks without downtime. Note that the two networking stacks _must not_ be configured to bind to the same IP/port. - -Note: P2P.V1 is deprecated will be removed in the future. - +P2P has a versioned networking stack. Currenly only `[P2P.V2]` is supported. All nodes in the OCR network should share the same networking stack. ### IncomingMessageBufferSize @@ -1149,108 +1129,6 @@ TraceLogging = false # Default ``` TraceLogging enables trace level logging. -## P2P.V1 -```toml -[P2P.V1] -Enabled = false # Default -AnnounceIP = '1.2.3.4' # Example -AnnouncePort = 1337 # Example -BootstrapCheckInterval = '20s' # Default -DefaultBootstrapPeers = ['/dns4/example.com/tcp/1337/p2p/12D3KooWMHMRLQkgPbFSYHwD3NBuwtS1AmxhvKVUrcfyaGDASR4U', '/ip4/1.2.3.4/tcp/9999/p2p/12D3KooWLZ9uTC3MrvKfDpGju6RAQubiMDL7CuJcAgDRTYP7fh7R'] # Example -DHTAnnouncementCounterUserPrefix = 0 # Default -DHTLookupInterval = 10 # Default -ListenIP = '0.0.0.0' # Default -ListenPort = 1337 # Example -NewStreamTimeout = '10s' # Default -PeerstoreWriteInterval = '5m' # Default -``` -P2P.V1 is deprecated and will be removed in a future version. - -### Enabled -```toml -Enabled = false # Default -``` -Enabled enables P2P V1. - -### AnnounceIP -```toml -AnnounceIP = '1.2.3.4' # Example -``` -AnnounceIP should be set as the externally reachable IP address of the Chainlink node. - -### AnnouncePort -```toml -AnnouncePort = 1337 # Example -``` -AnnouncePort should be set as the externally reachable port of the Chainlink node. - -### BootstrapCheckInterval -```toml -BootstrapCheckInterval = '20s' # Default -``` -BootstrapCheckInterval is the interval at which nodes check connections to bootstrap nodes and reconnect if any of them is lost. -Setting this to a small value would allow newly joined bootstrap nodes to get more connectivity -more quickly, which helps to make bootstrap process faster. The cost of this operation is relatively -cheap. We set this to 1 minute during our test. - -### DefaultBootstrapPeers -```toml -DefaultBootstrapPeers = ['/dns4/example.com/tcp/1337/p2p/12D3KooWMHMRLQkgPbFSYHwD3NBuwtS1AmxhvKVUrcfyaGDASR4U', '/ip4/1.2.3.4/tcp/9999/p2p/12D3KooWLZ9uTC3MrvKfDpGju6RAQubiMDL7CuJcAgDRTYP7fh7R'] # Example -``` -DefaultBootstrapPeers is the default set of bootstrap peers. - -### DHTAnnouncementCounterUserPrefix -```toml -DHTAnnouncementCounterUserPrefix = 0 # Default -``` -DHTAnnouncementCounterUserPrefix can be used to restore the node's -ability to announce its IP/port on the P2P network after a database -rollback. Make sure to only increase this value, and *never* decrease it. -Don't use this variable unless you really know what you're doing, since you -could semi-permanently exclude your node from the P2P network by -misconfiguring it. - -### DHTLookupInterval -:warning: **_ADVANCED_**: _Do not change this setting unless you know what you are doing._ -```toml -DHTLookupInterval = 10 # Default -``` -DHTLookupInterval is the interval between which we do the expensive peer -lookup using DHT. - -Every DHTLookupInterval failures to open a stream to a peer, we will -attempt to lookup its IP from DHT - -### ListenIP -```toml -ListenIP = '0.0.0.0' # Default -``` -ListenIP is the default IP address to bind to. - -### ListenPort -```toml -ListenPort = 1337 # Example -``` -ListenPort is the port to listen on. If left blank, the node randomly selects a different port each time it boots. It is highly recommended to set this to a static value to avoid network instability. - -### NewStreamTimeout -:warning: **_ADVANCED_**: _Do not change this setting unless you know what you are doing._ -```toml -NewStreamTimeout = '10s' # Default -``` -NewStreamTimeout is the maximum length of time to wait to open a -stream before we give up. -We shouldn't hit this in practice since libp2p will give up fast if -it can't get a connection, but it is here anyway as a failsafe. -Set to 0 to disable any timeout on top of what libp2p gives us by default. - -### PeerstoreWriteInterval -:warning: **_ADVANCED_**: _Do not change this setting unless you know what you are doing._ -```toml -PeerstoreWriteInterval = '5m' # Default -``` -PeerstoreWriteInterval controls how often the peerstore for the OCR V1 networking stack is persisted to the database. - ## P2P.V2 ```toml [P2P.V2] @@ -1697,6 +1575,19 @@ LatestReportDeadline = "5s" # Default LatestReportDeadline controls how long to wait for a response from the mercury server before retrying. Setting this to zero will wait indefinitely. +## Mercury.TLS +```toml +[Mercury.TLS] +CertFile = "/path/to/client/certs.pem" # Example +``` +Mercury.TLS controls client settings for when the node talks to traditional web servers or load balancers. + +### CertFile +```toml +CertFile = "/path/to/client/certs.pem" # Example +``` +CertFile is the path to a PEM file of trusted root certificate authority certificates + ## EVM EVM defaults depend on ChainID: @@ -5109,6 +5000,7 @@ GasLimit = 14500000 AutoCreateKey = true BlockBackfillDepth = 10 BlockBackfillSkip = false +ChainType = 'scroll' FinalityDepth = 1 FinalityTagEnabled = false LogBackfillBatchSize = 1000 @@ -5189,6 +5081,7 @@ GasLimit = 5300000 AutoCreateKey = true BlockBackfillDepth = 10 BlockBackfillSkip = false +ChainType = 'scroll' FinalityDepth = 1 FinalityTagEnabled = false LogBackfillBatchSize = 1000 @@ -5543,7 +5436,7 @@ BlockBackfillSkip enables skipping of very long backfills. ChainType = 'arbitrum' # Example ``` ChainType is automatically detected from chain ID. Set this to force a certain chain type regardless of chain ID. -Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix, zksync +Available types: arbitrum, metis, optimismBedrock, xdai, celo, kroma, wemix, zksync, scroll ### FinalityDepth ```toml diff --git a/docs/Mercury.md b/docs/Mercury.md new file mode 100644 index 00000000000..82835c9519a --- /dev/null +++ b/docs/Mercury.md @@ -0,0 +1,251 @@ +# Mercury Documentation + +## Useful Links + +[Configuration Builder](https://github.com/smartcontractkit/the-most-amazing-mercury-contract-configuration-tool) + +[Contracts](https://github.com/smartcontractkit/chainlink/contracts/src/v0.8/llo-feeds) + +[OCR3 Config Documentation](https://github.com/smartcontractkit/libocr/blob/master/offchainreporting2plus/internal/config/ocr3config/public_config.go) + + + + +### Example Feed Configuration + +```json +{ + "feedId": "0x14e044f932bb959cc2aa8dc1ba110c09224e639aae00264c1ffc2a0830904a3c", + "chainId": 42161, // source chain id + "contractAddress": "0x14e044f932bb959cc2aa8dc1ba110c09224e639a", // verifier contract address + "configCount": 1, // the index of this config + "signers": [ + "0x000....01", + "0x000....02", + "0x000....03", + "0x000....04" + ], // NOP signing addresses, + "transmitters": [ + "0x000....11", + "0x000....12", + "0x000....13", + "0x000....14" + ], // NOP transmitter addresses + "offchainConfig": { + "baseUSDFee": "0.1", // 10c base fee to verify the report + "deltaCertifiedCommitRequest": "1s", + "deltaGrace": "0s", + "deltaInitial": "600ms", + "deltaProgress": "2s", + "deltaResend": "10s", + "deltaRound": "250ms", + "deltaStage": "0s", + "expirationWindow": "86400", //window in in which a report can be verified in seconds + "f": 3, + "maxDurationObservation": "250ms", + "maxDurationQuery": "50ms", + "maxDurationShouldAcceptAttestedReport": "50ms", + "maxDurationShouldTransmitAcceptedReport": "50ms", + "rMax": "25", + "s": [ + 4 + ] + }, + "offchainConfigVersion": 30, + "onchainConfig": { + "max": "99999999999999999999999999999", + "min": "1" + } +} +``` + +## Jobs + +### Bootstrap + +**🚨 Important config** + +`relayConfig.chainID` - target chain id. (the chain we pull block numbers from) + +`contractID` - the contract address of the verifier contract. + +
Example bootstrap TOML + +```toml +type = "bootstrap" +relay = "evm" +schemaVersion = 1 +name = "$feed_name" +contractID = "$verifier_contract_address" +feedID = "$feed_id" # IMPORTANT - DON'T FORGET THIS OR IT WON'T WORK +contractConfigTrackerPollInterval = "15s" + +[relayConfig] +chainID = $evm_chain_id +fromBlock = $from_block +``` +
+ +### OCR2 + +
Example OCR2 Mercury TOML + +```toml +type = "offchainreporting2" +schemaVersion = 1 +name = "$feed_name" +forwardingAllowed = false +maxTaskDuration = "1s" +contractID = "$verifier_contract_address" +feedID = "$feed_id" +contractConfigTrackerPollInterval = "15s" +ocrKeyBundleID = "$key_bundle_id" +p2pv2Bootstrappers = [ + "$bootstrapper_address>" +] +relay = "evm" +pluginType = "mercury" +transmitterID = "$csa_public_key" + +observationSource = """ + // ncfx + ds1_payload [type=bridge name="ncfx" timeout="50ms" requestData="{\\"data\\":{\\"endpoint\\":\\"crypto-lwba\\",\\"from\\":\\"ETH\\",\\"to\\":\\"USD\\"}}"]; + ds1_median [type=jsonparse path="data,mid"]; + ds1_bid [type=jsonparse path="data,bid"]; + ds1_ask [type=jsonparse path="data,ask"]; + + ds1_median_multiply [type=multiply times=100000000]; + ds1_bid_multiply [type=multiply times=100000000]; + ds1_ask_multiply [type=multiply times=100000000]; + + // tiingo + ds2_payload [type=bridge name="tiingo" timeout="50ms" requestData="{\\"data\\":{\\"endpoint\\":\\"crypto-lwba\\",\\"from\\":\\"ETH\\",\\"to\\":\\"USD\\"}}"]; + ds2_median [type=jsonparse path="data,mid"]; + ds2_bid [type=jsonparse path="data,bid"]; + ds2_ask [type=jsonparse path="data,ask"]; + + ds2_median_multiply [type=multiply times=100000000]; + ds2_bid_multiply [type=multiply times=100000000]; + ds2_ask_multiply [type=multiply times=100000000]; + + // coinmetrics + ds3_payload [type=bridge name="coinmetrics" timeout="50ms" requestData="{\\"data\\":{\\"endpoint\\":\\"crypto-lwba\\",\\"from\\":\\"ETH\\",\\"to\\":\\"USD\\"}}"]; + ds3_median [type=jsonparse path="data,mid"]; + ds3_bid [type=jsonparse path="data,bid"]; + ds3_ask [type=jsonparse path="data,ask"]; + + ds3_median_multiply [type=multiply times=100000000]; + ds3_bid_multiply [type=multiply times=100000000]; + ds3_ask_multiply [type=multiply times=100000000]; + + ds1_payload -> ds1_median -> ds1_median_multiply -> benchmark_price; + ds2_payload -> ds2_median -> ds2_median_multiply -> benchmark_price; + ds3_payload -> ds3_median -> ds3_median_multiply -> benchmark_price; + + benchmark_price [type=median allowedFaults=2 index=0]; + + ds1_payload -> ds1_bid -> ds1_bid_multiply -> bid_price; + ds2_payload -> ds2_bid -> ds2_bid_multiply -> bid_price; + ds3_payload -> ds3_bid -> ds3_bid_multiply -> bid_price; + + bid_price [type=median allowedFaults=2 index=1]; + + ds1_payload -> ds1_ask -> ds1_ask_multiply -> ask_price; + ds2_payload -> ds2_ask -> ds2_ask_multiply -> ask_price; + ds3_payload -> ds3_ask -> ds3_ask_multiply -> ask_price; + + ask_price [type=median allowedFaults=2 index=2]; +""" + +[pluginConfig] +serverURL = "$mercury_server_url" +serverPubKey = "$mercury_server_public_key" + +[relayConfig] +chainID = $evm_chain_id +fromBlock = $from_block +``` +
+ +## Nodes + +**🚨 Important config** + +`OCR2.Enabled` - must be `true` - Mercury uses OCR2. + +`P2P.V2.Enabled` - required in order for OCR2 to work. + +`Feature.LogPoller` - required in order for OCR2 to work. You will get fatal errors if not set. + +`JobPipeline.MaxSuccessfulRuns` - set to `0` to disable saving pipeline runs to reduce load on the db. Obviously this means you won’t see anything in the UI. + +`TelemetryIngress.SendInterval` - How frequently to send telemetry batches. Mercury generates a lot of telemetry data due to the throughput. `100ms` has been tested for a single feed with 5 nodes - this will need to be monitored (along with relevant config) as we add more feeds to a node. + +`Database` - **must** increase connection limits above the standard defaults + +
Example node config TOML + +```toml +RootDir = '$ROOT_DIR' + +[JobPipeline] +MaxSuccessfulRuns = 0 # you may set to some small value like '10' or similar if you like looking at job runs in the UI + +[Feature] +UICSAKeys = true # required +LogPoller = true # required + +[Log] +Level = 'info' # this should be 'debug' for chainlink internal deployments, nops may use 'info' to reduce log volume + +[Log.File] +< standard values > + +[WebServer] +< standard values > + +[WebServer.TLS] +< standard values > + +[[EVM]] +ChainID = '42161' # change as needed based on target chain + +[OCR] +Enabled = false # turn off OCR 1 + +[P2P] +TraceLogging = false # this should be 'true' for chainlink internal deployments, we may ask nops to set this to true for debugging +PeerID = '$PEERID' + +[P2P.V2] +Enabled = true # required +DefaultBootstrappers = < mercury bootstrap nodes > # Note that this should ideally be set in the job spec, this is just a fallback +# Make sure these IPs are properly configured in the firewall. May not be necessary for internal nodes +AnnounceAddresses = ['$EXTERNAL_IP:$EXTERNAL_PORT'] # Use whichever port you like, pls randomize, MAKE SURE ITS CONFIGURED IN THE FIREWALL +ListenAddresses = ['0.0.0.0:$INTERNAL_PORT'] # Use whichever port you like, pls randomize, MAKE SURE ITS CONFIGURED IN THE FIREWALL + +[OCR2] +Enabled = true # required +KeyBundleID = '$KEY_BUNDLE_ID' # Note that this should ideally be set in the job spec, this is just a fallback +CaptureEATelemetry = true + +[TelemetryIngress] +UniConn = false +SendInterval = '250ms' +BufferSize = 300 +MaxBatchSize = 100 + +[[TelemetryIngress.Endpoints]] +Network = 'EVM' +ChainID = '42161' # change as needed based on target chain +URL = '$TELEMETRY_ENDPOINT_URL' # Provided by Chainlink Labs RSTP team +ServerPubKey = '$TELEMETRY_PUB_KEY' # Provided by Chainlink Labs RSTP team + +[Database] +MaxIdleConns = 100 # should equal or greater than total number of mercury jobs +MaxOpenConns = 400 # caution! ensure postgres is configured to support this + +[[EVM.Nodes]] +< put RPC nodes here > +``` +
diff --git a/go.md b/go.md new file mode 100644 index 00000000000..2a893c2a55e --- /dev/null +++ b/go.md @@ -0,0 +1,66 @@ +# smartcontractkit Go modules +```mermaid +flowchart LR + subgraph chains + chainlink-cosmos + chainlink-evm + chainlink-solana + chainlink-starknet/relayer + end + + subgraph products + chainlink-automation + chainlink-ccip + chainlink-data-streams + chainlink-feeds + chainlink-functions + chainlink-vrf + end + + classDef outline stroke-dasharray:6,fill:none; + class chains,products outline + + chainlink/v2 --> caigo + click caigo href "https://github.com/smartcontractkit/caigo" + chainlink/v2 --> chainlink-automation + click chainlink-automation href "https://github.com/smartcontractkit/chainlink-automation" + chainlink/v2 --> chainlink-common + click chainlink-common href "https://github.com/smartcontractkit/chainlink-common" + chainlink/v2 --> chainlink-cosmos + click chainlink-cosmos href "https://github.com/smartcontractkit/chainlink-cosmos" + chainlink/v2 --> chainlink-data-streams + click chainlink-data-streams href "https://github.com/smartcontractkit/chainlink-data-streams" + chainlink/v2 --> chainlink-feeds + click chainlink-feeds href "https://github.com/smartcontractkit/chainlink-feeds" + chainlink/v2 --> chainlink-solana + click chainlink-solana href "https://github.com/smartcontractkit/chainlink-solana" + chainlink/v2 --> chainlink-starknet/relayer + click chainlink-starknet/relayer href "https://github.com/smartcontractkit/chainlink-starknet" + chainlink/v2 --> chainlink-vrf + click chainlink-vrf href "https://github.com/smartcontractkit/chainlink-vrf" + chainlink/v2 --> libocr + click libocr href "https://github.com/smartcontractkit/libocr" + chainlink/v2 --> tdh2/go/ocr2/decryptionplugin + click tdh2/go/ocr2/decryptionplugin href "https://github.com/smartcontractkit/tdh2" + chainlink/v2 --> tdh2/go/tdh2 + click tdh2/go/tdh2 href "https://github.com/smartcontractkit/tdh2" + chainlink/v2 --> wsrpc + click wsrpc href "https://github.com/smartcontractkit/wsrpc" + chainlink-automation --> chainlink-common + chainlink-automation --> libocr + chainlink-common --> libocr + chainlink-cosmos --> chainlink-common + chainlink-cosmos --> libocr + chainlink-data-streams --> chainlink-common + chainlink-data-streams --> libocr + chainlink-feeds --> chainlink-common + chainlink-feeds --> libocr + chainlink-solana --> chainlink-common + chainlink-solana --> libocr + chainlink-starknet/relayer --> caigo + chainlink-starknet/relayer --> chainlink-common + chainlink-starknet/relayer --> libocr + chainlink-vrf --> libocr + tdh2/go/ocr2/decryptionplugin --> libocr + tdh2/go/ocr2/decryptionplugin --> tdh2/go/tdh2 +``` diff --git a/go.mod b/go.mod index 0343f4e7159..cbcad20919f 100644 --- a/go.mod +++ b/go.mod @@ -3,27 +3,28 @@ module github.com/smartcontractkit/chainlink/v2 go 1.21.3 require ( - github.com/Depado/ginprom v1.7.11 + github.com/Depado/ginprom v1.8.0 github.com/Masterminds/semver/v3 v3.2.1 github.com/Masterminds/sprig/v3 v3.2.3 github.com/avast/retry-go/v4 v4.5.1 - github.com/btcsuite/btcd v0.23.4 + github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/cometbft/cometbft v0.37.2 github.com/cosmos/cosmos-sdk v0.47.4 github.com/danielkov/gin-helmet v0.0.0-20171108135313-1387e224435e github.com/esote/minmaxheap v1.0.0 - github.com/ethereum/go-ethereum v1.12.0 + 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/getsentry/sentry-go v0.19.0 - github.com/gin-contrib/cors v1.4.0 + github.com/gin-contrib/cors v1.5.0 github.com/gin-contrib/expvar v0.0.1 github.com/gin-contrib/sessions v0.0.5 github.com/gin-contrib/size v0.0.0-20230212012657-e14a14094dc4 github.com/gin-gonic/gin v1.9.1 - github.com/go-webauthn/webauthn v0.9.1 - github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 + 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/gorilla/securecookie v1.1.2 github.com/gorilla/sessions v1.2.2 @@ -32,64 +33,65 @@ require ( github.com/graph-gophers/dataloader v5.0.0+incompatible github.com/graph-gophers/graphql-go v1.3.0 github.com/hashicorp/consul/sdk v0.14.1 + github.com/hashicorp/go-envparse v0.1.0 github.com/hashicorp/go-plugin v1.5.2 github.com/hdevalence/ed25519consensus v0.1.0 github.com/jackc/pgconn v1.14.1 github.com/jackc/pgtype v1.14.0 github.com/jackc/pgx/v4 v4.18.1 + github.com/jmoiron/sqlx v1.3.5 github.com/jpillora/backoff v1.0.0 github.com/kylelemons/godebug v1.1.0 github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a github.com/lib/pq v1.10.9 - github.com/libp2p/go-libp2p-core v0.8.5 - github.com/libp2p/go-libp2p-peerstore v0.2.7 github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.5.0 github.com/mr-tron/base58 v1.2.0 - github.com/multiformats/go-multiaddr v0.3.3 github.com/olekukonko/tablewriter v0.0.5 github.com/onsi/gomega v1.30.0 github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pelletier/go-toml v1.9.5 - github.com/pelletier/go-toml/v2 v2.1.0 + github.com/pelletier/go-toml/v2 v2.1.1 github.com/pkg/errors v0.9.1 github.com/pressly/goose/v3 v3.16.0 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_model v0.5.0 github.com/prometheus/common v0.45.0 - github.com/prometheus/prometheus v0.48.0 + github.com/prometheus/prometheus v0.48.1 github.com/robfig/cron/v3 v3.0.1 github.com/rogpeppe/go-internal v1.11.0 github.com/scylladb/go-reflectx v1.0.1 - github.com/shirou/gopsutil/v3 v3.23.10 + github.com/shirou/gopsutil/v3 v3.23.11 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 - github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 - github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 + github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240124161023-948579cbaffa + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 - github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 + github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 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/spf13/cast v1.5.1 + github.com/spf13/cast v1.6.0 github.com/stretchr/testify v1.8.4 github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a github.com/tidwall/gjson v1.17.0 - github.com/ugorji/go/codec v1.2.11 + github.com/ugorji/go/codec v1.2.12 github.com/ulule/limiter/v3 v3.11.2 github.com/umbracle/ethgo v0.1.3 github.com/unrolled/secure v1.13.0 github.com/urfave/cli v1.22.14 go.dedis.ch/fixbuf v1.0.3 go.dedis.ch/kyber/v3 v3.1.0 + go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.16.0 + golang.org/x/crypto v0.17.0 golang.org/x/exp v0.0.0-20231127185646-65229373498e golang.org/x/sync v0.5.0 golang.org/x/term v0.15.0 @@ -101,11 +103,10 @@ require ( google.golang.org/protobuf v1.31.0 gopkg.in/guregu/null.v2 v2.1.2 gopkg.in/guregu/null.v4 v4.0.0 - gopkg.in/natefinch/lumberjack.v2 v2.0.0 + gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( - cloud.google.com/go/compute v1.23.3 // indirect contrib.go.opencensus.io/exporter/stackdriver v0.13.5 // indirect cosmossdk.io/api v0.3.1 // indirect cosmossdk.io/core v0.5.1 // indirect @@ -121,27 +122,31 @@ require ( github.com/CosmWasm/wasmvm v1.2.4 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/VictoriaMetrics/fastcache v1.10.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // 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/btcsuite/btcd/btcec/v2 v2.3.2 // indirect - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/bytedance/sonic v1.9.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 github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect + github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect github.com/cockroachdb/redact v1.1.3 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft-db v0.7.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.2 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect @@ -151,9 +156,10 @@ require ( github.com/cosmos/ics23/go v0.9.1-0.20221207100636-b1abd8678aab // indirect github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect + github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/deckarep/golang-set/v2 v2.3.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 // indirect @@ -163,33 +169,33 @@ require ( github.com/docker/distribution v2.8.2+incompatible // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.5.0 // indirect - github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect + 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/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 github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-ldap/ldap/v3 v3.4.5 github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/x v0.1.4 // indirect + github.com/go-playground/validator/v10 v10.15.5 // indirect + github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gofrs/uuid v4.3.1+incompatible // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang-jwt/jwt/v5 v5.1.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect @@ -199,7 +205,6 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/gopacket v1.1.19 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect @@ -210,79 +215,33 @@ require ( github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect + github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.2 // indirect + github.com/holiman/uint256 v1.2.4 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect - github.com/huin/goupnp v1.0.3 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/ipfs/go-cid v0.0.7 // indirect - github.com/ipfs/go-datastore v0.4.5 // indirect - github.com/ipfs/go-ipfs-util v0.0.2 // indirect - github.com/ipfs/go-ipns v0.0.2 // indirect - github.com/ipfs/go-log v1.0.4 // indirect - github.com/ipfs/go-log/v2 v2.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgproto3/v2 v2.3.2 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/jbenet/goprocess v0.1.4 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/jmoiron/sqlx v1.3.5 github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.2 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect - github.com/koron/go-ssdp v0.0.2 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.2.4 // indirect - github.com/libp2p/go-addr-util v0.0.2 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-conn-security-multistream v0.2.0 // indirect - github.com/libp2p/go-eventbus v0.2.1 // indirect - github.com/libp2p/go-flow-metrics v0.0.3 // indirect - github.com/libp2p/go-libp2p v0.13.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 // indirect - github.com/libp2p/go-libp2p-autonat v0.4.0 // indirect - github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect - github.com/libp2p/go-libp2p-circuit v0.4.0 // indirect - github.com/libp2p/go-libp2p-discovery v0.5.0 // indirect - github.com/libp2p/go-libp2p-kad-dht v0.11.1 // indirect - github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect - github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect - github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect - github.com/libp2p/go-libp2p-nat v0.0.6 // indirect - github.com/libp2p/go-libp2p-noise v0.1.2 // indirect - github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect - github.com/libp2p/go-libp2p-record v0.1.3 // indirect - github.com/libp2p/go-libp2p-swarm v0.4.0 // indirect - github.com/libp2p/go-libp2p-tls v0.1.3 // indirect - github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 // indirect - github.com/libp2p/go-libp2p-yamux v0.5.1 // indirect - github.com/libp2p/go-mplex v0.3.0 // indirect - github.com/libp2p/go-msgio v0.0.6 // indirect - github.com/libp2p/go-nat v0.0.5 // indirect - github.com/libp2p/go-netroute v0.1.4 // indirect - github.com/libp2p/go-openssl v0.0.7 // indirect - github.com/libp2p/go-reuseport v0.0.2 // indirect - github.com/libp2p/go-reuseport-transport v0.0.4 // indirect - github.com/libp2p/go-sockaddr v0.1.0 // indirect - github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect - github.com/libp2p/go-tcp-transport v0.2.1 // indirect - github.com/libp2p/go-ws-transport v0.4.0 // indirect - github.com/libp2p/go-yamux/v2 v2.0.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -290,24 +249,14 @@ require ( github.com/mattn/go-runewidth v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect - github.com/minio/sha256-simd v0.1.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect - github.com/multiformats/go-multiaddr-dns v0.2.0 // indirect - github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multiaddr-net v0.2.0 // indirect - github.com/multiformats/go-multibase v0.0.3 // indirect - github.com/multiformats/go-multihash v0.0.14 // indirect - github.com/multiformats/go-multistream v0.2.0 // indirect - github.com/multiformats/go-varint v0.0.6 // indirect github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -318,13 +267,12 @@ require ( github.com/prometheus/procfs v0.12.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect + github.com/rs/zerolog v1.30.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sethvargo/go-retry v0.2.4 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect - github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/afero v1.9.3 // indirect github.com/spf13/cobra v1.6.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -333,6 +281,7 @@ require ( github.com/status-im/keycard-go v0.2.0 // indirect github.com/stretchr/objx v0.5.0 // 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 github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tendermint/go-amino v0.16.0 // indirect @@ -346,8 +295,6 @@ 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/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect - github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // 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 @@ -365,27 +312,24 @@ require ( go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/arch v0.6.0 // indirect + golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.15.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/appengine v1.6.8 // indirect + google.golang.org/api v0.149.0 // indirect google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // 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 sigs.k8s.io/yaml v1.3.0 // indirect ) replace ( - // Fix go mod tidy issue for ambiguous imports from go-ethereum - // See https://github.com/ugorji/go/issues/279 - github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1 - // replicating the replace directive on cosmos SDK github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 diff --git a/go.sum b/go.sum index 4bd90da600d..c8f6620af85 100644 --- a/go.sum +++ b/go.sum @@ -75,14 +75,12 @@ github.com/99designs/keyring v1.2.1 h1:tYLp1ULvO7i3fI5vE21ReQuj99QFSs7lGm0xWyJo8 github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= -github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= @@ -100,12 +98,11 @@ github.com/CosmWasm/wasmvm v1.2.4/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/Depado/ginprom v1.7.11 h1:qOhxW/NJZkNkkG4TQrzAZklX8SUTjTfLA73zIUNIpww= -github.com/Depado/ginprom v1.7.11/go.mod h1:49mxL3NTQwDrhpDbY4V1mAIB3us9B+b2hP1+ph+Sla8= +github.com/Depado/ginprom v1.8.0 h1:zaaibRLNI1dMiiuj1MKzatm8qrcHzikMlCc1anqOdyo= +github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0FU0UKgg= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= -github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -122,11 +119,10 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= -github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= +github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= @@ -172,30 +168,25 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3 h1:SDlJ7bAm4ewvrmZtR0DaiYbQGdKPeaaIm7bM+qRhFeU= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= +github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= @@ -206,12 +197,14 @@ github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= @@ -231,17 +224,20 @@ github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b80 github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/apd/v3 v3.1.0/go.mod h1:6qgPBMXjATAdD/VefbRP9NoSLKjbB4LCoA7gN4LpHs4= -github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= @@ -251,6 +247,10 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -258,10 +258,10 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= @@ -290,6 +290,10 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= +github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8= github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -307,33 +311,24 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g= github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT/t/lKtH99JQmKIb0v9WL3VaYkJ36CfHlVECI= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 h1:CuJS05R9jmNlUK8GOxrEELPbfXm0EuGh/30LjkjN5vo= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70/go.mod h1:EoK/8RFbMEteaCaz89uessDTnCWjbbcr+DXcBh4el5o= -github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= -github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -370,8 +365,10 @@ github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7 github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGCrqSJ5FZk= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= -github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= +github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= +github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.13.8 h1:1od+thJel3tM52ZUNQwvpYOeRHlbkVFZ5S8fhi0Lgsg= +github.com/ethereum/go-ethereum v1.13.8/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= @@ -389,12 +386,10 @@ github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBd github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= @@ -416,14 +411,16 @@ github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89 github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM= github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= github.com/getsentry/sentry-go v0.19.0 h1:BcCH3CN5tXt5aML+gwmbFwVptLLQA+eT866fCO9wVOM= github.com/getsentry/sentry-go v0.19.0/go.mod h1:y3+lGEFEFexZtpbG1GUE2WD/f9zGyKYwpEqryTOC/nE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= -github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= +github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk= +github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI= github.com/gin-contrib/expvar v0.0.1 h1:IuU5ArEgihz50vG8Onrwz22kJr7Mcvgv9xSSpfU5g+w= github.com/gin-contrib/expvar v0.0.1/go.mod h1:8o2CznfQi1JjktORdHr2/abg3wSV6OCnXh0yGypvvVw= github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE= @@ -434,11 +431,12 @@ github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NB github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= -github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -450,6 +448,8 @@ github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= @@ -457,8 +457,8 @@ github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEai github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= -github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= +github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= +github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -475,28 +475,29 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= +github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-webauthn/webauthn v0.9.1 h1:KuZjvUX9JTuFjB2n7kZhM6n76BClLUFbFM8SLKnrXpo= -github.com/go-webauthn/webauthn v0.9.1/go.mod h1:m315kRGbUljOytw8b9FGWG9QzErjI5v02pNFCF3lwpI= -github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= -github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= +github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g= +github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw= +github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0= +github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -505,6 +506,7 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -518,8 +520,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= -github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -558,7 +560,6 @@ 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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/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= @@ -592,10 +593,6 @@ github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -612,16 +609,18 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= 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.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/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= @@ -675,21 +674,19 @@ github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= -github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= -github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs= github.com/hashicorp/consul/sdk v0.14.1/go.mod h1:vFt03juSzocLRFo59NkeQHHmQa6+g7oU0pfzdI1mUhg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY= +github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= @@ -699,9 +696,6 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo= @@ -719,7 +713,6 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -732,10 +725,12 @@ github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce h1:7UnVY3T/ZnHUrfv github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU= github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.2 h1:TXKcSGc2WaxPD2+bmzAsVthL4+pEN0YwXcL5qED83vk= -github.com/holiman/uint256 v1.2.2/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -744,10 +739,8 @@ github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXM github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= -github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -761,49 +754,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= -github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= -github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= -github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= -github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.5 h1:cwOUcGMLdLPWgu3SlrCckCMznaGADbPqE0r8h768/Dg= -github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= -github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= -github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= -github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= -github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= -github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= -github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= -github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= -github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= -github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= -github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= -github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= -github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs= -github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= -github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= -github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= -github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= -github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= -github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= -github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0= -github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -863,20 +813,8 @@ github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= -github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= -github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= -github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= -github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= -github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= -github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= -github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= -github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= -github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= @@ -896,7 +834,6 @@ github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -906,7 +843,6 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= @@ -916,9 +852,9 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= @@ -926,17 +862,14 @@ github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.2 h1:fL3wAoyT6hXHQlORyXUW4Q23kkQpJRgEAYcZB5BR71o= -github.com/koron/go-ssdp v0.0.2/go.mod h1:XoLfkAiA2KeZsYh4DbHxD7h3nR2AZNqVQOa+LJuqPYs= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -952,6 +885,7 @@ github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awS github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a h1:dHCfT5W7gghzPtfsW488uPmEOm85wewI+ypUwibyTdU= github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= @@ -961,211 +895,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= -github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= -github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= -github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= -github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= -github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= -github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= -github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= -github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= -github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= -github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= -github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= -github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= -github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= -github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= -github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= -github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= -github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s= -github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 h1:2H/P+forDWBHije1WULwPfGduByUmC4fthndHVRpYNU= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= -github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= -github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= -github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= -github.com/libp2p/go-libp2p-autonat v0.4.0 h1:3y8XQbpr+ssX8QfZUHekjHCYK64sj6/4hnf/awD4+Ug= -github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= -github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= -github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= -github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= -github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= -github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= -github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= -github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= -github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= -github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= -github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= -github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= -github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= -github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= -github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= -github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= -github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= -github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= -github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= -github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= -github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= -github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= -github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= -github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc= -github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= -github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= -github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= -github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= -github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= -github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= -github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= -github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= -github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= -github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= -github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= -github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= -github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= -github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= -github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= -github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= -github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= -github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= -github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= -github.com/libp2p/go-libp2p-noise v0.1.2 h1:IH9GRihQJTx56obm+GnpdPX4KeVIlvpXrP6xnJ0wxWk= -github.com/libp2p/go-libp2p-noise v0.1.2/go.mod h1:9B10b7ueo7TIxZHHcjcDCo5Hd6kfKT2m77by82SFRfE= -github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= -github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= -github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= -github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= -github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= -github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= -github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= -github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= -github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= -github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= -github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= -github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= -github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= -github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= -github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= -github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= -github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= -github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= -github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= -github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= -github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA= -github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= -github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= -github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= -github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= -github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= -github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= -github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= -github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= -github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s= -github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= -github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= -github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= -github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= -github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= -github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= -github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= -github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0= -github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= -github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= -github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= -github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= -github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= -github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= -github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= -github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= -github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= -github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= -github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.4 h1:47V0+hJfYaqj1WO0A+cDkRc9xr9qKiK7i8zaoGv8Mmo= -github.com/libp2p/go-netroute v0.1.4/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= -github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= -github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= -github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= -github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= -github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= -github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= -github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= -github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0= -github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= -github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= -github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= -github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= -github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= -github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= -github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= -github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= -github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= -github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= -github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= -github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= -github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU= -github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= @@ -1173,7 +904,6 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/manyminds/api2go v0.0.0-20171030193247-e7b693844a6f h1:tVvGiZQFjOXP+9YyGqSA6jE55x1XVxmoPYudncxrZ8U= @@ -1190,7 +920,6 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -1212,25 +941,13 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= @@ -1252,6 +969,9 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1264,66 +984,10 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY 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= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= -github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= -github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= -github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= -github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= -github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= -github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= -github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= -github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= -github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= -github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= -github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= -github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= -github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= -github.com/multiformats/go-multistream v0.2.0 h1:6AuNmQVKUkRnddw2YiDjt5Elit40SFxMJkVnhmETXtU= -github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= @@ -1342,10 +1006,7 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -1353,11 +1014,7 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= @@ -1369,7 +1026,6 @@ github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/ github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.10 h1:EaL5WeO9lv9wmS6SASjszOeQdSctvpbu0DdBQBizE40= github.com/opencontainers/runc v1.1.10/go.mod h1:+/R6+KmDlh+hOO8NkjmgkG9Qzvypzk0yXxAPYYR65+M= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= @@ -1388,8 +1044,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= @@ -1435,8 +1091,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.48.0 h1:yrBloImGQ7je4h8M10ujGh4R6oxYQJQKlMuETwNskGk= -github.com/prometheus/prometheus v0.48.0/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= +github.com/prometheus/prometheus v0.48.1 h1:CTszphSNTXkuCG6O0IfpKdHcJkvvnAAE1GbELKS+NFk= +github.com/prometheus/prometheus v0.48.1/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= @@ -1465,10 +1121,11 @@ github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUz github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= -github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= +github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= +github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= @@ -1489,8 +1146,8 @@ github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08O github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= -github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= +github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= +github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1505,26 +1162,28 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= -github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 h1:qau0/AHvPwMR3p6gWsFWC4qVfEtSEALtBetTOpHA2IU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 h1:xkejUBZhcBpBrTSfxc91Iwzadrb6SXw8ks69bHIQ9Ww= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429/go.mod h1:wJmVvDf4XSjsahWtfUq3wvIAYEAuhr7oxmxYnEL/LGQ= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240124161023-948579cbaffa h1:9g7e1C3295ALDK8Gs42fIKSSJfI+H1RoBmivGWTvIZo= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240124161023-948579cbaffa/go.mod h1:05rRF84QKlIOF5LfTBPkHdw4UpBI2G3zxRcuZ65bPjk= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 h1:NALwENz6vQ972DuD9AZjqRjyNSxH9ptNapizQGLI+2s= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0/go.mod h1:NcVAT/GETDBvIoAej5K6OYqAtDOkF6vO5pYw/hLuYVU= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= +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.20240122152632-38444d2ad8ba h1:6rnQrD8NaLfLOPHszW1hbpviqpU8011gzdZk6wKP1xY= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba/go.mod h1:OZfzyayUdwsVBqxvbEMqwUntQT8HbFbgyqoudvwfVN0= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 h1:KwB0H2P/gxJgt823Ku1fTcFLDKMj6zsP3wbQGlBOm4U= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007/go.mod h1:EbZAlb/2K6mKr26u3+3cLBe/caJaqCHw786On94C43g= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= 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-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= -github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 h1:3y9WsXkZ5lxFrmfH7DQHs/q308lylKId5l/3VC0QAdM= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1/go.mod h1:kC0qmVPUaVkFqGiZMNhmRmjdphuUmeyLEdlWFOQzFWI= 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= @@ -1533,11 +1192,7 @@ github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= 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/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -1546,8 +1201,8 @@ github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= @@ -1563,7 +1218,6 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= 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/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1588,7 +1242,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= @@ -1627,8 +1282,8 @@ github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= @@ -1641,8 +1296,8 @@ github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFs github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= @@ -1653,15 +1308,6 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= -github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= -github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= -github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= -github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= -github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= 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/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1718,8 +1364,12 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 h1:mMv2jG58h6ZI5t5S9QCVGdzCmAsTakMa3oxVgpSD44g= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1/go.mod h1:oqRuNKG0upTaDPbLVCG8AD0G2ETrfDtmh7jViy7ox6M= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= +go.opentelemetry.io/contrib/propagators/b3 v1.21.1 h1:WPYiUgmw3+b7b3sQ1bFBFAf0q+Di9dvNc3AtYfnT4RQ= +go.opentelemetry.io/contrib/propagators/b3 v1.21.1/go.mod h1:EmzokPoSqsYMBVK4nRnhsfm5mbn8J1eDuz/U1UaQaWg= go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= @@ -1741,7 +1391,6 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -1758,8 +1407,6 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 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.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= 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.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= @@ -1771,26 +1418,15 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -1804,9 +1440,9 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1848,18 +1484,15 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1888,7 +1521,6 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -1907,7 +1539,7 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1947,17 +1579,13 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1966,7 +1594,6 @@ golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1986,7 +1613,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2014,11 +1640,9 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2029,7 +1653,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -2038,7 +1662,8 @@ golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2050,10 +1675,10 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2063,7 +1688,6 @@ golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -2086,7 +1710,6 @@ golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -2238,7 +1861,6 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= @@ -2289,13 +1911,9 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= -gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -2346,13 +1964,16 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= -nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/integration-tests/.root_dir b/integration-tests/.root_dir new file mode 100644 index 00000000000..e69de29bb2d diff --git a/integration-tests/.tool-versions b/integration-tests/.tool-versions index 47b73e9de11..ac6300f9797 100644 --- a/integration-tests/.tool-versions +++ b/integration-tests/.tool-versions @@ -1,4 +1,4 @@ -golang 1.21.4 +golang 1.21.5 k3d 5.4.6 kubectl 1.25.5 nodejs 18.13.0 diff --git a/integration-tests/Makefile b/integration-tests/Makefile index fb4bfa74f3e..8415c00f9cd 100644 --- a/integration-tests/Makefile +++ b/integration-tests/Makefile @@ -60,12 +60,12 @@ lint: golangci-lint --color=always run ./... --fix -v build: - @go build ./... && SELECTED_NETWORKS=SIMULATED go test -run=^# ./... + @go build ./... go test -run=^# ./... # Builds the test image # tag: the tag for the test image being built, example: tag=tate # base_tag: the tag for the base-test-image to use, example: base_tag=latest -# suite: the test suites to build into the image, example: suite="chaos soak smoke reorg migration performance" +# suite: the test suites to build into the image, example: suite="chaos soak smoke reorg migration" # push: set to true if you want the image pushed or leave blank if not, example: push=true .PHONY: build_test_image build_test_image: @@ -74,12 +74,12 @@ build_test_image: #Build a chainlink docker image for local testing and push to k3d registry .PHONY: build_push_docker_image build_push_docker_image: - docker build -f ../core/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t localhost:5000/chainlink:develop ../ ; docker push localhost:5000/chainlink:develop + docker build -f ../core/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t 127.0.0.1:5000/chainlink:develop ../ ; docker push 127.0.0.1:5000/chainlink:develop #Build a chainlink docker image in plugin mode for local testing and push to k3d registry .PHONY: build_push_plugin_docker_image build_push_plugin_docker_image: - docker build -f ../plugins/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t localhost:5000/chainlink:develop ../ ; docker push localhost:5000/chainlink:develop + docker build -f ../plugins/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t 127.0.0.1:5000/chainlink:develop ../ ; docker push 127.0.0.1:5000/chainlink:develop # Spins up containers needed to collect traces for local testing .PHONY: run_tracing @@ -89,10 +89,11 @@ run_tracing: ## Test Runner .PHONY: run -run: # Need to set network first in case it's unset. Doesn't matter for the runner - SELECTED_NETWORKS="SIMULATED" go run . +run: + go run . ## All commands will use 16 threads to run tests in parallel. To change this, use -test.parallel n +## Remember to set selected_networks and CL image in the TOML file (e.g. overrides.toml) # Smoke .PHONY: test_smoke_product @@ -122,23 +123,15 @@ test_chaos_network: install_gotestfmt ## Run all smoke tests test_chaos_verbose: ## Run all smoke tests with verbose logging go test -timeout 24h -count=1 -v $(args) ./chaos -# Performance -.PHONY: test_perf -test_perf: ## Run core node performance tests. - TEST_LOG_LEVEL="disabled" \ - SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ - go test -timeout 1h -count=1 -json $(args) ./performance 2>&1 | tee /tmp/gotest.log | gotestfmt - # Migrations .PHONY: test_node_migrations -test_node_migrations: install_gotestfmt ## Run all node migration tests +test_node_migrations: install_gotestfmt ## Run all node migration tests. TEST_LOG_LEVEL="disabled" \ go test -timeout 1h -count=1 -json $(args) ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt .PHONY: test_node_migrations_simulated -test_node_migrations_simulated: install_gotestfmt +test_node_migrations_simulated: install_gotestfmt TEST_LOG_LEVEL="disabled" \ - SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ go test -timeout 1h -count=1 -json $(args) ./migration 2>&1 | tee /tmp/gotest.log | gotestfmt .PHONY: test_node_migrations_verbose @@ -147,7 +140,6 @@ test_node_migrations_verbose: .PHONY: test_node_migrations_simulated_verbose test_node_migrations_simulated_verbose: - SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ go test -timeout 1h -count=1 -v $(args) ./migration # Soak @@ -157,7 +149,7 @@ test_soak_ocr: .PHONY: test_soak_ocr_simulated test_soak_ocr_simulated: - SELECTED_NETWORKS="SIMULATED" go test -v -count=1 -run TestOCRSoak ./soak + go test -v -count=1 -run TestOCRSoak ./soak .PHONY: test_soak_forwarder_ocr test_soak_forwarder_ocr: @@ -165,7 +157,7 @@ test_soak_forwarder_ocr: .PHONY: test_soak_forwarder_ocr_simulated test_soak_forwarder_ocr_simulated: - SELECTED_NETWORKS="SIMULATED" go test -v -count=1 -run TestForwarderOCRSoak ./soak + go test -v -count=1 -run TestForwarderOCRSoak ./soak .PHONY: test_soak_automation test_soak_automation: @@ -173,8 +165,6 @@ test_soak_automation: .PHONY: test_soak_automation_simulated test_soak_automation_simulated: - SELECTED_NETWORKS="SIMULATED" \ - TEST_INPUTS="TEST_TYPE=SOAK,NUMBEROFCONTRACTS=50,BLOCKRANGE=1000,BLOCKINTERVAL=50,GRAFANA_DASHBOARD_URL=https://chainlinklabs.grafana.net/d/Q8n6m1unz/chainlink-keepers-qa?orgId=1" \ go test -v -run ^TestAutomationBenchmark$$ ./benchmark -count=1 .PHONY: test_benchmark_automation @@ -192,17 +182,26 @@ test_reorg_automation: ## Run the automation reorg tests build_docker_image: docker build -f ../core/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t $(image):$(tag) ../ +# image: the name for the chainlink image being built, example: image=chainlink +# tag: the tag for the chainlink image being built, example: tag=latest +# example usage: make build_docker_image image=chainlink tag=latest +.PHONY: build_plugin_docker_image +build_plugin_docker_image: + docker build -f ../plugins/chainlink.Dockerfile --build-arg COMMIT_SHA=$(git rev-parse HEAD) --build-arg CHAINLINK_USER=chainlink -t 127.0.0.1:5000/chainlink:develop ../ # image: the name for the chainlink image being built, example: image=chainlink # tag: the tag for the chainlink image being built, example: tag=latest # args: the args to pass to the test runner, example: args="--focus @cron -p" # product: the product to run tests for, example: product=cron # example usage: make run_test_with_local_image image=chainlink tag=latest-dev product=cron +# remember to put the case CL image name and tag in the TOML config (and don't forget about selected network configuration) .PHONY: run_test_with_local_image run_test_with_local_image: build_docker_image - CHAINLINK_IMAGE=$(image) \ - CHAINLINK_VERSION=$(tag) \ - SELECTED_NETWORKS="SIMULATED,SIMULATED_1,SIMULATED_2" \ ARGS="$(args)" \ PRODUCT=$(product) \ ./scripts/run_product_tests + +# removes all occurrences of .run.id file in current folder and it's subdirectories +# before making any changes lists all file locations and awaits user confirmation +remove_test_execution_artefacts: + ./scripts/search_and_delete.sh .run.id \ No newline at end of file diff --git a/integration-tests/README.md b/integration-tests/README.md index c0b673fa92b..37a8fa19ed3 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -26,10 +26,16 @@ e.g. `make build_docker_image image=chainlink tag=test-tag` +You'll want to set the `CHAINLINK_IMAGE` and `CHAINLINK_VERSION` env values appropriately as well. See [example.env](./example.env) for more details. + ## Run `go test ./smoke/_test.go` +Most test files have a couple of tests, it's recommended to look into the file and focus on a specific one if possible. 90% of the time this will probably be the `Basic` test. See [ocr_test.go](./smoke/ocr_test.go) for example, which contains the `TestOCRBasic` test. + +`go test ./smoke/ocr_test.go -run TestOCRBasic` + It's generally recommended to run only one test at a time on a local machine as it needs a lot of docker containers and can peg your resources otherwise. You will see docker containers spin up on your machine for each component of the test where you can inspect logs. ## Analyze diff --git a/integration-tests/actions/actions.go b/integration-tests/actions/actions.go index 624df39c479..95b538129c7 100644 --- a/integration-tests/actions/actions.go +++ b/integration-tests/actions/actions.go @@ -4,6 +4,7 @@ package actions import ( "crypto/ecdsa" "encoding/json" + "errors" "fmt" "math/big" "strings" @@ -258,10 +259,11 @@ func TeardownSuite( chainlinkNodes []*client.ChainlinkK8sClient, optionalTestReporter testreporters.TestReporter, // Optionally pass in a test reporter to log further metrics failingLogLevel zapcore.Level, // Examines logs after the test, and fails the test if any Chainlink logs are found at or above provided level + grafnaUrlProvider testreporters.GrafanaURLProvider, clients ...blockchain.EVMClient, ) error { l := logging.GetTestLogger(t) - if err := testreporters.WriteTeardownLogs(t, env, optionalTestReporter, failingLogLevel); err != nil { + if err := testreporters.WriteTeardownLogs(t, env, optionalTestReporter, failingLogLevel, grafnaUrlProvider); err != nil { return fmt.Errorf("Error dumping environment logs, leaving environment running for manual retrieval, err: %w", err) } // Delete all jobs to stop depleting the funds @@ -302,11 +304,12 @@ func TeardownRemoteSuite( namespace string, chainlinkNodes []*client.ChainlinkK8sClient, optionalTestReporter testreporters.TestReporter, // Optionally pass in a test reporter to log further metrics + grafnaUrlProvider testreporters.GrafanaURLProvider, client blockchain.EVMClient, ) error { l := logging.GetTestLogger(t) var err error - if err = testreporters.SendReport(t, namespace, "./", optionalTestReporter); err != nil { + if err = testreporters.SendReport(t, namespace, "./", optionalTestReporter, grafnaUrlProvider); err != nil { l.Warn().Err(err).Msg("Error writing test report") } // Delete all jobs to stop depleting the funds @@ -415,8 +418,8 @@ func UpgradeChainlinkNodeVersions( newImage, newVersion string, nodes ...*client.ChainlinkK8sClient, ) error { - if newImage == "" && newVersion == "" { - return fmt.Errorf("unable to upgrade node version, found empty image and version, must provide either a new image or a new version") + if newImage == "" || newVersion == "" { + return errors.New("New image and new version is needed to upgrade the node") } for _, node := range nodes { if err := node.UpgradeVersion(testEnvironment, newImage, newVersion); err != nil { diff --git a/integration-tests/actions/actions_local.go b/integration-tests/actions/actions_local.go index d4913cabd8a..8ac623d8841 100644 --- a/integration-tests/actions/actions_local.go +++ b/integration-tests/actions/actions_local.go @@ -2,8 +2,6 @@ package actions import ( - "fmt" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" ) @@ -13,9 +11,6 @@ func UpgradeChainlinkNodeVersionsLocal( newImage, newVersion string, nodes ...*test_env.ClNode, ) error { - if newImage == "" && newVersion == "" { - return fmt.Errorf("unable to upgrade node version, found empty image and version, must provide either a new image or a new version") - } for _, node := range nodes { if err := node.UpgradeVersion(newImage, newVersion); err != nil { return err diff --git a/integration-tests/actions/automationv2/actions.go b/integration-tests/actions/automationv2/actions.go index febdd892150..bccd3ef1675 100644 --- a/integration-tests/actions/automationv2/actions.go +++ b/integration-tests/actions/automationv2/actions.go @@ -32,12 +32,12 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_registrar_wrapper2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_registrar_wrapper2_0" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/v2/core/utils" ctfTestEnv "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" ) diff --git a/integration-tests/actions/ocr2_helpers.go b/integration-tests/actions/ocr2_helpers.go index 7b0700c3452..8c7af76866a 100644 --- a/integration-tests/actions/ocr2_helpers.go +++ b/integration-tests/actions/ocr2_helpers.go @@ -9,6 +9,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/google/uuid" "github.com/lib/pq" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -22,6 +23,11 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" + "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -105,12 +111,15 @@ func ConfigureOCRv2AggregatorContracts( } // BuildMedianOCR2Config builds a default OCRv2 config for the given chainlink nodes for a standard median aggregation job -func BuildMedianOCR2Config(workerNodes []*client.ChainlinkK8sClient) (*contracts.OCRv2Config, error) { +func BuildMedianOCR2Config( + workerNodes []*client.ChainlinkK8sClient, + ocrOffchainOptions contracts.OffchainOptions, +) (*contracts.OCRv2Config, error) { S, oracleIdentities, err := GetOracleIdentities(workerNodes) if err != nil { return nil, err } - signerKeys, transmitterAccounts, f_, onchainConfig, offchainConfigVersion, offchainConfig, err := confighelper.ContractSetConfigArgsForTests( + signerKeys, transmitterAccounts, f_, _, offchainConfigVersion, offchainConfig, err := confighelper.ContractSetConfigArgsForTests( 30*time.Second, // deltaProgress time.Duration, 30*time.Second, // deltaResend time.Duration, 10*time.Second, // deltaRound time.Duration, @@ -150,6 +159,8 @@ func BuildMedianOCR2Config(workerNodes []*client.ChainlinkK8sClient) (*contracts transmitterAddresses = append(transmitterAddresses, common.HexToAddress(string(account))) } + onchainConfig, err := testhelpers.GenerateDefaultOCR2OnchainConfig(ocrOffchainOptions.MinimumAnswer, ocrOffchainOptions.MaximumAnswer) + return &contracts.OCRv2Config{ Signers: signerAddresses, Transmitters: transmitterAddresses, @@ -157,7 +168,7 @@ func BuildMedianOCR2Config(workerNodes []*client.ChainlinkK8sClient) (*contracts OnchainConfig: onchainConfig, OffchainConfigVersion: offchainConfigVersion, OffchainConfig: []byte(fmt.Sprintf("0x%s", offchainConfig)), - }, nil + }, err } // GetOracleIdentities retrieves all chainlink nodes' OCR2 config identities with defaul key index @@ -258,7 +269,6 @@ func CreateOCRv2Jobs( bootstrapNode *client.ChainlinkK8sClient, workerChainlinkNodes []*client.ChainlinkK8sClient, mockserver *ctfClient.MockserverClient, - mockServerPath string, // Path on the mock server for the Chainlink nodes to query mockServerValue int, // Value to get from the mock server when querying the path chainId uint64, // EVM chain ID forwardingAllowed bool, @@ -269,20 +279,28 @@ func CreateOCRv2Jobs( return err } p2pV2Bootstrapper := fmt.Sprintf("%s@%s:%d", bootstrapP2PIds.Data[0].Attributes.PeerID, bootstrapNode.InternalIP(), 6690) - // Set the value for the jobs to report on - err = mockserver.SetValuePath(mockServerPath, mockServerValue) - if err != nil { - return err - } + mockJuelsPath := "ocr2/juelsPerFeeCoinSource" // Set the juelsPerFeeCoinSource config value - err = mockserver.SetValuePath(fmt.Sprintf("%s/juelsPerFeeCoinSource", mockServerPath), mockServerValue) + err = mockserver.SetValuePath(mockJuelsPath, mockServerValue) if err != nil { return err } + // Create the juels bridge for each node only once + juelsBridge := &client.BridgeTypeAttributes{ + Name: "juels", + URL: fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, mockJuelsPath), + } + for _, chainlinkNode := range workerChainlinkNodes { + err = chainlinkNode.MustCreateBridge(juelsBridge) + if err != nil { + return fmt.Errorf("failed creating bridge %s on CL node : %w", juelsBridge.Name, err) + } + } + for _, ocrInstance := range ocrInstances { bootstrapSpec := &client.OCR2TaskJobSpec{ - Name: "ocr2 bootstrap node", + Name: fmt.Sprintf("ocr2-bootstrap-%s", ocrInstance.Address()), JobType: "bootstrap", OCR2OracleSpec: job.OCR2OracleSpec{ ContractID: ocrInstance.Address(), @@ -290,7 +308,7 @@ func CreateOCRv2Jobs( RelayConfig: map[string]interface{}{ "chainID": chainId, }, - MonitoringEndpoint: null.StringFrom(fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, mockServerPath)), + MonitoringEndpoint: null.StringFrom(fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, "ocr2")), ContractConfigTrackerPollInterval: *models.NewInterval(15 * time.Second), }, } @@ -310,25 +328,22 @@ func CreateOCRv2Jobs( } nodeOCRKeyId := nodeOCRKeys.Data[0].ID - bta := &client.BridgeTypeAttributes{ - Name: mockServerPath, - URL: fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, mockServerPath), + nodeContractPairID, err := BuildOCR2NodeContractPairID(chainlinkNode, ocrInstance) + if err != nil { + return err } - juelsBridge := &client.BridgeTypeAttributes{ - Name: "juels", - URL: fmt.Sprintf("%s/%s/juelsPerFeeCoinSource", mockserver.Config.ClusterURL, mockServerPath), + bta := &client.BridgeTypeAttributes{ + Name: nodeContractPairID, + URL: fmt.Sprintf("%s/%s", mockserver.Config.ClusterURL, strings.TrimPrefix(nodeContractPairID, "/")), } + err = chainlinkNode.MustCreateBridge(bta) if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) - } - err = chainlinkNode.MustCreateBridge(juelsBridge) - if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) + return fmt.Errorf("failed creating bridge %s on CL node: %w", bta.Name, err) } ocrSpec := &client.OCR2TaskJobSpec{ - Name: "ocr2", + Name: fmt.Sprintf("ocr2-%s", uuid.NewString()), JobType: "offchainreporting2", MaxTaskDuration: "1m", ObservationSource: client.ObservationSourceSpecBridge(bta), @@ -366,6 +381,7 @@ func StartNewOCR2Round( timeout time.Duration, logger zerolog.Logger, ) error { + time.Sleep(5 * time.Second) for i := 0; i < len(ocrInstances); i++ { err := ocrInstances[i].RequestNewRound() if err != nil { @@ -373,9 +389,12 @@ func StartNewOCR2Round( } ocrRound := contracts.NewOffchainAggregatorV2RoundConfirmer(ocrInstances[i], big.NewInt(roundNumber), timeout, logger) client.AddHeaderEventSubscription(ocrInstances[i].Address(), ocrRound) - err = client.WaitForEvents() + err = ocrRound.Wait() // wait for OCR Round to complete if err != nil { - return fmt.Errorf("failed to wait for event subscriptions of OCR instance %d: %w", i+1, err) + return fmt.Errorf("failed to wait for OCR Round %d to complete instance %d", roundNumber, i) + } + if !ocrRound.Complete() { + return fmt.Errorf("failed to complete OCR Round %d for ocr instance %d", roundNumber, i) } } return nil @@ -400,3 +419,90 @@ func WatchNewOCR2Round( } return nil } + +// SetOCR2AdapterResponse sets a single adapter response that correlates with an ocr contract and a chainlink node +// used for OCR2 tests +func SetOCR2AdapterResponse( + response int, + ocrInstance contracts.OffchainAggregatorV2, + chainlinkNode *client.ChainlinkK8sClient, + mockserver *ctfClient.MockserverClient, +) error { + nodeContractPairID, err := BuildOCR2NodeContractPairID(chainlinkNode, ocrInstance) + if err != nil { + return err + } + path := fmt.Sprintf("/%s", nodeContractPairID) + err = mockserver.SetValuePath(path, response) + if err != nil { + return fmt.Errorf("setting mockserver value path failed: %w", err) + } + return nil +} + +// SetOCR2AllAdapterResponsesToTheSameValue sets the mock responses in mockserver that are read by chainlink nodes +// to simulate different adapters. This sets all adapter responses for each node and contract to the same response +// used for OCR2 tests +func SetOCR2AllAdapterResponsesToTheSameValue( + response int, + ocrInstances []contracts.OffchainAggregatorV2, + chainlinkNodes []*client.ChainlinkK8sClient, + mockserver *ctfClient.MockserverClient, +) error { + eg := &errgroup.Group{} + for _, o := range ocrInstances { + ocrInstance := o + for _, n := range chainlinkNodes { + node := n + eg.Go(func() error { + return SetOCR2AdapterResponse(response, ocrInstance, node, mockserver) + }) + } + } + return eg.Wait() +} + +// SetOCR2AllAdapterResponsesToDifferentValues sets the mock responses in mockserver that are read by chainlink nodes +// to simulate different adapters. This sets all adapter responses for each node and contract to different responses +// used for OCR2 tests +func SetOCR2AllAdapterResponsesToDifferentValues( + responses []int, + ocrInstances []contracts.OffchainAggregatorV2, + chainlinkNodes []*client.ChainlinkK8sClient, + mockserver *ctfClient.MockserverClient, +) error { + if len(responses) != len(ocrInstances)*len(chainlinkNodes) { + return fmt.Errorf( + "amount of responses %d should be equal to the amount of OCR instances %d times the amount of Chainlink nodes %d", + len(responses), len(ocrInstances), len(chainlinkNodes), + ) + } + eg := &errgroup.Group{} + for _, o := range ocrInstances { + ocrInstance := o + for ni := 1; ni < len(chainlinkNodes); ni++ { + nodeIndex := ni + eg.Go(func() error { + return SetOCR2AdapterResponse(responses[nodeIndex-1], ocrInstance, chainlinkNodes[nodeIndex], mockserver) + }) + } + } + return eg.Wait() +} + +// BuildOCR2NodeContractPairID builds a UUID based on a related pair of a Chainlink node and OCRv2 contract +func BuildOCR2NodeContractPairID(node *client.ChainlinkK8sClient, ocrInstance contracts.OffchainAggregatorV2) (string, error) { + if node == nil { + return "", fmt.Errorf("chainlink node is nil") + } + if ocrInstance == nil { + return "", fmt.Errorf("OCR Instance is nil") + } + nodeAddress, err := node.PrimaryEthAddress() + if err != nil { + return "", fmt.Errorf("getting chainlink node's primary ETH address failed: %w", err) + } + shortNodeAddr := nodeAddress[2:12] + shortOCRAddr := ocrInstance.Address()[2:12] + return strings.ToLower(fmt.Sprintf("node_%s_contract_%s", shortNodeAddr, shortOCRAddr)), nil +} diff --git a/integration-tests/actions/ocr2_helpers_local.go b/integration-tests/actions/ocr2_helpers_local.go index e1b470bd0d4..8a0a02c050f 100644 --- a/integration-tests/actions/ocr2_helpers_local.go +++ b/integration-tests/actions/ocr2_helpers_local.go @@ -18,14 +18,17 @@ import ( "golang.org/x/sync/errgroup" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink-common/pkg/codec" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/store/models" + + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) func CreateOCRv2JobsLocal( @@ -37,6 +40,7 @@ func CreateOCRv2JobsLocal( mockAdapterValue int, // Value to get from the mock server when querying the path chainId uint64, // EVM chain ID forwardingAllowed bool, + enableChainReaderAndCodec bool, ) error { // Collect P2P ID bootstrapP2PIds, err := bootstrapNode.MustReadP2PKeys() @@ -95,11 +99,11 @@ func CreateOCRv2JobsLocal( } err = chainlinkNode.MustCreateBridge(bta) if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) + return fmt.Errorf("creating bridge on CL node failed: %w", err) } err = chainlinkNode.MustCreateBridge(juelsBridge) if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) + return fmt.Errorf("creating bridge on CL node failed: %w", err) } ocrSpec := &client.OCR2TaskJobSpec{ @@ -124,6 +128,43 @@ func CreateOCRv2JobsLocal( P2PV2Bootstrappers: pq.StringArray{p2pV2Bootstrapper}, // bootstrap node key and address @bootstrap:6690 }, } + if enableChainReaderAndCodec { + ocrSpec.OCR2OracleSpec.RelayConfig["chainReader"] = evmtypes.ChainReaderConfig{ + Contracts: map[string]evmtypes.ChainContractReader{ + "median": { + ContractABI: `[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"requester","type":"address"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"epoch","type":"uint32"},{"indexed":false,"internalType":"uint8","name":"round","type":"uint8"}],"name":"RoundRequested","type":"event"},{"inputs":[],"name":"latestTransmissionDetails","outputs":[{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint32","name":"epoch","type":"uint32"},{"internalType":"uint8","name":"round","type":"uint8"},{"internalType":"int192","name":"latestAnswer_","type":"int192"},{"internalType":"uint64","name":"latestTimestamp_","type":"uint64"}],"stateMutability":"view","type":"function"}]`, + Configs: map[string]*evmtypes.ChainReaderDefinition{ + "LatestTransmissionDetails": { + ChainSpecificName: "latestTransmissionDetails", + OutputModifications: codec.ModifiersConfig{ + &codec.EpochToTimeModifierConfig{ + Fields: []string{"LatestTimestamp_"}, + }, + &codec.RenameModifierConfig{ + Fields: map[string]string{ + "LatestAnswer_": "LatestAnswer", + "LatestTimestamp_": "LatestTimestamp", + }, + }, + }, + }, + "LatestRoundRequested": { + ChainSpecificName: "RoundRequested", + ReadType: evmtypes.Event, + }, + }, + }, + }, + } + ocrSpec.OCR2OracleSpec.RelayConfig["codec"] = evmtypes.CodecConfig{ + Configs: map[string]evmtypes.ChainCodecConfig{ + "MedianReport": { + TypeABI: `[{"Name": "Timestamp","Type": "uint32"},{"Name": "Observers","Type": "bytes32"},{"Name": "Observations","Type": "int192[]"},{"Name": "JuelsPerFeeCoin","Type": "int192"}]`, + }, + }, + } + } + _, err = chainlinkNode.MustCreateJob(ocrSpec) if err != nil { return fmt.Errorf("creating OCR task job on OCR node have failed: %w", err) diff --git a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go index c3add16ec67..dd51e302744 100644 --- a/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go +++ b/integration-tests/actions/ocr2vrf_actions/ocr2vrf_steps.go @@ -16,8 +16,8 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" - chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/ocr2vrf_actions/ocr2vrf_constants" diff --git a/integration-tests/actions/ocr_helpers.go b/integration-tests/actions/ocr_helpers.go index 4f713dcdd6d..dd0e6606e43 100644 --- a/integration-tests/actions/ocr_helpers.go +++ b/integration-tests/actions/ocr_helpers.go @@ -236,7 +236,7 @@ func CreateOCRJobs( } err = node.MustCreateBridge(bta) if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) + return fmt.Errorf("creating bridge on CL node failed: %w", err) } bootstrapPeers := []*client.ChainlinkClient{bootstrapNode.ChainlinkClient} @@ -343,6 +343,25 @@ func StartNewRound( return nil } +// WatchNewRound watches for a new OCR round, similarly to StartNewRound, but it does not explicitly request a new +// round from the contract, as this can cause some odd behavior in some cases +func WatchNewRound( + roundNumber int64, + ocrInstances []contracts.OffchainAggregator, + client blockchain.EVMClient, + logger zerolog.Logger, +) error { + for i := 0; i < len(ocrInstances); i++ { + ocrRound := contracts.NewOffchainAggregatorRoundConfirmer(ocrInstances[i], big.NewInt(roundNumber), client.GetNetworkConfig().Timeout.Duration, logger) + client.AddHeaderEventSubscription(ocrInstances[i].Address(), ocrRound) + err := client.WaitForEvents() + if err != nil { + return fmt.Errorf("failed to wait for event subscriptions of OCR instance %d: %w", i+1, err) + } + } + return nil +} + // SetAdapterResponse sets a single adapter response that correlates with an ocr contract and a chainlink node func SetAdapterResponse( response int, diff --git a/integration-tests/actions/ocr_helpers_local.go b/integration-tests/actions/ocr_helpers_local.go index fb0fd0bd47d..e9cad3f67ea 100644 --- a/integration-tests/actions/ocr_helpers_local.go +++ b/integration-tests/actions/ocr_helpers_local.go @@ -196,7 +196,7 @@ func CreateOCRJobsLocal( } err = node.MustCreateBridge(bta) if err != nil { - return fmt.Errorf("creating bridge job have failed: %w", err) + return fmt.Errorf("creating bridge on CL node failed: %w", err) } bootstrapPeers := []*client.ChainlinkClient{bootstrapNode} diff --git a/integration-tests/actions/private_network.go b/integration-tests/actions/private_network.go new file mode 100644 index 00000000000..7f8bfe8bb2c --- /dev/null +++ b/integration-tests/actions/private_network.go @@ -0,0 +1,28 @@ +package actions + +import ( + "github.com/rs/zerolog" + + ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" +) + +func EthereumNetworkConfigFromConfig(l zerolog.Logger, config tc.GlobalTestConfig) (network ctf_test_env.EthereumNetwork, err error) { + if config.GetPrivateEthereumNetworkConfig() == nil { + l.Warn().Msg("No TOML private ethereum network config found, will use old geth") + ethBuilder := ctf_test_env.NewEthereumNetworkBuilder() + network, err = ethBuilder. + WithConsensusType(ctf_test_env.ConsensusType_PoW). + WithExecutionLayer(ctf_test_env.ExecutionLayer_Geth). + Build() + + return + } + + ethBuilder := ctf_test_env.NewEthereumNetworkBuilder() + network, err = ethBuilder. + WithExistingConfig(*config.GetPrivateEthereumNetworkConfig()). + Build() + + return +} diff --git a/integration-tests/actions/vrfv1/actions.go b/integration-tests/actions/vrf/vrfv1/actions.go similarity index 100% rename from integration-tests/actions/vrfv1/actions.go rename to integration-tests/actions/vrf/vrfv1/actions.go diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_models.go b/integration-tests/actions/vrf/vrfv2/vrfv2_models.go similarity index 82% rename from integration-tests/actions/vrfv2_actions/vrfv2_models.go rename to integration-tests/actions/vrf/vrfv2/vrfv2_models.go index 0576d6f7d6e..be627b43e4f 100644 --- a/integration-tests/actions/vrfv2_actions/vrfv2_models.go +++ b/integration-tests/actions/vrf/vrfv2/vrfv2_models.go @@ -1,4 +1,4 @@ -package vrfv2_actions +package vrfv2 import ( "math/big" @@ -19,10 +19,16 @@ type VRFV2JobInfo struct { type VRFV2Contracts struct { Coordinator contracts.VRFCoordinatorV2 + VRFOwner contracts.VRFOwner BHS contracts.BlockHashStore LoadTestConsumers []contracts.VRFv2LoadTestConsumer } +type VRFV2WrapperContracts struct { + VRFV2Wrapper contracts.VRFV2Wrapper + LoadTestConsumers []contracts.VRFv2WrapperLoadTestConsumer +} + // VRFV2PlusKeyData defines a jobs into and proving key info type VRFV2KeyData struct { VRFKey *client.VRFKey diff --git a/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go b/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go new file mode 100644 index 00000000000..276105d20ef --- /dev/null +++ b/integration-tests/actions/vrf/vrfv2/vrfv2_steps.go @@ -0,0 +1,1049 @@ +package vrfv2 + +import ( + "context" + "fmt" + "math/big" + "sync" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/rs/zerolog" + + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" + + "github.com/google/uuid" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/types" +) + +var ( + 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" + ErrRegisteringProvingKey = "error registering a proving key on Coordinator contract" + ErrRegisterProvingKey = "error registering proving keys" + ErrEncodingProvingKey = "error encoding proving key" + ErrCreatingVRFv2Key = "error creating VRFv2 key" + ErrDeployBlockHashStore = "error deploying blockhash store" + ErrDeployCoordinator = "error deploying VRF CoordinatorV2" + ErrAdvancedConsumer = "error deploying VRFv2 Advanced Consumer" + ErrABIEncodingFunding = "error Abi encoding subscriptionID" + ErrSendingLinkToken = "error sending Link token" + ErrCreatingVRFv2Job = "error creating VRFv2 job" + ErrParseJob = "error parsing job definition" + ErrDeployVRFV2Contracts = "error deploying VRFV2 contracts" + ErrSetVRFCoordinatorConfig = "error setting config for VRF Coordinator contract" + ErrCreateVRFSubscription = "error creating VRF Subscription" + ErrAddConsumerToSub = "error adding consumer to VRF Subscription" + ErrFundSubWithLinkToken = "error funding subscription with Link tokens" + ErrCreateVRFV2Jobs = "error creating VRF V2 Jobs" + ErrRestartCLNode = "error restarting CL node" + ErrWaitTXsComplete = "error waiting for TXs to complete" + ErrRequestRandomness = "error requesting randomness" + ErrLoadingCoordinator = "error loading coordinator contract" + + ErrWaitRandomWordsRequestedEvent = "error waiting for RandomWordsRequested event" + ErrWaitRandomWordsFulfilledEvent = "error waiting for RandomWordsFulfilled event" + ErrDeployWrapper = "error deploying VRFV2PlusWrapper" +) + +type VRFOwnerConfig struct { + OwnerAddress string + useVRFOwner bool +} + +type VRFJobSpecConfig struct { + ForwardingAllowed bool + CoordinatorAddress string + FromAddresses []string + EVMChainID string + MinIncomingConfirmations int + PublicKey string + BatchFulfillmentEnabled bool + BatchFulfillmentGasMultiplier float64 + EstimateGasMultiplier float64 + PollPeriod time.Duration + RequestTimeout time.Duration + VRFOwnerConfig VRFOwnerConfig +} + +func DeployVRFV2Contracts( + env *test_env.CLClusterTestEnv, + linkTokenContract contracts.LinkToken, + linkEthFeedContract contracts.MockETHLINKFeed, + consumerContractsAmount int, + useVRFOwner bool, + useTestCoordinator bool, +) (*VRFV2Contracts, error) { + bhs, err := env.ContractDeployer.DeployBlockhashStore() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployBlockHashStore, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + var coordinatorAddress string + if useTestCoordinator { + testCoordinator, err := env.ContractDeployer.DeployVRFCoordinatorTestV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + coordinatorAddress = testCoordinator.Address() + } else { + coordinator, err := env.ContractDeployer.DeployVRFCoordinatorV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + coordinatorAddress = coordinator.Address() + } + consumers, err := DeployVRFV2Consumers(env.ContractDeployer, coordinatorAddress, consumerContractsAmount) + if err != nil { + return nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(coordinatorAddress) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrLoadingCoordinator, err) + } + if useVRFOwner { + vrfOwner, err := env.ContractDeployer.DeployVRFOwner(coordinatorAddress) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return &VRFV2Contracts{coordinator, vrfOwner, bhs, consumers}, nil + } + return &VRFV2Contracts{coordinator, nil, bhs, consumers}, nil +} + +func DeployVRFV2Consumers(contractDeployer contracts.ContractDeployer, coordinatorAddress string, consumerContractsAmount int) ([]contracts.VRFv2LoadTestConsumer, error) { + var consumers []contracts.VRFv2LoadTestConsumer + for i := 1; i <= consumerContractsAmount; i++ { + loadTestConsumer, err := contractDeployer.DeployVRFv2LoadTestConsumer(coordinatorAddress) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) + } + consumers = append(consumers, loadTestConsumer) + } + return consumers, nil +} + +func DeployVRFV2WrapperConsumers(contractDeployer contracts.ContractDeployer, linkTokenAddress string, vrfV2Wrapper contracts.VRFV2Wrapper, consumerContractsAmount int) ([]contracts.VRFv2WrapperLoadTestConsumer, error) { + var consumers []contracts.VRFv2WrapperLoadTestConsumer + for i := 1; i <= consumerContractsAmount; i++ { + loadTestConsumer, err := contractDeployer.DeployVRFV2WrapperLoadTestConsumer(linkTokenAddress, vrfV2Wrapper.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) + } + consumers = append(consumers, loadTestConsumer) + } + return consumers, nil +} + +func DeployVRFV2DirectFundingContracts( + contractDeployer contracts.ContractDeployer, + chainClient blockchain.EVMClient, + linkTokenAddress string, + linkEthFeedAddress string, + coordinator contracts.VRFCoordinatorV2, + consumerContractsAmount int, +) (*VRFV2WrapperContracts, error) { + vrfv2Wrapper, err := contractDeployer.DeployVRFV2Wrapper(linkTokenAddress, linkEthFeedAddress, coordinator.Address()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrDeployWrapper, err) + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + consumers, err := DeployVRFV2WrapperConsumers(contractDeployer, linkTokenAddress, vrfv2Wrapper, consumerContractsAmount) + if err != nil { + return nil, err + } + err = chainClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return &VRFV2WrapperContracts{vrfv2Wrapper, consumers}, nil +} + +func CreateVRFV2Job( + chainlinkNode *client.ChainlinkClient, + vrfJobSpecConfig VRFJobSpecConfig, +) (*client.Job, error) { + jobUUID := uuid.New() + os := &client.VRFV2TxPipelineSpec{ + Address: vrfJobSpecConfig.CoordinatorAddress, + EstimateGasMultiplier: vrfJobSpecConfig.EstimateGasMultiplier, + FromAddress: vrfJobSpecConfig.FromAddresses[0], + } + ost, err := os.String() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) + } + + spec := &client.VRFV2JobSpec{ + Name: fmt.Sprintf("vrf-v2-%s", jobUUID), + ForwardingAllowed: vrfJobSpecConfig.ForwardingAllowed, + CoordinatorAddress: vrfJobSpecConfig.CoordinatorAddress, + FromAddresses: vrfJobSpecConfig.FromAddresses, + EVMChainID: vrfJobSpecConfig.EVMChainID, + MinIncomingConfirmations: vrfJobSpecConfig.MinIncomingConfirmations, + PublicKey: vrfJobSpecConfig.PublicKey, + ExternalJobID: jobUUID.String(), + ObservationSource: ost, + BatchFulfillmentEnabled: vrfJobSpecConfig.BatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: vrfJobSpecConfig.BatchFulfillmentGasMultiplier, + PollPeriod: vrfJobSpecConfig.PollPeriod, + RequestTimeout: vrfJobSpecConfig.RequestTimeout, + } + if vrfJobSpecConfig.VRFOwnerConfig.useVRFOwner { + spec.VRFOwner = vrfJobSpecConfig.VRFOwnerConfig.OwnerAddress + spec.UseVRFOwner = true + } + + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) + + } + job, err := chainlinkNode.MustCreateJob(spec) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Job, err) + } + return job, nil +} + +func VRFV2RegisterProvingKey( + vrfKey *client.VRFKey, + oracleAddress string, + coordinator contracts.VRFCoordinatorV2, +) (VRFV2EncodedProvingKey, error) { + provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) + if err != nil { + return VRFV2EncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrEncodingProvingKey, err) + } + err = coordinator.RegisterProvingKey( + oracleAddress, + provingKey, + ) + if err != nil { + return VRFV2EncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrRegisterProvingKey, err) + } + return provingKey, nil +} + +func FundVRFCoordinatorV2Subscription( + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2, + chainClient blockchain.EVMClient, + subscriptionID uint64, + linkFundingAmountJuels *big.Int, +) error { + encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint64"}]`, subscriptionID) + if err != nil { + return fmt.Errorf("%s, err %w", ErrABIEncodingFunding, err) + } + _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) + if err != nil { + return fmt.Errorf("%s, err %w", ErrSendingLinkToken, err) + } + return chainClient.WaitForEvents() +} + +// SetupVRFV2Environment will create specified number of subscriptions and add the same conumer/s to each of them +func SetupVRFV2Environment( + env *test_env.CLClusterTestEnv, + vrfv2TestConfig types.VRFv2TestConfig, + useVRFOwner bool, + useTestCoordinator bool, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.MockETHLINKFeed, + registerProvingKeyAgainstAddress string, + numberOfTxKeysToCreate int, + numberOfConsumers int, + numberOfSubToCreate int, + l zerolog.Logger, +) (*VRFV2Contracts, []uint64, *VRFV2Data, error) { + l.Info().Msg("Starting VRFV2 environment setup") + l.Info().Msg("Deploying VRFV2 contracts") + vrfv2Contracts, err := DeployVRFV2Contracts( + env, + linkToken, + mockNativeLINKFeed, + numberOfConsumers, + useVRFOwner, + useTestCoordinator, + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2Contracts, err) + } + vrfv2Config := vrfv2TestConfig.GetVRFv2Config().General + vrfCoordinatorV2FeeConfig := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ + FulfillmentFlatFeeLinkPPMTier1: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier1, + FulfillmentFlatFeeLinkPPMTier2: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier2, + FulfillmentFlatFeeLinkPPMTier3: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier3, + FulfillmentFlatFeeLinkPPMTier4: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier4, + FulfillmentFlatFeeLinkPPMTier5: *vrfv2Config.FulfillmentFlatFeeLinkPPMTier5, + ReqsForTier2: big.NewInt(*vrfv2Config.ReqsForTier2), + ReqsForTier3: big.NewInt(*vrfv2Config.ReqsForTier3), + ReqsForTier4: big.NewInt(*vrfv2Config.ReqsForTier4), + ReqsForTier5: big.NewInt(*vrfv2Config.ReqsForTier5)} + + l.Info().Str("Coordinator", vrfv2Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") + err = vrfv2Contracts.Coordinator.SetConfig( + *vrfv2Config.MinimumConfirmations, + *vrfv2Config.MaxGasLimitCoordinatorConfig, + *vrfv2Config.StalenessSeconds, + *vrfv2Config.GasAfterPaymentCalculation, + big.NewInt(*vrfv2Config.FallbackWeiPerUnitLink), + vrfCoordinatorV2FeeConfig, + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrSetVRFCoordinatorConfig, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + l.Info(). + Str("Coordinator", vrfv2Contracts.Coordinator.Address()). + Int("Number of Subs to create", numberOfSubToCreate). + Msg("Creating and funding subscriptions, adding consumers") + subIDs, err := CreateFundSubsAndAddConsumers( + env, + big.NewFloat(*vrfv2Config.SubscriptionFundingAmountLink), + linkToken, + vrfv2Contracts.Coordinator, vrfv2Contracts.LoadTestConsumers, numberOfSubToCreate) + if err != nil { + return nil, nil, nil, err + } + l.Info().Str("Node URL", env.ClCluster.NodeAPIs()[0].URL()).Msg("Creating VRF Key on the Node") + vrfKey, err := env.ClCluster.NodeAPIs()[0].MustCreateVRFKey() + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Key, err) + } + pubKeyCompressed := vrfKey.Data.ID + + l.Info().Str("Coordinator", vrfv2Contracts.Coordinator.Address()).Msg("Registering Proving Key") + provingKey, err := VRFV2RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfv2Contracts.Coordinator) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRegisteringProvingKey, err) + } + keyHash, err := vrfv2Contracts.Coordinator.HashOfKey(context.Background(), provingKey) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingProvingKeyHash, err) + } + + chainID := env.EVMClient.GetChainID() + newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2TestConfig, numberOfTxKeysToCreate, chainID) + if err != nil { + return nil, nil, nil, err + } + nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) + } + allNativeTokenKeyAddressStrings := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) + allNativeTokenKeyAddresses := make([]common.Address, len(allNativeTokenKeyAddressStrings)) + + for _, addressString := range allNativeTokenKeyAddressStrings { + allNativeTokenKeyAddresses = append(allNativeTokenKeyAddresses, common.HexToAddress(addressString)) + } + + var vrfOwnerConfig VRFOwnerConfig + if useVRFOwner { + err := setupVRFOwnerContract(env, vrfv2Contracts, allNativeTokenKeyAddressStrings, allNativeTokenKeyAddresses, l) + if err != nil { + return nil, nil, nil, err + } + vrfOwnerConfig = VRFOwnerConfig{ + OwnerAddress: vrfv2Contracts.VRFOwner.Address(), + useVRFOwner: useVRFOwner, + } + } else { + vrfOwnerConfig = VRFOwnerConfig{ + OwnerAddress: "", + useVRFOwner: useVRFOwner, + } + } + + vrfJobSpecConfig := VRFJobSpecConfig{ + ForwardingAllowed: false, + CoordinatorAddress: vrfv2Contracts.Coordinator.Address(), + FromAddresses: allNativeTokenKeyAddressStrings, + EVMChainID: chainID.String(), + MinIncomingConfirmations: int(*vrfv2Config.MinimumConfirmations), + PublicKey: pubKeyCompressed, + EstimateGasMultiplier: 1, + BatchFulfillmentEnabled: false, + BatchFulfillmentGasMultiplier: 1.15, + PollPeriod: time.Second * 1, + RequestTimeout: time.Hour * 24, + VRFOwnerConfig: vrfOwnerConfig, + } + + l.Info().Msg("Creating VRFV2 Job") + vrfV2job, err := CreateVRFV2Job( + env.ClCluster.NodeAPIs()[0], + vrfJobSpecConfig, + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreateVRFV2Jobs, err) + } + + // this part is here because VRFv2 can work with only a specific key + // [[EVM.KeySpecific]] + // Key = '...' + nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, + node.WithVRFv2EVMEstimator(allNativeTokenKeyAddressStrings, *vrfv2Config.CLNodeMaxGasPriceGWei), + ) + l.Info().Msg("Restarting Node with new sending key PriceMax configuration") + err = env.ClCluster.Nodes[0].Restart(nodeConfig) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRestartCLNode, err) + } + + vrfv2KeyData := VRFV2KeyData{ + VRFKey: vrfKey, + EncodedProvingKey: provingKey, + KeyHash: keyHash, + } + + data := VRFV2Data{ + vrfv2KeyData, + vrfV2job, + nativeTokenPrimaryKeyAddress, + chainID, + } + + l.Info().Msg("VRFV2 environment setup is finished") + return vrfv2Contracts, subIDs, &data, nil +} + +func setupVRFOwnerContract(env *test_env.CLClusterTestEnv, vrfv2Contracts *VRFV2Contracts, allNativeTokenKeyAddressStrings []string, allNativeTokenKeyAddresses []common.Address, l zerolog.Logger) error { + l.Info().Msg("Setting up VRFOwner contract") + l.Info(). + Str("Coordinator", vrfv2Contracts.Coordinator.Address()). + Str("VRFOwner", vrfv2Contracts.VRFOwner.Address()). + Msg("Transferring ownership of Coordinator to VRFOwner") + err := vrfv2Contracts.Coordinator.TransferOwnership(common.HexToAddress(vrfv2Contracts.VRFOwner.Address())) + if err != nil { + return nil + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil + } + l.Info(). + Str("VRFOwner", vrfv2Contracts.VRFOwner.Address()). + Msg("Accepting VRF Ownership") + err = vrfv2Contracts.VRFOwner.AcceptVRFOwnership() + if err != nil { + return nil + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil + } + l.Info(). + Strs("Authorized Senders", allNativeTokenKeyAddressStrings). + Str("VRFOwner", vrfv2Contracts.VRFOwner.Address()). + Msg("Setting authorized senders for VRFOwner contract") + err = vrfv2Contracts.VRFOwner.SetAuthorizedSenders(allNativeTokenKeyAddresses) + if err != nil { + return nil + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return err +} + +func SetupVRFV2WrapperEnvironment( + env *test_env.CLClusterTestEnv, + vrfv2TestConfig tc.VRFv2TestConfig, + linkToken contracts.LinkToken, + mockNativeLINKFeed contracts.MockETHLINKFeed, + coordinator contracts.VRFCoordinatorV2, + keyHash [32]byte, + wrapperConsumerContractsAmount int, +) (*VRFV2WrapperContracts, *uint64, error) { + // Deploy VRF v2 direct funding contracts + wrapperContracts, err := DeployVRFV2DirectFundingContracts( + env.ContractDeployer, + env.EVMClient, + linkToken.Address(), + mockNativeLINKFeed.Address(), + coordinator, + wrapperConsumerContractsAmount, + ) + if err != nil { + return nil, nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + vrfv2Config := vrfv2TestConfig.GetVRFv2Config() + + // Configure VRF v2 wrapper contract + err = wrapperContracts.VRFV2Wrapper.SetConfig( + *vrfv2Config.General.WrapperGasOverhead, + *vrfv2Config.General.CoordinatorGasOverhead, + *vrfv2Config.General.WrapperPremiumPercentage, + keyHash, + *vrfv2Config.General.WrapperMaxNumberOfWords, + ) + if err != nil { + return nil, nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + // Fetch wrapper subscription ID + wrapperSubID, err := wrapperContracts.VRFV2Wrapper.GetSubID(context.Background()) + if err != nil { + return nil, nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + // Fund wrapper subscription + err = FundSubscriptions(env, big.NewFloat(*vrfv2Config.General.SubscriptionFundingAmountLink), linkToken, coordinator, []uint64{wrapperSubID}) + if err != nil { + return nil, nil, err + } + + // Fund consumer with LINK + err = linkToken.Transfer( + wrapperContracts.LoadTestConsumers[0].Address(), + big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(*vrfv2Config.General.WrapperConsumerFundingAmountLink)), + ) + if err != nil { + return nil, nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + return wrapperContracts, &wrapperSubID, nil +} + +func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, testConfig tc.CommonTestConfig, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { + var newNativeTokenKeyAddresses []string + for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { + newTxKey, response, err := env.ClCluster.NodeAPIs()[0].CreateTxKey("evm", chainID.String()) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrNodeNewTxKey, err) + } + if response.StatusCode != 200 { + return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) + } + newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.ID) + err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(*testConfig.GetCommonConfig().ChainlinkNodeFunding)) + if err != nil { + return nil, err + } + } + return newNativeTokenKeyAddresses, nil +} + +func CreateFundSubsAndAddConsumers( + env *test_env.CLClusterTestEnv, + subscriptionFundingAmountLink *big.Float, + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2, + consumers []contracts.VRFv2LoadTestConsumer, + numberOfSubToCreate int, +) ([]uint64, error) { + subIDs, err := CreateSubsAndFund(env, subscriptionFundingAmountLink, linkToken, coordinator, numberOfSubToCreate) + if err != nil { + return nil, err + } + subToConsumersMap := map[uint64][]contracts.VRFv2LoadTestConsumer{} + + //each subscription will have the same consumers + for _, subID := range subIDs { + subToConsumersMap[subID] = consumers + } + + err = AddConsumersToSubs( + subToConsumersMap, + coordinator, + ) + if err != nil { + return nil, err + } + + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return subIDs, nil +} + +func CreateSubsAndFund( + env *test_env.CLClusterTestEnv, + subscriptionFundingAmountLink *big.Float, + linkToken contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2, + subAmountToCreate int, +) ([]uint64, error) { + subs, err := CreateSubs(env, coordinator, subAmountToCreate) + if err != nil { + return nil, err + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + err = FundSubscriptions(env, subscriptionFundingAmountLink, linkToken, coordinator, subs) + if err != nil { + return nil, err + } + return subs, nil +} + +func CreateSubs( + env *test_env.CLClusterTestEnv, + coordinator contracts.VRFCoordinatorV2, + subAmountToCreate int, +) ([]uint64, error) { + var subIDArr []uint64 + + for i := 0; i < subAmountToCreate; i++ { + subID, err := CreateSubAndFindSubID(env, coordinator) + if err != nil { + return nil, err + } + subIDArr = append(subIDArr, subID) + } + return subIDArr, nil +} + +func AddConsumersToSubs( + subToConsumerMap map[uint64][]contracts.VRFv2LoadTestConsumer, + coordinator contracts.VRFCoordinatorV2, +) error { + for subID, consumers := range subToConsumerMap { + for _, consumer := range consumers { + err := coordinator.AddConsumer(subID, consumer.Address()) + if err != nil { + return fmt.Errorf("%s, err %w", ErrAddConsumerToSub, err) + } + } + } + return nil +} + +func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts.VRFCoordinatorV2) (uint64, error) { + tx, err := coordinator.CreateSubscription() + if err != nil { + return 0, fmt.Errorf("%s, err %w", ErrCreateVRFSubscription, err) + } + err = env.EVMClient.WaitForEvents() + if err != nil { + return 0, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + receipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + if err != nil { + return 0, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + + //SubscriptionsCreated Log should be emitted with the subscription ID + subID := receipt.Logs[0].Topics[1].Big().Uint64() + + return subID, nil +} + +func FundSubscriptions( + env *test_env.CLClusterTestEnv, + subscriptionFundingAmountLink *big.Float, + linkAddress contracts.LinkToken, + coordinator contracts.VRFCoordinatorV2, + subIDs []uint64, +) error { + for _, subID := range subIDs { + //Link Billing + amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) + err := FundVRFCoordinatorV2Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + } + } + err := env.EVMClient.WaitForEvents() + if err != nil { + return fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) + } + return nil +} + +func DirectFundingRequestRandomnessAndWaitForFulfillment( + l zerolog.Logger, + consumer contracts.VRFv2WrapperLoadTestConsumer, + coordinator contracts.VRFCoordinatorV2, + subID uint64, + vrfv2Data *VRFV2Data, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, + randomWordsFulfilledEventTimeout time.Duration, +) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { + logRandRequest(l, consumer.Address(), coordinator.Address(), subID, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) + _, err := consumer.RequestRandomness( + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + } + wrapperAddress, err := consumer.GetWrapper(context.Background()) + if err != nil { + return nil, fmt.Errorf("error getting wrapper address, err: %w", err) + } + fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( + wrapperAddress.String(), + coordinator, + vrfv2Data, + subID, + randomWordsFulfilledEventTimeout, + l, + ) + return fulfillmentEvents, err +} + +func RequestRandomnessAndWaitForFulfillment( + l zerolog.Logger, + consumer contracts.VRFv2LoadTestConsumer, + coordinator contracts.VRFCoordinatorV2, + subID uint64, + vrfv2Data *VRFV2Data, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, + randomWordsFulfilledEventTimeout time.Duration, +) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { + logRandRequest(l, consumer.Address(), coordinator.Address(), subID, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) + _, err := consumer.RequestRandomness( + vrfv2Data.KeyHash, + subID, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + } + + fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( + consumer.Address(), + coordinator, + vrfv2Data, + subID, + randomWordsFulfilledEventTimeout, + l, + ) + return fulfillmentEvents, err +} + +func RequestRandomnessWithForceFulfillAndWaitForFulfillment( + l zerolog.Logger, + consumer contracts.VRFv2LoadTestConsumer, + coordinator contracts.VRFCoordinatorV2, + vrfOwner contracts.VRFOwner, + vrfv2Data *VRFV2Data, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, + subTopUpAmount *big.Int, + linkAddress common.Address, + randomWordsFulfilledEventTimeout time.Duration, +) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, *vrf_owner.VRFOwnerRandomWordsForced, error) { + logRandRequest(l, consumer.Address(), coordinator.Address(), 0, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) + _, err := consumer.RequestRandomWordsWithForceFulfill( + vrfv2Data.KeyHash, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, + subTopUpAmount, + linkAddress, + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) + } + + randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfv2Data.KeyHash}, + nil, + []common.Address{common.HexToAddress(consumer.Address())}, + time.Minute*1, + ) + if err != nil { + return nil, nil, nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) + } + LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) + + errorChannel := make(chan error) + configSetEventChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) + randWordsFulfilledEventChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled) + randWordsForcedEventChannel := make(chan *vrf_owner.VRFOwnerRandomWordsForced) + + go func() { + configSetEvent, err := coordinator.WaitForConfigSetEvent( + randomWordsFulfilledEventTimeout, + ) + if err != nil { + l.Error().Err(err).Msg("error waiting for ConfigSetEvent") + errorChannel <- err + } + configSetEventChannel <- configSetEvent + }() + + go func() { + randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( + []*big.Int{randomWordsRequestedEvent.RequestId}, + randomWordsFulfilledEventTimeout, + ) + if err != nil { + l.Error().Err(err).Msg("error waiting for RandomWordsFulfilledEvent") + errorChannel <- err + } + randWordsFulfilledEventChannel <- randomWordsFulfilledEvent + }() + + go func() { + randomWordsForcedEvent, err := vrfOwner.WaitForRandomWordsForcedEvent( + []*big.Int{randomWordsRequestedEvent.RequestId}, + nil, + nil, + randomWordsFulfilledEventTimeout, + ) + if err != nil { + l.Error().Err(err).Msg("error waiting for RandomWordsForcedEvent") + errorChannel <- err + } + randWordsForcedEventChannel <- randomWordsForcedEvent + }() + + var configSetEvent *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet + var randomWordsFulfilledEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled + var randomWordsForcedEvent *vrf_owner.VRFOwnerRandomWordsForced + for i := 0; i < 3; i++ { + select { + case err = <-errorChannel: + return nil, nil, nil, err + case configSetEvent = <-configSetEventChannel: + case randomWordsFulfilledEvent = <-randWordsFulfilledEventChannel: + LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent) + case randomWordsForcedEvent = <-randWordsForcedEventChannel: + LogRandomWordsForcedEvent(l, vrfOwner, randomWordsForcedEvent) + case <-time.After(randomWordsFulfilledEventTimeout): + return nil, nil, nil, fmt.Errorf("timeout waiting for ConfigSet, RandomWordsFulfilled and RandomWordsForced events") + } + } + return configSetEvent, randomWordsFulfilledEvent, randomWordsForcedEvent, err +} + +func WaitForRequestAndFulfillmentEvents( + consumerAddress string, + coordinator contracts.VRFCoordinatorV2, + vrfv2Data *VRFV2Data, + subID uint64, + randomWordsFulfilledEventTimeout time.Duration, + l zerolog.Logger, +) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { + randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( + [][32]byte{vrfv2Data.KeyHash}, + []uint64{subID}, + []common.Address{common.HexToAddress(consumerAddress)}, + time.Minute*1, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) + } + + LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) + randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( + []*big.Int{randomWordsRequestedEvent.RequestId}, + randomWordsFulfilledEventTimeout, + ) + if err != nil { + return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsFulfilledEvent, err) + } + + LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent) + return randomWordsFulfilledEvent, err +} + +func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2LoadTestConsumer, timeout time.Duration, wg *sync.WaitGroup) (*big.Int, *big.Int, error) { + metricsChannel := make(chan *contracts.VRFLoadTestMetrics) + metricsErrorChannel := make(chan error) + + testContext, testCancel := context.WithTimeout(context.Background(), timeout) + defer testCancel() + + ticker := time.NewTicker(time.Second * 1) + var metrics *contracts.VRFLoadTestMetrics + for { + select { + case <-testContext.Done(): + ticker.Stop() + wg.Done() + return metrics.RequestCount, metrics.FulfilmentCount, + fmt.Errorf("timeout waiting for rand request and fulfilments to be equal AFTER performance test was executed. Request Count: %d, Fulfilment Count: %d", + metrics.RequestCount.Uint64(), metrics.FulfilmentCount.Uint64()) + case <-ticker.C: + go retrieveLoadTestMetrics(consumer, metricsChannel, metricsErrorChannel) + case metrics = <-metricsChannel: + if metrics.RequestCount.Cmp(metrics.FulfilmentCount) == 0 { + ticker.Stop() + wg.Done() + return metrics.RequestCount, metrics.FulfilmentCount, nil + } + case err := <-metricsErrorChannel: + ticker.Stop() + wg.Done() + return nil, nil, err + } + } +} + +func retrieveLoadTestMetrics( + consumer contracts.VRFv2LoadTestConsumer, + metricsChannel chan *contracts.VRFLoadTestMetrics, + metricsErrorChannel chan error, +) { + metrics, err := consumer.GetLoadTestMetrics(context.Background()) + if err != nil { + metricsErrorChannel <- err + } + metricsChannel <- metrics +} + +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.Debug(). + Str("Coordinator", coordinator.Address()). + Str("Request ID", randomWordsRequestedEvent.RequestId.String()). + Uint64("Subscription ID", randomWordsRequestedEvent.SubId). + Str("Sender Address", randomWordsRequestedEvent.Sender.String()). + Interface("Keyhash", randomWordsRequestedEvent.KeyHash). + Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). + Uint32("Number of Words", randomWordsRequestedEvent.NumWords). + Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). + Msg("RandomnessRequested Event") +} + +func LogRandomWordsFulfilledEvent( + l zerolog.Logger, + coordinator contracts.VRFCoordinatorV2, + randomWordsFulfilledEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, +) { + l.Debug(). + 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). + 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, + coordinator string, + subID uint64, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, +) { + l.Debug(). + Str("Consumer", consumer). + Str("Coordinator", coordinator). + Uint64("SubID", subID). + Uint16("MinimumConfirmations", minimumConfirmations). + Uint32("CallbackGasLimit", callbackGasLimit). + Uint32("NumberOfWords", numberOfWords). + Uint16("RandomnessRequestCountPerRequest", randomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", randomnessRequestCountPerRequestDeviation). + Msg("Requesting randomness") +} diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_models.go b/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_models.go similarity index 100% rename from integration-tests/actions/vrfv2plus/vrfv2plus_models.go rename to integration-tests/actions/vrf/vrfv2plus/vrfv2plus_models.go diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go b/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go similarity index 79% rename from integration-tests/actions/vrfv2plus/vrfv2plus_steps.go rename to integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go index 70320530aa8..fc2a47f53ef 100644 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_steps.go +++ b/integration-tests/actions/vrf/vrfv2plus/vrfv2plus_steps.go @@ -18,14 +18,16 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "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" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/types" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + 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" - chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" ) var ( @@ -65,6 +67,20 @@ var ( ErrDeployWrapper = "error deploying VRFV2PlusWrapper" ) +type VRFJobSpecConfig struct { + ForwardingAllowed bool + CoordinatorAddress string + FromAddresses []string + EVMChainID string + MinIncomingConfirmations int + PublicKey string + BatchFulfillmentEnabled bool + BatchFulfillmentGasMultiplier float64 + EstimateGasMultiplier float64 + PollPeriod time.Duration + RequestTimeout time.Duration +} + func DeployVRFV2_5Contracts( contractDeployer contracts.ContractDeployer, chainClient blockchain.EVMClient, @@ -111,15 +127,13 @@ func DeployVRFV2PlusConsumers(contractDeployer contracts.ContractDeployer, coord func CreateVRFV2PlusJob( chainlinkNode *client.ChainlinkClient, - coordinatorAddress string, - nativeTokenKeyAddresses []string, - pubKeyCompressed string, - chainID string, - minIncomingConfirmations uint16, + vrfJobSpecConfig VRFJobSpecConfig, ) (*client.Job, error) { jobUUID := uuid.New() os := &client.VRFV2PlusTxPipelineSpec{ - Address: coordinatorAddress, + Address: vrfJobSpecConfig.CoordinatorAddress, + EstimateGasMultiplier: vrfJobSpecConfig.EstimateGasMultiplier, + FromAddress: vrfJobSpecConfig.FromAddresses[0], } ost, err := os.String() if err != nil { @@ -127,16 +141,18 @@ func CreateVRFV2PlusJob( } job, err := chainlinkNode.MustCreateJob(&client.VRFV2PlusJobSpec{ - Name: fmt.Sprintf("vrf-v2-plus-%s", jobUUID), - CoordinatorAddress: coordinatorAddress, - FromAddresses: nativeTokenKeyAddresses, - EVMChainID: chainID, - MinIncomingConfirmations: int(minIncomingConfirmations), - PublicKey: pubKeyCompressed, - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - BatchFulfillmentEnabled: false, - PollPeriod: time.Second, + Name: fmt.Sprintf("vrf-v2-plus-%s", jobUUID), + CoordinatorAddress: vrfJobSpecConfig.CoordinatorAddress, + FromAddresses: vrfJobSpecConfig.FromAddresses, + EVMChainID: vrfJobSpecConfig.EVMChainID, + MinIncomingConfirmations: vrfJobSpecConfig.MinIncomingConfirmations, + PublicKey: vrfJobSpecConfig.PublicKey, + ExternalJobID: jobUUID.String(), + ObservationSource: ost, + BatchFulfillmentEnabled: vrfJobSpecConfig.BatchFulfillmentEnabled, + BatchFulfillmentGasMultiplier: vrfJobSpecConfig.BatchFulfillmentGasMultiplier, + PollPeriod: vrfJobSpecConfig.PollPeriod, + RequestTimeout: vrfJobSpecConfig.RequestTimeout, }) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2PlusJob, err) @@ -147,7 +163,6 @@ func CreateVRFV2PlusJob( func VRFV2_5RegisterProvingKey( vrfKey *client.VRFKey, - oracleAddress string, coordinator contracts.VRFCoordinatorV2_5, ) (VRFV2PlusEncodedProvingKey, error) { provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) @@ -155,7 +170,6 @@ func VRFV2_5RegisterProvingKey( return VRFV2PlusEncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrEncodingProvingKey, err) } err = coordinator.RegisterProvingKey( - oracleAddress, provingKey, ) if err != nil { @@ -166,7 +180,6 @@ func VRFV2_5RegisterProvingKey( func VRFV2PlusUpgradedVersionRegisterProvingKey( vrfKey *client.VRFKey, - oracleAddress string, coordinator contracts.VRFCoordinatorV2PlusUpgradedVersion, ) (VRFV2PlusEncodedProvingKey, error) { provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) @@ -174,7 +187,6 @@ func VRFV2PlusUpgradedVersionRegisterProvingKey( return VRFV2PlusEncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrEncodingProvingKey, err) } err = coordinator.RegisterProvingKey( - oracleAddress, provingKey, ) if err != nil { @@ -204,10 +216,9 @@ func FundVRFCoordinatorV2_5Subscription( // SetupVRFV2_5Environment will create specified number of subscriptions and add the same conumer/s to each of them func SetupVRFV2_5Environment( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusTestConfig types.VRFv2PlusTestConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, - registerProvingKeyAgainstAddress string, numberOfTxKeysToCreate int, numberOfConsumers int, numberOfSubToCreate int, @@ -221,15 +232,16 @@ func SetupVRFV2_5Environment( } l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") + vrfv2PlusConfig := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General err = vrfv2_5Contracts.Coordinator.SetConfig( - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, - vrfv2PlusConfig.StalenessSeconds, - vrfv2PlusConfig.GasAfterPaymentCalculation, - big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse), + *vrfv2PlusConfig.MinimumConfirmations, + *vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, + *vrfv2PlusConfig.StalenessSeconds, + *vrfv2PlusConfig.GasAfterPaymentCalculation, + big.NewInt(*vrfv2PlusConfig.FallbackWeiPerUnitLink), vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig{ - FulfillmentFlatFeeLinkPPM: vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, - FulfillmentFlatFeeNativePPM: vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + FulfillmentFlatFeeLinkPPM: *vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + FulfillmentFlatFeeNativePPM: *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, }, ) if err != nil { @@ -251,9 +263,12 @@ func SetupVRFV2_5Environment( Msg("Creating and funding subscriptions, adding consumers") subIDs, err := CreateFundSubsAndAddConsumers( env, - vrfv2PlusConfig, + big.NewFloat(*vrfv2PlusConfig.SubscriptionFundingAmountNative), + big.NewFloat(*vrfv2PlusConfig.SubscriptionFundingAmountLink), linkToken, - vrfv2_5Contracts.Coordinator, vrfv2_5Contracts.LoadTestConsumers, numberOfSubToCreate) + vrfv2_5Contracts.Coordinator, vrfv2_5Contracts.LoadTestConsumers, + numberOfSubToCreate, + vrfv2plus_config.BillingType(*vrfv2PlusConfig.SubscriptionBillingType)) if err != nil { return nil, nil, nil, err } @@ -265,7 +280,7 @@ func SetupVRFV2_5Environment( pubKeyCompressed := vrfKey.Data.ID l.Info().Str("Coordinator", vrfv2_5Contracts.Coordinator.Address()).Msg("Registering Proving Key") - provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfv2_5Contracts.Coordinator) + provingKey, err := VRFV2_5RegisterProvingKey(vrfKey, vrfv2_5Contracts.Coordinator) if err != nil { return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRegisteringProvingKey, err) } @@ -275,7 +290,7 @@ func SetupVRFV2_5Environment( } chainID := env.EVMClient.GetChainID() - newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2PlusConfig, numberOfTxKeysToCreate, chainID) + newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2PlusTestConfig, numberOfTxKeysToCreate, chainID) if err != nil { return nil, nil, nil, err } @@ -285,14 +300,24 @@ func SetupVRFV2_5Environment( } allNativeTokenKeyAddresses := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) + vrfJobSpecConfig := VRFJobSpecConfig{ + ForwardingAllowed: false, + CoordinatorAddress: vrfv2_5Contracts.Coordinator.Address(), + FromAddresses: allNativeTokenKeyAddresses, + EVMChainID: chainID.String(), + MinIncomingConfirmations: int(*vrfv2PlusConfig.MinimumConfirmations), + PublicKey: pubKeyCompressed, + EstimateGasMultiplier: 1, + BatchFulfillmentEnabled: false, + BatchFulfillmentGasMultiplier: 1.15, + PollPeriod: time.Second * 1, + RequestTimeout: time.Hour * 24, + } + l.Info().Msg("Creating VRFV2 Plus Job") job, err := CreateVRFV2PlusJob( env.ClCluster.NodeAPIs()[0], - vrfv2_5Contracts.Coordinator.Address(), - allNativeTokenKeyAddresses, - pubKeyCompressed, - chainID.String(), - vrfv2PlusConfig.MinimumConfirmations, + vrfJobSpecConfig, ) if err != nil { return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreateVRFV2PlusJobs, err) @@ -303,7 +328,7 @@ func SetupVRFV2_5Environment( // Key = '...' nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, node.WithLogPollInterval(1*time.Second), - node.WithVRFv2EVMEstimator(allNativeTokenKeyAddresses, vrfv2PlusConfig.CLNodeMaxGasPriceGWei), + node.WithVRFv2EVMEstimator(allNativeTokenKeyAddresses, *vrfv2PlusConfig.CLNodeMaxGasPriceGWei), ) l.Info().Msg("Restarting Node with new sending key PriceMax configuration and log poll period configuration") err = env.ClCluster.Nodes[0].Restart(nodeConfig) @@ -328,7 +353,7 @@ func SetupVRFV2_5Environment( return vrfv2_5Contracts, subIDs, &data, nil } -func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { +func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, commonTestConfig tc.CommonTestConfig, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { var newNativeTokenKeyAddresses []string for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { newTxKey, response, err := env.ClCluster.NodeAPIs()[0].CreateTxKey("evm", chainID.String()) @@ -339,7 +364,7 @@ func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2PlusConfig vr return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) } newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.ID) - err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)) + err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(*commonTestConfig.GetCommonConfig().ChainlinkNodeFunding)) if err != nil { return nil, err } @@ -349,13 +374,23 @@ func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2PlusConfig vr func CreateFundSubsAndAddConsumers( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + subscriptionFundingAmountNative *big.Float, + subscriptionFundingAmountLink *big.Float, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, consumers []contracts.VRFv2PlusLoadTestConsumer, numberOfSubToCreate int, + subscriptionBillingType vrfv2plus_config.BillingType, ) ([]*big.Int, error) { - subIDs, err := CreateSubsAndFund(env, vrfv2PlusConfig, linkToken, coordinator, numberOfSubToCreate) + subIDs, err := CreateSubsAndFund( + env, + subscriptionFundingAmountNative, + subscriptionFundingAmountLink, + linkToken, + coordinator, + numberOfSubToCreate, + subscriptionBillingType, + ) if err != nil { return nil, err } @@ -383,10 +418,12 @@ func CreateFundSubsAndAddConsumers( func CreateSubsAndFund( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + subscriptionFundingAmountNative *big.Float, + subscriptionFundingAmountLink *big.Float, linkToken contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subAmountToCreate int, + subscriptionBillingType vrfv2plus_config.BillingType, ) ([]*big.Int, error) { subs, err := CreateSubs(env, coordinator, subAmountToCreate) if err != nil { @@ -396,7 +433,15 @@ func CreateSubsAndFund( if err != nil { return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, coordinator, subs) + err = FundSubscriptions( + env, + subscriptionFundingAmountNative, + subscriptionFundingAmountLink, + linkToken, + coordinator, + subs, + subscriptionBillingType, + ) if err != nil { return nil, err } @@ -458,26 +503,50 @@ func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts func FundSubscriptions( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + subscriptionFundingAmountNative *big.Float, + subscriptionFundingAmountLink *big.Float, linkAddress contracts.LinkToken, coordinator contracts.VRFCoordinatorV2_5, subIDs []*big.Int, + subscriptionBillingType vrfv2plus_config.BillingType, ) error { for _, subID := range subIDs { - //Native Billing - amountWei := conversions.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountNative)) - err := coordinator.FundSubscriptionWithNative( - subID, - amountWei, - ) - if err != nil { - return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) - } - //Link Billing - amountJuels := conversions.EtherToWei(big.NewFloat(vrfv2PlusConfig.SubscriptionFundingAmountLink)) - err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) - if err != nil { - return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + switch subscriptionBillingType { + case vrfv2plus_config.BillingType_Native: + //Native Billing + amountWei := conversions.EtherToWei(subscriptionFundingAmountNative) + err := coordinator.FundSubscriptionWithNative( + subID, + amountWei, + ) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) + } + case vrfv2plus_config.BillingType_Link: + //Link Billing + amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) + err := FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + } + case vrfv2plus_config.BillingType_Link_and_Native: + //Native Billing + amountWei := conversions.EtherToWei(subscriptionFundingAmountNative) + err := coordinator.FundSubscriptionWithNative( + subID, + amountWei, + ) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithNativeToken, err) + } + //Link Billing + amountJuels := conversions.EtherToWei(subscriptionFundingAmountLink) + err = FundVRFCoordinatorV2_5Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) + if err != nil { + return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) + } + default: + return fmt.Errorf("invalid billing type: %s", subscriptionBillingType) } } err := env.EVMClient.WaitForEvents() @@ -517,19 +586,22 @@ func RequestRandomnessAndWaitForFulfillment( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, randomnessRequestCountPerRequest uint16, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) + logRandRequest(l, consumer.Address(), coordinator.Address(), subID, isNativeBilling, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) _, err := consumer.RequestRandomness( vrfv2PlusData.KeyHash, subID, - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.CallbackGasLimit, + minimumConfirmations, + callbackGasLimit, isNativeBilling, - vrfv2PlusConfig.NumberOfWords, + numberOfWords, randomnessRequestCountPerRequest, ) if err != nil { @@ -553,18 +625,22 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, l zerolog.Logger, ) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsFulfilled, error) { - logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) + logRandRequest(l, consumer.Address(), coordinator.Address(), subID, isNativeBilling, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) _, err := consumer.RequestRandomness( vrfv2PlusData.KeyHash, subID, - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.CallbackGasLimit, + minimumConfirmations, + callbackGasLimit, isNativeBilling, - vrfv2PlusConfig.NumberOfWords, - vrfv2PlusConfig.RandomnessRequestCountPerRequest, + numberOfWords, + randomnessRequestCountPerRequest, ) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) @@ -597,14 +673,14 @@ func RequestRandomnessAndWaitForFulfillmentUpgraded( func SetupVRFV2PlusWrapperEnvironment( env *test_env.CLClusterTestEnv, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + vrfv2PlusTestConfig types.VRFv2PlusTestConfig, linkToken contracts.LinkToken, mockNativeLINKFeed contracts.MockETHLINKFeed, coordinator contracts.VRFCoordinatorV2_5, keyHash [32]byte, wrapperConsumerContractsAmount int, ) (*VRFV2PlusWrapperContracts, *big.Int, error) { - + vrfv2PlusConfig := vrfv2PlusTestConfig.GetVRFv2PlusConfig().General wrapperContracts, err := DeployVRFV2PlusDirectFundingContracts( env.ContractDeployer, env.EVMClient, @@ -623,15 +699,15 @@ func SetupVRFV2PlusWrapperEnvironment( return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } err = wrapperContracts.VRFV2PlusWrapper.SetConfig( - vrfv2PlusConfig.WrapperGasOverhead, - vrfv2PlusConfig.CoordinatorGasOverhead, - vrfv2PlusConfig.WrapperPremiumPercentage, + *vrfv2PlusConfig.WrapperGasOverhead, + *vrfv2PlusConfig.CoordinatorGasOverhead, + *vrfv2PlusConfig.WrapperPremiumPercentage, keyHash, - vrfv2PlusConfig.WrapperMaxNumberOfWords, - vrfv2PlusConfig.StalenessSeconds, - big.NewInt(vrfv2PlusConfig.FallbackWeiPerUnitLink), - vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, - vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + *vrfv2PlusConfig.WrapperMaxNumberOfWords, + *vrfv2PlusConfig.StalenessSeconds, + big.NewInt(*vrfv2PlusConfig.FallbackWeiPerUnitLink), + *vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, ) if err != nil { return nil, nil, err @@ -653,7 +729,7 @@ func SetupVRFV2PlusWrapperEnvironment( return nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) } - err = FundSubscriptions(env, vrfv2PlusConfig, linkToken, coordinator, []*big.Int{wrapperSubID}) + err = FundSubscriptions(env, big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), big.NewFloat(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, coordinator, []*big.Int{wrapperSubID}, vrfv2plus_config.BillingType(*vrfv2PlusTestConfig.GetVRFv2PlusConfig().General.SubscriptionBillingType)) if err != nil { return nil, nil, err } @@ -661,7 +737,7 @@ func SetupVRFV2PlusWrapperEnvironment( //fund consumer with Link err = linkToken.Transfer( wrapperContracts.LoadTestConsumers[0].Address(), - big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(vrfv2PlusConfig.WrapperConsumerFundingAmountLink)), + big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(*vrfv2PlusConfig.WrapperConsumerFundingAmountLink)), ) if err != nil { return nil, nil, err @@ -672,7 +748,7 @@ func SetupVRFV2PlusWrapperEnvironment( } //fund consumer with Eth - err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) + err = wrapperContracts.LoadTestConsumers[0].Fund(big.NewFloat(*vrfv2PlusConfig.WrapperConsumerFundingAmountNativeToken)) if err != nil { return nil, nil, err } @@ -730,27 +806,31 @@ func DirectFundingRequestRandomnessAndWaitForFulfillment( vrfv2PlusData *VRFV2PlusData, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16, randomWordsFulfilledEventTimeout time.Duration, l zerolog.Logger, ) (*vrf_coordinator_v2_5.VRFCoordinatorV25RandomWordsFulfilled, error) { - logRandRequest(consumer.Address(), coordinator.Address(), subID, isNativeBilling, vrfv2PlusConfig, l) + logRandRequest(l, consumer.Address(), coordinator.Address(), subID, isNativeBilling, minimumConfirmations, callbackGasLimit, numberOfWords, randomnessRequestCountPerRequest, randomnessRequestCountPerRequestDeviation) if isNativeBilling { _, err := consumer.RequestRandomnessNative( - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.CallbackGasLimit, - vrfv2PlusConfig.NumberOfWords, - vrfv2PlusConfig.RandomnessRequestCountPerRequest, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, ) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingNativePayment, err) } } else { _, err := consumer.RequestRandomness( - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.CallbackGasLimit, - vrfv2PlusConfig.NumberOfWords, - vrfv2PlusConfig.RandomnessRequestCountPerRequest, + minimumConfirmations, + callbackGasLimit, + numberOfWords, + randomnessRequestCountPerRequest, ) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrRequestRandomnessDirectFundingLinkPayment, err) @@ -848,9 +928,8 @@ func ReturnFundsForFulfilledRequests(client blockchain.EVMClient, coordinator co Str("LINK amount", linkTotalBalance.String()). Str("Returning to", defaultWallet). Msg("Returning LINK for fulfilled requests") - err = coordinator.OracleWithdraw( + err = coordinator.Withdraw( common.HexToAddress(defaultWallet), - linkTotalBalance, ) if err != nil { return fmt.Errorf("Error withdrawing LINK from coordinator to default wallet, err: %w", err) @@ -860,12 +939,11 @@ func ReturnFundsForFulfilledRequests(client blockchain.EVMClient, coordinator co return fmt.Errorf("Error getting NATIVE total balance, err: %w", err) } l.Info(). - Str("Native Token amount", linkTotalBalance.String()). + Str("Native Token amount", nativeTotalBalance.String()). Str("Returning to", defaultWallet). Msg("Returning Native Token for fulfilled requests") - err = coordinator.OracleWithdrawNative( + err = coordinator.WithdrawNative( common.HexToAddress(defaultWallet), - nativeTotalBalance, ) if err != nil { return fmt.Errorf("Error withdrawing NATIVE from coordinator to default wallet, err: %w", err) @@ -1026,20 +1104,25 @@ func LogFulfillmentDetailsNativeBilling( } func logRandRequest( + l zerolog.Logger, consumer string, coordinator string, subID *big.Int, isNativeBilling bool, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, - l zerolog.Logger) { + minimumConfirmations uint16, + callbackGasLimit uint32, + numberOfWords uint32, + randomnessRequestCountPerRequest uint16, + randomnessRequestCountPerRequestDeviation uint16) { l.Debug(). Str("Consumer", consumer). Str("Coordinator", coordinator). Str("SubID", subID.String()). Bool("IsNativePayment", isNativeBilling). - Uint16("MinimumConfirmations", vrfv2PlusConfig.MinimumConfirmations). - Uint32("CallbackGasLimit", vrfv2PlusConfig.CallbackGasLimit). - Uint16("RandomnessRequestCountPerRequest", vrfv2PlusConfig.RandomnessRequestCountPerRequest). - Uint16("RandomnessRequestCountPerRequestDeviation", vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation). + Uint16("MinimumConfirmations", minimumConfirmations). + Uint32("CallbackGasLimit", callbackGasLimit). + Uint32("NumberOfWords", numberOfWords). + Uint16("RandomnessRequestCountPerRequest", randomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", randomnessRequestCountPerRequestDeviation). Msg("Requesting randomness") } diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_config/config.go b/integration-tests/actions/vrfv2_actions/vrfv2_config/config.go deleted file mode 100644 index aa2ac7f59ea..00000000000 --- a/integration-tests/actions/vrfv2_actions/vrfv2_config/config.go +++ /dev/null @@ -1,54 +0,0 @@ -package vrfv2_config - -import "time" - -type VRFV2Config struct { - ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of native currency to fund each chainlink node with - CLNodeMaxGasPriceGWei int64 `envconfig:"MAX_GAS_PRICE_GWEI" default:"1000"` // Max gas price in GWei for the chainlink node - IsNativePayment bool `envconfig:"IS_NATIVE_PAYMENT" default:"false"` // Whether to use native payment or LINK token - LinkNativeFeedResponse int64 `envconfig:"LINK_NATIVE_FEED_RESPONSE" default:"1000000000000000000"` // Response of the LINK/ETH feed - MinimumConfirmations uint16 `envconfig:"MINIMUM_CONFIRMATIONS" default:"3"` // Minimum number of confirmations for the VRF Coordinator - SubscriptionFundingAmountLink float64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"5"` // Amount of LINK to fund the subscription with - NumberOfWords uint32 `envconfig:"NUMBER_OF_WORDS" default:"3"` // Number of words to request - CallbackGasLimit uint32 `envconfig:"CALLBACK_GAS_LIMIT" default:"1000000"` // Gas limit for the callback - MaxGasLimitCoordinatorConfig uint32 `envconfig:"MAX_GAS_LIMIT_COORDINATOR_CONFIG" default:"2500000"` // Max gas limit for the VRF Coordinator config - FallbackWeiPerUnitLink int64 `envconfig:"FALLBACK_WEI_PER_UNIT_LINK" default:"60000000000000000"` // Fallback wei per unit LINK for the VRF Coordinator config - StalenessSeconds uint32 `envconfig:"STALENESS_SECONDS" default:"86400"` // Staleness in seconds for the VRF Coordinator config - GasAfterPaymentCalculation uint32 `envconfig:"GAS_AFTER_PAYMENT_CALCULATION" default:"33825"` // Gas after payment calculation for the VRF Coordinator config - FulfillmentFlatFeeLinkPPMTier1 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_1" default:"500"` - FulfillmentFlatFeeLinkPPMTier2 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_2" default:"500"` - FulfillmentFlatFeeLinkPPMTier3 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_3" default:"500"` - FulfillmentFlatFeeLinkPPMTier4 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_4" default:"500"` - FulfillmentFlatFeeLinkPPMTier5 uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM_TIER_5" default:"500"` - ReqsForTier2 int64 `envconfig:"REQS_FOR_TIER_2" default:"0"` - ReqsForTier3 int64 `envconfig:"REQS_FOR_TIER_3" default:"0"` - ReqsForTier4 int64 `envconfig:"REQS_FOR_TIER_4" default:"0"` - ReqsForTier5 int64 `envconfig:"REQS_FOR_TIER_5" default:"0"` - - NumberOfSubToCreate int `envconfig:"NUMBER_OF_SUB_TO_CREATE" default:"1"` // Number of subscriptions to create - - RandomnessRequestCountPerRequest uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST" default:"1"` // How many randomness requests to send per request - RandomnessRequestCountPerRequestDeviation uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST_DEVIATION" default:"0"` // How many randomness requests to send per request - - RandomWordsFulfilledEventTimeout time.Duration `envconfig:"RANDOM_WORDS_FULFILLED_EVENT_TIMEOUT" default:"2m"` // How long to wait for the RandomWordsFulfilled event to be emitted - - //Wrapper Config - WrapperGasOverhead uint32 `envconfig:"WRAPPER_GAS_OVERHEAD" default:"50000"` - CoordinatorGasOverhead uint32 `envconfig:"COORDINATOR_GAS_OVERHEAD" default:"52000"` - WrapperPremiumPercentage uint8 `envconfig:"WRAPPER_PREMIUM_PERCENTAGE" default:"25"` - WrapperMaxNumberOfWords uint8 `envconfig:"WRAPPER_MAX_NUMBER_OF_WORDS" default:"10"` - WrapperConsumerFundingAmountNativeToken float64 `envconfig:"WRAPPER_CONSUMER_FUNDING_AMOUNT_NATIVE_TOKEN" default:"1"` - WrapperConsumerFundingAmountLink int64 `envconfig:"WRAPPER_CONSUMER_FUNDING_AMOUNT_LINK" default:"10"` - - //LOAD/SOAK Test Config - TestDuration time.Duration `envconfig:"TEST_DURATION" default:"3m"` // How long to run the test for - RPS int64 `envconfig:"RPS" default:"1"` // How many requests per second to send - RateLimitUnitDuration time.Duration `envconfig:"RATE_LIMIT_UNIT_DURATION" default:"1m"` - //Using existing environment and contracts - UseExistingEnv bool `envconfig:"USE_EXISTING_ENV" default:"false"` // Whether to use an existing environment or create a new one - CoordinatorAddress string `envconfig:"COORDINATOR_ADDRESS" default:""` // Coordinator address - ConsumerAddress string `envconfig:"CONSUMER_ADDRESS" default:""` // Consumer address - LinkAddress string `envconfig:"LINK_ADDRESS" default:""` // Link address - SubID uint64 `envconfig:"SUB_ID" default:""` // Subscription ID - KeyHash string `envconfig:"KEY_HASH" default:""` -} diff --git a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go b/integration-tests/actions/vrfv2_actions/vrfv2_steps.go deleted file mode 100644 index 4ea4a4a8534..00000000000 --- a/integration-tests/actions/vrfv2_actions/vrfv2_steps.go +++ /dev/null @@ -1,628 +0,0 @@ -package vrfv2_actions - -import ( - "context" - "fmt" - "math/big" - "sync" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/rs/zerolog" - - commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" - "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" - - "github.com/google/uuid" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" -) - -var ( - 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" - ErrRegisteringProvingKey = "error registering a proving key on Coordinator contract" - ErrRegisterProvingKey = "error registering proving keys" - ErrEncodingProvingKey = "error encoding proving key" - ErrCreatingVRFv2Key = "error creating VRFv2 key" - ErrDeployBlockHashStore = "error deploying blockhash store" - ErrDeployCoordinator = "error deploying VRF CoordinatorV2" - ErrAdvancedConsumer = "error deploying VRFv2 Advanced Consumer" - ErrABIEncodingFunding = "error Abi encoding subscriptionID" - ErrSendingLinkToken = "error sending Link token" - ErrCreatingVRFv2Job = "error creating VRFv2 job" - ErrParseJob = "error parsing job definition" - ErrDeployVRFV2Contracts = "error deploying VRFV2 contracts" - ErrSetVRFCoordinatorConfig = "error setting config for VRF Coordinator contract" - ErrCreateVRFSubscription = "error creating VRF Subscription" - ErrAddConsumerToSub = "error adding consumer to VRF Subscription" - ErrFundSubWithLinkToken = "error funding subscription with Link tokens" - ErrCreateVRFV2Jobs = "error creating VRF V2 Jobs" - ErrGetPrimaryKey = "error getting primary ETH key address" - ErrRestartCLNode = "error restarting CL node" - ErrWaitTXsComplete = "error waiting for TXs to complete" - ErrRequestRandomness = "error requesting randomness" - - ErrWaitRandomWordsRequestedEvent = "error waiting for RandomWordsRequested event" - ErrWaitRandomWordsFulfilledEvent = "error waiting for RandomWordsFulfilled event" -) - -func DeployVRFV2Contracts( - contractDeployer contracts.ContractDeployer, - chainClient blockchain.EVMClient, - linkTokenContract contracts.LinkToken, - linkEthFeedContract contracts.MockETHLINKFeed, - consumerContractsAmount int, -) (*VRFV2Contracts, error) { - bhs, err := contractDeployer.DeployBlockhashStore() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployBlockHashStore, err) - } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - coordinator, err := contractDeployer.DeployVRFCoordinatorV2(linkTokenContract.Address(), bhs.Address(), linkEthFeedContract.Address()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrDeployCoordinator, err) - } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - consumers, err := DeployVRFV2Consumers(contractDeployer, coordinator, consumerContractsAmount) - if err != nil { - return nil, err - } - err = chainClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - return &VRFV2Contracts{coordinator, bhs, consumers}, nil -} - -func DeployVRFV2Consumers(contractDeployer contracts.ContractDeployer, coordinator contracts.VRFCoordinatorV2, consumerContractsAmount int) ([]contracts.VRFv2LoadTestConsumer, error) { - var consumers []contracts.VRFv2LoadTestConsumer - for i := 1; i <= consumerContractsAmount; i++ { - loadTestConsumer, err := contractDeployer.DeployVRFv2LoadTestConsumer(coordinator.Address()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrAdvancedConsumer, err) - } - consumers = append(consumers, loadTestConsumer) - } - return consumers, nil -} - -func CreateVRFV2Job( - chainlinkNode *client.ChainlinkClient, - coordinatorAddress string, - nativeTokenKeyAddresses []string, - pubKeyCompressed string, - chainID string, - minIncomingConfirmations uint16, -) (*client.Job, error) { - jobUUID := uuid.New() - os := &client.VRFV2TxPipelineSpec{ - Address: coordinatorAddress, - } - ost, err := os.String() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrParseJob, err) - } - - job, err := chainlinkNode.MustCreateJob(&client.VRFV2JobSpec{ - Name: fmt.Sprintf("vrf-v2-%s", jobUUID), - CoordinatorAddress: coordinatorAddress, - FromAddresses: nativeTokenKeyAddresses, - EVMChainID: chainID, - MinIncomingConfirmations: int(minIncomingConfirmations), - PublicKey: pubKeyCompressed, - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - BatchFulfillmentEnabled: false, - }) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Job, err) - } - - return job, nil -} - -func VRFV2RegisterProvingKey( - vrfKey *client.VRFKey, - oracleAddress string, - coordinator contracts.VRFCoordinatorV2, -) (VRFV2EncodedProvingKey, error) { - provingKey, err := actions.EncodeOnChainVRFProvingKey(*vrfKey) - if err != nil { - return VRFV2EncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrEncodingProvingKey, err) - } - err = coordinator.RegisterProvingKey( - oracleAddress, - provingKey, - ) - if err != nil { - return VRFV2EncodedProvingKey{}, fmt.Errorf("%s, err %w", ErrRegisterProvingKey, err) - } - return provingKey, nil -} - -func FundVRFCoordinatorV2Subscription( - linkToken contracts.LinkToken, - coordinator contracts.VRFCoordinatorV2, - chainClient blockchain.EVMClient, - subscriptionID uint64, - linkFundingAmountJuels *big.Int, -) error { - encodedSubId, err := chainlinkutils.ABIEncode(`[{"type":"uint64"}]`, subscriptionID) - if err != nil { - return fmt.Errorf("%s, err %w", ErrABIEncodingFunding, err) - } - _, err = linkToken.TransferAndCall(coordinator.Address(), linkFundingAmountJuels, encodedSubId) - if err != nil { - return fmt.Errorf("%s, err %w", ErrSendingLinkToken, err) - } - return chainClient.WaitForEvents() -} - -// SetupVRFV2Environment will create specified number of subscriptions and add the same conumer/s to each of them -func SetupVRFV2Environment( - env *test_env.CLClusterTestEnv, - vrfv2Config vrfv2_config.VRFV2Config, - linkToken contracts.LinkToken, - mockNativeLINKFeed contracts.MockETHLINKFeed, - registerProvingKeyAgainstAddress string, - numberOfTxKeysToCreate int, - numberOfConsumers int, - numberOfSubToCreate int, - l zerolog.Logger, -) (*VRFV2Contracts, []uint64, *VRFV2Data, error) { - l.Info().Msg("Starting VRFV2 environment setup") - l.Info().Msg("Deploying VRFV2 contracts") - vrfv2Contracts, err := DeployVRFV2Contracts( - env.ContractDeployer, - env.EVMClient, - linkToken, - mockNativeLINKFeed, - numberOfConsumers, - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrDeployVRFV2Contracts, err) - } - vrfCoordinatorV2FeeConfig := vrf_coordinator_v2.VRFCoordinatorV2FeeConfig{ - FulfillmentFlatFeeLinkPPMTier1: vrfv2Config.FulfillmentFlatFeeLinkPPMTier1, - FulfillmentFlatFeeLinkPPMTier2: vrfv2Config.FulfillmentFlatFeeLinkPPMTier2, - FulfillmentFlatFeeLinkPPMTier3: vrfv2Config.FulfillmentFlatFeeLinkPPMTier3, - FulfillmentFlatFeeLinkPPMTier4: vrfv2Config.FulfillmentFlatFeeLinkPPMTier4, - FulfillmentFlatFeeLinkPPMTier5: vrfv2Config.FulfillmentFlatFeeLinkPPMTier5, - ReqsForTier2: big.NewInt(vrfv2Config.ReqsForTier2), - ReqsForTier3: big.NewInt(vrfv2Config.ReqsForTier3), - ReqsForTier4: big.NewInt(vrfv2Config.ReqsForTier4), - ReqsForTier5: big.NewInt(vrfv2Config.ReqsForTier5)} - - l.Info().Str("Coordinator", vrfv2Contracts.Coordinator.Address()).Msg("Setting Coordinator Config") - err = vrfv2Contracts.Coordinator.SetConfig( - vrfv2Config.MinimumConfirmations, - vrfv2Config.CallbackGasLimit, - vrfv2Config.StalenessSeconds, - vrfv2Config.GasAfterPaymentCalculation, - big.NewInt(vrfv2Config.LinkNativeFeedResponse), - vrfCoordinatorV2FeeConfig, - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrSetVRFCoordinatorConfig, err) - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - l.Info(). - Str("Coordinator", vrfv2Contracts.Coordinator.Address()). - Int("Number of Subs to create", numberOfSubToCreate). - Msg("Creating and funding subscriptions, adding consumers") - subIDs, err := CreateFundSubsAndAddConsumers( - env, - vrfv2Config, - linkToken, - vrfv2Contracts.Coordinator, vrfv2Contracts.LoadTestConsumers, numberOfSubToCreate) - if err != nil { - return nil, nil, nil, err - } - l.Info().Str("Node URL", env.ClCluster.NodeAPIs()[0].URL()).Msg("Creating VRF Key on the Node") - vrfKey, err := env.ClCluster.NodeAPIs()[0].MustCreateVRFKey() - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingVRFv2Key, err) - } - pubKeyCompressed := vrfKey.Data.ID - - l.Info().Str("Coordinator", vrfv2Contracts.Coordinator.Address()).Msg("Registering Proving Key") - provingKey, err := VRFV2RegisterProvingKey(vrfKey, registerProvingKeyAgainstAddress, vrfv2Contracts.Coordinator) - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRegisteringProvingKey, err) - } - keyHash, err := vrfv2Contracts.Coordinator.HashOfKey(context.Background(), provingKey) - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreatingProvingKeyHash, err) - } - - chainID := env.EVMClient.GetChainID() - newNativeTokenKeyAddresses, err := CreateAndFundSendingKeys(env, vrfv2Config, numberOfTxKeysToCreate, chainID) - if err != nil { - return nil, nil, nil, err - } - nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrNodePrimaryKey, err) - } - allNativeTokenKeyAddresses := append(newNativeTokenKeyAddresses, nativeTokenPrimaryKeyAddress) - - l.Info().Msg("Creating VRFV2 Job") - vrfV2job, err := CreateVRFV2Job( - env.ClCluster.NodeAPIs()[0], - vrfv2Contracts.Coordinator.Address(), - allNativeTokenKeyAddresses, - pubKeyCompressed, - chainID.String(), - vrfv2Config.MinimumConfirmations, - ) - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrCreateVRFV2Jobs, err) - } - - // this part is here because VRFv2 can work with only a specific key - // [[EVM.KeySpecific]] - // Key = '...' - nodeConfig := node.NewConfig(env.ClCluster.Nodes[0].NodeConfig, - node.WithVRFv2EVMEstimator(allNativeTokenKeyAddresses, vrfv2Config.CLNodeMaxGasPriceGWei), - ) - l.Info().Msg("Restarting Node with new sending key PriceMax configuration") - err = env.ClCluster.Nodes[0].Restart(nodeConfig) - if err != nil { - return nil, nil, nil, fmt.Errorf("%s, err %w", ErrRestartCLNode, err) - } - - vrfv2KeyData := VRFV2KeyData{ - VRFKey: vrfKey, - EncodedProvingKey: provingKey, - KeyHash: keyHash, - } - - data := VRFV2Data{ - vrfv2KeyData, - vrfV2job, - nativeTokenPrimaryKeyAddress, - chainID, - } - - l.Info().Msg("VRFV2 environment setup is finished") - return vrfv2Contracts, subIDs, &data, nil -} - -func CreateAndFundSendingKeys(env *test_env.CLClusterTestEnv, vrfv2Config vrfv2_config.VRFV2Config, numberOfNativeTokenAddressesToCreate int, chainID *big.Int) ([]string, error) { - var newNativeTokenKeyAddresses []string - for i := 0; i < numberOfNativeTokenAddressesToCreate; i++ { - newTxKey, response, err := env.ClCluster.NodeAPIs()[0].CreateTxKey("evm", chainID.String()) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrNodeNewTxKey, err) - } - if response.StatusCode != 200 { - return nil, fmt.Errorf("error creating transaction key - response code, err %d", response.StatusCode) - } - newNativeTokenKeyAddresses = append(newNativeTokenKeyAddresses, newTxKey.Data.ID) - err = actions.FundAddress(env.EVMClient, newTxKey.Data.ID, big.NewFloat(vrfv2Config.ChainlinkNodeFunding)) - if err != nil { - return nil, err - } - } - return newNativeTokenKeyAddresses, nil -} - -func CreateFundSubsAndAddConsumers( - env *test_env.CLClusterTestEnv, - vrfv2Config vrfv2_config.VRFV2Config, - linkToken contracts.LinkToken, - coordinator contracts.VRFCoordinatorV2, - consumers []contracts.VRFv2LoadTestConsumer, - numberOfSubToCreate int, -) ([]uint64, error) { - subIDs, err := CreateSubsAndFund(env, vrfv2Config, linkToken, coordinator, numberOfSubToCreate) - if err != nil { - return nil, err - } - subToConsumersMap := map[uint64][]contracts.VRFv2LoadTestConsumer{} - - //each subscription will have the same consumers - for _, subID := range subIDs { - subToConsumersMap[subID] = consumers - } - - err = AddConsumersToSubs( - subToConsumersMap, - coordinator, - ) - if err != nil { - return nil, err - } - - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - return subIDs, nil -} - -func CreateSubsAndFund( - env *test_env.CLClusterTestEnv, - vrfv2Config vrfv2_config.VRFV2Config, - linkToken contracts.LinkToken, - coordinator contracts.VRFCoordinatorV2, - subAmountToCreate int, -) ([]uint64, error) { - subs, err := CreateSubs(env, coordinator, subAmountToCreate) - if err != nil { - return nil, err - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - err = FundSubscriptions(env, vrfv2Config, linkToken, coordinator, subs) - if err != nil { - return nil, err - } - return subs, nil -} - -func CreateSubs( - env *test_env.CLClusterTestEnv, - coordinator contracts.VRFCoordinatorV2, - subAmountToCreate int, -) ([]uint64, error) { - var subIDArr []uint64 - - for i := 0; i < subAmountToCreate; i++ { - subID, err := CreateSubAndFindSubID(env, coordinator) - if err != nil { - return nil, err - } - subIDArr = append(subIDArr, subID) - } - return subIDArr, nil -} - -func AddConsumersToSubs( - subToConsumerMap map[uint64][]contracts.VRFv2LoadTestConsumer, - coordinator contracts.VRFCoordinatorV2, -) error { - for subID, consumers := range subToConsumerMap { - for _, consumer := range consumers { - err := coordinator.AddConsumer(subID, consumer.Address()) - if err != nil { - return fmt.Errorf("%s, err %w", ErrAddConsumerToSub, err) - } - } - } - return nil -} - -func CreateSubAndFindSubID(env *test_env.CLClusterTestEnv, coordinator contracts.VRFCoordinatorV2) (uint64, error) { - tx, err := coordinator.CreateSubscription() - if err != nil { - return 0, fmt.Errorf("%s, err %w", ErrCreateVRFSubscription, err) - } - err = env.EVMClient.WaitForEvents() - if err != nil { - return 0, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - - receipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) - if err != nil { - return 0, fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - - //SubscriptionsCreated Log should be emitted with the subscription ID - subID := receipt.Logs[0].Topics[1].Big().Uint64() - - return subID, nil -} - -func FundSubscriptions( - env *test_env.CLClusterTestEnv, - vrfv2Config vrfv2_config.VRFV2Config, - linkAddress contracts.LinkToken, - coordinator contracts.VRFCoordinatorV2, - subIDs []uint64, -) error { - for _, subID := range subIDs { - //Link Billing - amountJuels := conversions.EtherToWei(big.NewFloat(vrfv2Config.SubscriptionFundingAmountLink)) - err := FundVRFCoordinatorV2Subscription(linkAddress, coordinator, env.EVMClient, subID, amountJuels) - if err != nil { - return fmt.Errorf("%s, err %w", ErrFundSubWithLinkToken, err) - } - } - err := env.EVMClient.WaitForEvents() - if err != nil { - return fmt.Errorf("%s, err %w", ErrWaitTXsComplete, err) - } - return nil -} - -func RequestRandomnessAndWaitForFulfillment( - consumer contracts.VRFv2LoadTestConsumer, - coordinator contracts.VRFCoordinatorV2, - vrfv2Data *VRFV2Data, - subID uint64, - randomnessRequestCountPerRequest uint16, - vrfv2Config vrfv2_config.VRFV2Config, - randomWordsFulfilledEventTimeout time.Duration, - l zerolog.Logger, -) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { - logRandRequest(consumer.Address(), coordinator.Address(), subID, vrfv2Config, l) - _, err := consumer.RequestRandomness( - vrfv2Data.KeyHash, - subID, - vrfv2Config.MinimumConfirmations, - vrfv2Config.CallbackGasLimit, - vrfv2Config.NumberOfWords, - randomnessRequestCountPerRequest, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrRequestRandomness, err) - } - - fulfillmentEvents, err := WaitForRequestAndFulfillmentEvents( - consumer.Address(), - coordinator, - vrfv2Data, - subID, - randomWordsFulfilledEventTimeout, - l, - ) - return fulfillmentEvents, err -} - -func WaitForRequestAndFulfillmentEvents( - consumerAddress string, - coordinator contracts.VRFCoordinatorV2, - vrfv2Data *VRFV2Data, - subID uint64, - randomWordsFulfilledEventTimeout time.Duration, - l zerolog.Logger, -) (*vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, error) { - randomWordsRequestedEvent, err := coordinator.WaitForRandomWordsRequestedEvent( - [][32]byte{vrfv2Data.KeyHash}, - []uint64{subID}, - []common.Address{common.HexToAddress(consumerAddress)}, - time.Minute*1, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsRequestedEvent, err) - } - - LogRandomnessRequestedEvent(l, coordinator, randomWordsRequestedEvent) - randomWordsFulfilledEvent, err := coordinator.WaitForRandomWordsFulfilledEvent( - []*big.Int{randomWordsRequestedEvent.RequestId}, - randomWordsFulfilledEventTimeout, - ) - if err != nil { - return nil, fmt.Errorf("%s, err %w", ErrWaitRandomWordsFulfilledEvent, err) - } - - LogRandomWordsFulfilledEvent(l, coordinator, randomWordsFulfilledEvent) - return randomWordsFulfilledEvent, err -} - -func WaitForRequestCountEqualToFulfilmentCount(consumer contracts.VRFv2LoadTestConsumer, timeout time.Duration, wg *sync.WaitGroup) (*big.Int, *big.Int, error) { - metricsChannel := make(chan *contracts.VRFLoadTestMetrics) - metricsErrorChannel := make(chan error) - - testContext, testCancel := context.WithTimeout(context.Background(), timeout) - defer testCancel() - - ticker := time.NewTicker(time.Second * 1) - var metrics *contracts.VRFLoadTestMetrics - for { - select { - case <-testContext.Done(): - ticker.Stop() - wg.Done() - return metrics.RequestCount, metrics.FulfilmentCount, - fmt.Errorf("timeout waiting for rand request and fulfilments to be equal AFTER performance test was executed. Request Count: %d, Fulfilment Count: %d", - metrics.RequestCount.Uint64(), metrics.FulfilmentCount.Uint64()) - case <-ticker.C: - go retrieveLoadTestMetrics(consumer, metricsChannel, metricsErrorChannel) - case metrics = <-metricsChannel: - if metrics.RequestCount.Cmp(metrics.FulfilmentCount) == 0 { - ticker.Stop() - wg.Done() - return metrics.RequestCount, metrics.FulfilmentCount, nil - } - case err := <-metricsErrorChannel: - ticker.Stop() - wg.Done() - return nil, nil, err - } - } -} - -func retrieveLoadTestMetrics( - consumer contracts.VRFv2LoadTestConsumer, - metricsChannel chan *contracts.VRFLoadTestMetrics, - metricsErrorChannel chan error, -) { - metrics, err := consumer.GetLoadTestMetrics(context.Background()) - if err != nil { - metricsErrorChannel <- err - } - metricsChannel <- metrics -} - -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.Debug(). - Str("Coordinator", coordinator.Address()). - Str("Request ID", randomWordsRequestedEvent.RequestId.String()). - Uint64("Subscription ID", randomWordsRequestedEvent.SubId). - Str("Sender Address", randomWordsRequestedEvent.Sender.String()). - Interface("Keyhash", randomWordsRequestedEvent.KeyHash). - Uint32("Callback Gas Limit", randomWordsRequestedEvent.CallbackGasLimit). - Uint32("Number of Words", randomWordsRequestedEvent.NumWords). - Uint16("Minimum Request Confirmations", randomWordsRequestedEvent.MinimumRequestConfirmations). - Msg("RandomnessRequested Event") -} - -func LogRandomWordsFulfilledEvent( - l zerolog.Logger, - coordinator contracts.VRFCoordinatorV2, - randomWordsFulfilledEvent *vrf_coordinator_v2.VRFCoordinatorV2RandomWordsFulfilled, -) { - l.Debug(). - 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). - Msg("RandomWordsFulfilled Event (TX metadata)") -} - -func logRandRequest( - consumer string, - coordinator string, - subID uint64, - vrfv2Config vrfv2_config.VRFV2Config, - l zerolog.Logger, -) { - l.Debug(). - Str("Consumer", consumer). - Str("Coordinator", coordinator). - Uint64("SubID", subID). - Uint16("MinimumConfirmations", vrfv2Config.MinimumConfirmations). - Uint32("CallbackGasLimit", vrfv2Config.CallbackGasLimit). - Uint16("RandomnessRequestCountPerRequest", vrfv2Config.RandomnessRequestCountPerRequest). - Uint16("RandomnessRequestCountPerRequestDeviation", vrfv2Config.RandomnessRequestCountPerRequestDeviation). - Msg("Requesting randomness") -} diff --git a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go b/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go deleted file mode 100644 index 8cd6e0a8ce8..00000000000 --- a/integration-tests/actions/vrfv2plus/vrfv2plus_config/config.go +++ /dev/null @@ -1,48 +0,0 @@ -package vrfv2plus_config - -import "time" - -type VRFV2PlusConfig struct { - ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of native currency to fund each chainlink node with - CLNodeMaxGasPriceGWei int64 `envconfig:"MAX_GAS_PRICE_GWEI" default:"1000"` // Max gas price in GWei for the chainlink node - IsNativePayment bool `envconfig:"IS_NATIVE_PAYMENT" default:"false"` // Whether to use native payment or LINK token - LinkNativeFeedResponse int64 `envconfig:"LINK_NATIVE_FEED_RESPONSE" default:"1000000000000000000"` // Response of the LINK/ETH feed - MinimumConfirmations uint16 `envconfig:"MINIMUM_CONFIRMATIONS" default:"3"` // Minimum number of confirmations for the VRF Coordinator - SubscriptionFundingAmountLink float64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_LINK" default:"5"` // Amount of LINK to fund the subscription with - SubscriptionFundingAmountNative float64 `envconfig:"SUBSCRIPTION_FUNDING_AMOUNT_NATIVE" default:"1"` // Amount of native currency to fund the subscription with - NumberOfWords uint32 `envconfig:"NUMBER_OF_WORDS" default:"3"` // Number of words to request - CallbackGasLimit uint32 `envconfig:"CALLBACK_GAS_LIMIT" default:"1000000"` // Gas limit for the callback - MaxGasLimitCoordinatorConfig uint32 `envconfig:"MAX_GAS_LIMIT_COORDINATOR_CONFIG" default:"2500000"` // Max gas limit for the VRF Coordinator config - FallbackWeiPerUnitLink int64 `envconfig:"FALLBACK_WEI_PER_UNIT_LINK" default:"60000000000000000"` // Fallback wei per unit LINK for the VRF Coordinator config - StalenessSeconds uint32 `envconfig:"STALENESS_SECONDS" default:"86400"` // Staleness in seconds for the VRF Coordinator config - GasAfterPaymentCalculation uint32 `envconfig:"GAS_AFTER_PAYMENT_CALCULATION" default:"33825"` // Gas after payment calculation for the VRF Coordinator config - FulfillmentFlatFeeLinkPPM uint32 `envconfig:"FULFILLMENT_FLAT_FEE_LINK_PPM" default:"500"` // Flat fee in ppm for LINK for the VRF Coordinator config - FulfillmentFlatFeeNativePPM uint32 `envconfig:"FULFILLMENT_FLAT_FEE_NATIVE_PPM" default:"500"` // Flat fee in ppm for native currency for the VRF Coordinator config - - NumberOfSubToCreate int `envconfig:"NUMBER_OF_SUB_TO_CREATE" default:"1"` // Number of subscriptions to create - - RandomnessRequestCountPerRequest uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST" default:"1"` // How many randomness requests to send per request - RandomnessRequestCountPerRequestDeviation uint16 `envconfig:"RANDOMNESS_REQUEST_COUNT_PER_REQUEST_DEVIATION" default:"0"` // How many randomness requests to send per request - - RandomWordsFulfilledEventTimeout time.Duration `envconfig:"RANDOM_WORDS_FULFILLED_EVENT_TIMEOUT" default:"2m"` // How long to wait for the RandomWordsFulfilled event to be emitted - - //Wrapper Config - WrapperGasOverhead uint32 `envconfig:"WRAPPER_GAS_OVERHEAD" default:"50000"` - CoordinatorGasOverhead uint32 `envconfig:"COORDINATOR_GAS_OVERHEAD" default:"52000"` - WrapperPremiumPercentage uint8 `envconfig:"WRAPPER_PREMIUM_PERCENTAGE" default:"25"` - WrapperMaxNumberOfWords uint8 `envconfig:"WRAPPER_MAX_NUMBER_OF_WORDS" default:"10"` - WrapperConsumerFundingAmountNativeToken float64 `envconfig:"WRAPPER_CONSUMER_FUNDING_AMOUNT_NATIVE_TOKEN" default:"1"` - WrapperConsumerFundingAmountLink int64 `envconfig:"WRAPPER_CONSUMER_FUNDING_AMOUNT_LINK" default:"10"` - - //LOAD/SOAK Test Config - TestDuration time.Duration `envconfig:"TEST_DURATION" default:"3m"` // How long to run the test for - RPS int64 `envconfig:"RPS" default:"1"` // How many requests per second to send - RateLimitUnitDuration time.Duration `envconfig:"RATE_LIMIT_UNIT_DURATION" default:"1m"` - //Using existing environment and contracts - UseExistingEnv bool `envconfig:"USE_EXISTING_ENV" default:"false"` // Whether to use an existing environment or create a new one - CoordinatorAddress string `envconfig:"COORDINATOR_ADDRESS" default:""` // Coordinator address - ConsumerAddress string `envconfig:"CONSUMER_ADDRESS" default:""` // Consumer address - LinkAddress string `envconfig:"LINK_ADDRESS" default:""` // Link address - SubID string `envconfig:"SUB_ID" default:""` // Subscription ID - KeyHash string `envconfig:"KEY_HASH" default:""` -} diff --git a/integration-tests/benchmark/keeper_test.go b/integration-tests/benchmark/keeper_test.go index d5a82a51e07..8997289a7eb 100644 --- a/integration-tests/benchmark/keeper_test.go +++ b/integration-tests/benchmark/keeper_test.go @@ -3,8 +3,6 @@ package benchmark import ( "fmt" "math/big" - "os" - "strconv" "strings" "testing" "time" @@ -12,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" env_client "github.com/smartcontractkit/chainlink-testing-framework/k8s/client" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" @@ -25,6 +24,9 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" + "github.com/smartcontractkit/chainlink/integration-tests/types" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -110,27 +112,6 @@ LimitDefault = 5_000_000` } ) -var ( - NumberOfNodes, _ = strconv.Atoi(getEnv("NUMBEROFNODES", "6")) - RegistryToTest = getEnv("REGISTRY", "2_1") - NumberOfUpkeeps, _ = strconv.Atoi(getEnv("NUMBEROFUPKEEPS", "500")) - CheckGasToBurn, _ = strconv.ParseInt(getEnv("CHECKGASTOBURN", "100000"), 0, 64) - PerformGasToBurn, _ = strconv.ParseInt(getEnv("PERFORMGASTOBURN", "50000"), 0, 64) - BlockRange, _ = strconv.ParseInt(getEnv("BLOCKRANGE", "3600"), 0, 64) - BlockInterval, _ = strconv.ParseInt(getEnv("BLOCKINTERVAL", "20"), 0, 64) - ChainlinkNodeFunding, _ = strconv.ParseFloat(getEnv("CHAINLINKNODEFUNDING", "0.5"), 64) - MaxPerformGas, _ = strconv.ParseInt(getEnv("MAXPERFORMGAS", "5000000"), 0, 32) - UpkeepGasLimit, _ = strconv.ParseInt(getEnv("UPKEEPGASLIMIT", fmt.Sprint(PerformGasToBurn+100000)), 0, 64) - NumberOfRegistries, _ = strconv.Atoi(getEnv("NUMBEROFREGISTRIES", "1")) - ForceSingleTxnKey, _ = strconv.ParseBool(getEnv("FORCESINGLETXNKEY", "false")) - DeleteJobsOnEnd, _ = strconv.ParseBool(getEnv("DELETEJOBSONEND", "true")) - RegistryAddress = getEnv("REGISTRYADDRESS", "") - RegistrarAddress = getEnv("REGISTRARADDRESS", "") - LinkTokenAddress = getEnv("LINKTOKENADDRESS", "") - EthFeedAddress = getEnv("ETHFEEDADDRESS", "") - GasFeedAddress = getEnv("GASFEEDADDRESS", "") -) - type NetworkConfig struct { upkeepSLA int64 blockTime time.Duration @@ -140,20 +121,26 @@ type NetworkConfig struct { func TestAutomationBenchmark(t *testing.T) { l := logging.GetTestLogger(t) - testEnvironment, benchmarkNetwork := SetupAutomationBenchmarkEnv(t) + testType, err := tc.GetConfigurationNameFromEnv() + require.NoError(t, err, "Error getting test type") + + config, err := tc.GetConfig(testType, tc.Keeper) + require.NoError(t, err, "Error getting test config") + + testEnvironment, benchmarkNetwork := SetupAutomationBenchmarkEnv(t, &config) if testEnvironment.WillUseRemoteRunner() { return } networkName := strings.ReplaceAll(benchmarkNetwork.Name, " ", "") - testName := fmt.Sprintf("%s%s", networkName, RegistryToTest) - l.Info().Str("Test Name", testName).Str("Test Inputs", os.Getenv("TEST_INPUTS")).Msg("Running Benchmark Test") - benchmarkTestNetwork := networkConfig[networkName] + testName := fmt.Sprintf("%s%s", networkName, *config.Keeper.Common.RegistryToTest) + l.Info().Str("Test Name", testName).Msg("Running Benchmark Test") + benchmarkTestNetwork := getNetworkConfig(networkName, &config) l.Info().Str("Namespace", testEnvironment.Cfg.Namespace).Msg("Connected to Keepers Benchmark Environment") chainClient, err := blockchain.NewEVMClient(benchmarkNetwork, testEnvironment, l) require.NoError(t, err, "Error connecting to blockchain") - registryVersions := addRegistry(RegistryToTest) + registryVersions := addRegistry(&config) keeperBenchmarkTest := testsetups.NewKeeperBenchmarkTest(t, testsetups.KeeperBenchmarkTestInputs{ BlockchainClient: chainClient, @@ -165,7 +152,7 @@ func TestAutomationBenchmark(t *testing.T) { CheckGasLimit: uint32(45_000_000), //45M StalenessSeconds: big.NewInt(90_000), GasCeilingMultiplier: uint16(2), - MaxPerformGas: uint32(MaxPerformGas), + MaxPerformGas: uint32(*config.Keeper.Common.MaxPerformGas), MinUpkeepSpend: big.NewInt(0), FallbackGasPrice: big.NewInt(2e11), FallbackLinkPrice: big.NewInt(2e18), @@ -173,27 +160,27 @@ func TestAutomationBenchmark(t *testing.T) { MaxPerformDataSize: uint32(5_000), }, Upkeeps: &testsetups.UpkeepConfig{ - NumberOfUpkeeps: NumberOfUpkeeps, - CheckGasToBurn: CheckGasToBurn, - PerformGasToBurn: PerformGasToBurn, - BlockRange: BlockRange, - BlockInterval: BlockInterval, - UpkeepGasLimit: UpkeepGasLimit, + NumberOfUpkeeps: *config.Keeper.Common.NumberOfUpkeeps, + CheckGasToBurn: *config.Keeper.Common.CheckGasToBurn, + PerformGasToBurn: *config.Keeper.Common.PerformGasToBurn, + BlockRange: *config.Keeper.Common.BlockRange, + BlockInterval: *config.Keeper.Common.BlockInterval, + UpkeepGasLimit: *config.Keeper.Common.UpkeepGasLimit, FirstEligibleBuffer: 1, }, Contracts: &testsetups.PreDeployedContracts{ - RegistrarAddress: RegistrarAddress, - RegistryAddress: RegistryAddress, - LinkTokenAddress: LinkTokenAddress, - EthFeedAddress: EthFeedAddress, - GasFeedAddress: GasFeedAddress, + RegistrarAddress: *config.Keeper.Common.RegistrarAddress, + RegistryAddress: *config.Keeper.Common.RegistryAddress, + LinkTokenAddress: *config.Keeper.Common.LinkTokenAddress, + EthFeedAddress: *config.Keeper.Common.EthFeedAddress, + GasFeedAddress: *config.Keeper.Common.GasFeedAddress, }, ChainlinkNodeFunding: benchmarkTestNetwork.funding, UpkeepSLA: benchmarkTestNetwork.upkeepSLA, BlockTime: benchmarkTestNetwork.blockTime, DeltaStage: benchmarkTestNetwork.deltaStage, - ForceSingleTxnKey: ForceSingleTxnKey, - DeleteJobsOnEnd: DeleteJobsOnEnd, + ForceSingleTxnKey: *config.Keeper.Common.ForceSingleTxKey, + DeleteJobsOnEnd: *config.Keeper.Common.DeleteJobsOnEnd, }, ) t.Cleanup(func() { @@ -201,12 +188,12 @@ func TestAutomationBenchmark(t *testing.T) { l.Error().Err(err).Msg("Error when tearing down remote suite") } }) - keeperBenchmarkTest.Setup(testEnvironment) + keeperBenchmarkTest.Setup(testEnvironment, &config) keeperBenchmarkTest.Run() } -func addRegistry(registryToTest string) []eth_contracts.KeeperRegistryVersion { - switch registryToTest { +func addRegistry(config *tc.TestConfig) []eth_contracts.KeeperRegistryVersion { + switch *config.Keeper.Common.RegistryToTest { case "1_1": return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_1_1} case "1_2": @@ -223,9 +210,9 @@ func addRegistry(registryToTest string) []eth_contracts.KeeperRegistryVersion { return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_1, eth_contracts.RegistryVersion_2_0, eth_contracts.RegistryVersion_1_3} case "2_0-Multiple": - return repeatRegistries(eth_contracts.RegistryVersion_2_0, NumberOfRegistries) + return repeatRegistries(eth_contracts.RegistryVersion_2_0, *config.Keeper.Common.NumberOfRegistries) case "2_1-Multiple": - return repeatRegistries(eth_contracts.RegistryVersion_2_1, NumberOfRegistries) + return repeatRegistries(eth_contracts.RegistryVersion_2_1, *config.Keeper.Common.NumberOfRegistries) default: return []eth_contracts.KeeperRegistryVersion{eth_contracts.RegistryVersion_2_0} } @@ -239,6 +226,22 @@ func repeatRegistries(registryVersion eth_contracts.KeeperRegistryVersion, numbe return repeatedRegistries } +func getNetworkConfig(networkName string, config *tc.TestConfig) NetworkConfig { + var nc NetworkConfig + var ok bool + if nc, ok = networkConfig[networkName]; !ok { + return NetworkConfig{} + } + + if networkName == "SimulatedGeth" || networkName == "geth" { + return nc + } + + nc.funding = big.NewFloat(*config.Common.ChainlinkNodeFunding) + + return nc +} + var networkConfig = map[string]NetworkConfig{ "SimulatedGeth": { upkeepSLA: int64(120), //2 minutes @@ -256,93 +259,71 @@ var networkConfig = map[string]NetworkConfig{ upkeepSLA: int64(4), blockTime: 12 * time.Second, deltaStage: time.Duration(0), - funding: big.NewFloat(ChainlinkNodeFunding), }, "ArbitrumGoerli": { upkeepSLA: int64(20), blockTime: time.Second, deltaStage: time.Duration(0), - funding: big.NewFloat(ChainlinkNodeFunding), }, "OptimismGoerli": { upkeepSLA: int64(20), blockTime: time.Second, deltaStage: time.Duration(0), - funding: big.NewFloat(ChainlinkNodeFunding), }, "SepoliaTestnet": { upkeepSLA: int64(4), blockTime: 12 * time.Second, deltaStage: time.Duration(0), - funding: big.NewFloat(ChainlinkNodeFunding), }, "PolygonMumbai": { upkeepSLA: int64(4), blockTime: 12 * time.Second, deltaStage: time.Duration(0), - funding: big.NewFloat(ChainlinkNodeFunding), }, "BaseGoerli": { upkeepSLA: int64(60), blockTime: 2 * time.Second, deltaStage: 20 * time.Second, - funding: big.NewFloat(ChainlinkNodeFunding), }, "ArbitrumSepolia": { upkeepSLA: int64(120), blockTime: time.Second, deltaStage: 20 * time.Second, - funding: big.NewFloat(ChainlinkNodeFunding), + }, + "LineaGoerli": { + upkeepSLA: int64(120), + blockTime: time.Second, + deltaStage: 20 * time.Second, }, } -func getEnv(key, fallback string) string { - if inputs, ok := os.LookupEnv("TEST_INPUTS"); ok { - values := strings.Split(inputs, ",") - for _, value := range values { - if strings.Contains(value, key) { - return strings.Split(value, "=")[1] - } - } - } - return fallback -} - -func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockchain.EVMNetwork) { +func SetupAutomationBenchmarkEnv(t *testing.T, keeperTestConfig types.KeeperBenchmarkTestConfig) (*environment.Environment, blockchain.EVMNetwork) { l := logging.GetTestLogger(t) - testNetwork := networks.MustGetSelectedNetworksFromEnv()[0] // Environment currently being used to run benchmark test on + testNetwork := networks.MustGetSelectedNetworkConfig(keeperTestConfig.GetNetworkConfig())[0] // Environment currently being used to run benchmark test on blockTime := "1" networkDetailTOML := `MinIncomingConfirmations = 1` - if strings.Contains(RegistryToTest, "2_") { - NumberOfNodes++ + numberOfNodes := *keeperTestConfig.GetKeeperConfig().Common.NumberOfNodes + + if strings.Contains(*keeperTestConfig.GetKeeperConfig().Common.RegistryToTest, "2_") { + numberOfNodes++ } - testType := strings.ToLower(getEnv("TEST_TYPE", "benchmark")) testEnvironment := environment.New(&environment.Config{ TTL: time.Hour * 720, // 30 days, NamespacePrefix: fmt.Sprintf( "automation-%s-%s-%s", - testType, + strings.ToLower(keeperTestConfig.GetConfigurationName()), strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-"), - strings.ReplaceAll(strings.ToLower(RegistryToTest), "_", "-"), + strings.ReplaceAll(strings.ToLower(*keeperTestConfig.GetKeeperConfig().Common.RegistryToTest), "_", "-"), ), Test: t, PreventPodEviction: true, }) - // propagate TEST_INPUTS to remote runner - if testEnvironment.WillUseRemoteRunner() { - key := "TEST_INPUTS" - err := os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) - require.NoError(t, err, "failed to set the environment variable TEST_INPUTS for remote runner") - key = "GRAFANA_DASHBOARD_URL" - err = os.Setenv(fmt.Sprintf("TEST_%s", key), getEnv(key, "")) - require.NoError(t, err, "failed to set the environment variable GRAFANA_DASHBOARD_URL for remote runner") - } dbResources := performanceDbResources chainlinkResources := performanceChainlinkResources - if testType == "soak" { + if strings.ToLower(keeperTestConfig.GetConfigurationName()) == "soak" { chainlinkResources = soakChainlinkResources dbResources = soakDbResources } @@ -356,7 +337,7 @@ func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockc Values: map[string]interface{}{ "geth": map[string]interface{}{ "tx": map[string]interface{}{ - "replicas": NumberOfNodes, + "replicas": numberOfNodes, }, "miner": map[string]interface{}{ "replicas": 2, @@ -406,7 +387,7 @@ func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockc // separate RPC urls per CL node internalWsURLs := make([]string, 0) internalHttpURLs := make([]string, 0) - for i := 0; i < NumberOfNodes; i++ { + for i := 0; i < numberOfNodes; i++ { // for simulated-nod-dev each CL node gets its own RPC node if testNetwork.Name == networks.SimulatedEVMNonDev.Name { podName := fmt.Sprintf("%s-ethereum-geth:%d", testNetwork.Name, i) @@ -428,14 +409,22 @@ func SetupAutomationBenchmarkEnv(t *testing.T) (*environment.Environment, blockc } l.Debug().Strs("internalWsURLs", internalWsURLs).Strs("internalHttpURLs", internalHttpURLs).Msg("internalURLs") - for i := 0; i < NumberOfNodes; i++ { + for i := 0; i < numberOfNodes; i++ { testNetwork.HTTPURLs = []string{internalHttpURLs[i]} testNetwork.URLs = []string{internalWsURLs[i]} - testEnvironment.AddHelm(chainlink.New(i, map[string]any{ - "toml": networks.AddNetworkDetailedConfig(keeperBenchmarkBaseTOML, networkDetailTOML, testNetwork), + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(keeperTestConfig.GetChainlinkImageConfig(), target) + ctf_config.MightConfigOverridePyroscopeKey(keeperTestConfig.GetPyroscopeConfig(), target) + } + + cd := chainlink.NewWithOverride(i, map[string]any{ + "toml": networks.AddNetworkDetailedConfig(keeperBenchmarkBaseTOML, keeperTestConfig.GetPyroscopeConfig(), networkDetailTOML, testNetwork), "chainlink": chainlinkResources, "db": dbResources, - })) + }, keeperTestConfig.GetChainlinkImageConfig(), overrideFn) + + testEnvironment.AddHelm(cd) } err = testEnvironment.Run() require.NoError(t, err, "Error launching test environment") diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 06352a93d72..711a3557307 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -11,6 +11,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" @@ -25,6 +26,8 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" eth_contracts "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -41,7 +44,7 @@ ListenAddresses = ["0.0.0.0:6690"]` defaultAutomationSettings = map[string]interface{}{ "replicas": 6, - "toml": networks.AddNetworksConfig(baseTOML, networks.MustGetSelectedNetworksFromEnv()[0]), + "toml": "", "db": map[string]interface{}{ "stateful": true, "capacity": "1Gi", @@ -58,11 +61,7 @@ ListenAddresses = ["0.0.0.0:6690"]` }, } - defaultEthereumSettings = ðereum.Props{ - // utils.MustGetSelectedNetworksFromEnv() - NetworkName: networks.MustGetSelectedNetworksFromEnv()[0].Name, - Simulated: networks.MustGetSelectedNetworksFromEnv()[0].Simulated, - WsURLs: networks.MustGetSelectedNetworksFromEnv()[0].URLs, + defaultEthereumSettings = ethereum.Props{ Values: map[string]interface{}{ "resources": map[string]interface{}{ "requests": map[string]interface{}{ @@ -96,6 +95,20 @@ ListenAddresses = ["0.0.0.0:6690"]` } ) +func getDefaultAutomationSettings(config *tc.TestConfig) map[string]interface{} { + defaultAutomationSettings["toml"] = networks.AddNetworksConfig(baseTOML, config.Pyroscope, networks.MustGetSelectedNetworkConfig(config.Network)[0]) + return defaultAutomationSettings +} + +func getDefaultEthereumSettings(config *tc.TestConfig) *ethereum.Props { + network := networks.MustGetSelectedNetworkConfig(config.Network)[0] + defaultEthereumSettings.NetworkName = network.Name + defaultEthereumSettings.Simulated = network.Simulated + defaultEthereumSettings.WsURLs = network.URLs + + return &defaultEthereumSettings +} + type KeeperConsumerContracts int32 const ( @@ -120,6 +133,18 @@ func TestAutomationChaos(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() + config, err := tc.GetConfig("Chaos", tc.Automation) + if err != nil { + t.Fatal(err) + } + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(config.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(config.Pyroscope, target) + } + + chainlinkCfg := chainlink.NewWithOverride(0, getDefaultAutomationSettings(&config), config.ChainlinkImage, overrideFn) + testCases := map[string]struct { networkChart environment.ConnectedChart clChart environment.ConnectedChart @@ -128,8 +153,8 @@ func TestAutomationChaos(t *testing.T) { }{ // see ocr_chaos.test.go for comments PodChaosFailMinorityNodes: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), + ethereum.New(getDefaultEthereumSettings(&config)), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, @@ -137,8 +162,8 @@ func TestAutomationChaos(t *testing.T) { }, }, PodChaosFailMajorityNodes: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), + ethereum.New(getDefaultEthereumSettings(&config)), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -146,8 +171,8 @@ func TestAutomationChaos(t *testing.T) { }, }, PodChaosFailMajorityDB: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), + ethereum.New(getDefaultEthereumSettings(&config)), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -156,8 +181,8 @@ func TestAutomationChaos(t *testing.T) { }, }, NetworkChaosFailMajorityNetwork: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), + ethereum.New(getDefaultEthereumSettings(&config)), + chainlinkCfg, chaos.NewNetworkPartition, &chaos.Props{ FromLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -166,8 +191,8 @@ func TestAutomationChaos(t *testing.T) { }, }, NetworkChaosFailBlockchainNode: { - ethereum.New(defaultEthereumSettings), - chainlink.New(0, defaultAutomationSettings), + ethereum.New(getDefaultEthereumSettings(&config)), + chainlinkCfg, chaos.NewNetworkPartition, &chaos.Props{ FromLabels: &map[string]*string{"app": ptr.Ptr("geth")}, @@ -182,7 +207,7 @@ func TestAutomationChaos(t *testing.T) { testCase := testCase t.Run(fmt.Sprintf("Automation_%s", name), func(t *testing.T) { t.Parallel() - network := networks.MustGetSelectedNetworksFromEnv()[0] // Need a new copy of the network for each test + network := networks.MustGetSelectedNetworkConfig(config.Network)[0] // Need a new copy of the network for each test testEnvironment := environment. New(&environment.Config{ @@ -224,7 +249,7 @@ func TestAutomationChaos(t *testing.T) { if chainClient != nil { chainClient.GasStats().PrintStats() } - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &config, chainClient) require.NoError(t, err, "Error tearing down environment") }) diff --git a/integration-tests/chaos/ocr2vrf_chaos_test.go b/integration-tests/chaos/ocr2vrf_chaos_test.go index 200114ddafb..eda60a37f3c 100644 --- a/integration-tests/chaos/ocr2vrf_chaos_test.go +++ b/integration-tests/chaos/ocr2vrf_chaos_test.go @@ -11,6 +11,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" @@ -26,17 +27,24 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestOCR2VRFChaos(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - loadedNetwork := networks.MustGetSelectedNetworksFromEnv()[0] + testconfig, err := tc.GetConfig("Chaos", tc.OCR2VRF) + if err != nil { + t.Fatal(err) + } + + loadedNetwork := networks.MustGetSelectedNetworkConfig(testconfig.Network)[0] defaultOCR2VRFSettings := map[string]interface{}{ "replicas": 6, "toml": networks.AddNetworkDetailedConfig( config.BaseOCR2Config, + testconfig.Pyroscope, config.DefaultOCR2VRFNetworkDetailTomlConfig, loadedNetwork, ), @@ -48,6 +56,13 @@ func TestOCR2VRFChaos(t *testing.T) { WsURLs: loadedNetwork.URLs, } + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(testconfig.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(testconfig.Pyroscope, target) + } + + chainlinkCfg := chainlink.NewWithOverride(0, defaultOCR2VRFSettings, testconfig.ChainlinkImage, overrideFn) + testCases := map[string]struct { networkChart environment.ConnectedChart clChart environment.ConnectedChart @@ -65,7 +80,7 @@ func TestOCR2VRFChaos(t *testing.T) { //4. verify VRF request gets fulfilled PodChaosFailMinorityNodes: { ethereum.New(defaultOCR2VRFEthereumSettings), - chainlink.New(0, defaultOCR2VRFSettings), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, @@ -75,7 +90,7 @@ func TestOCR2VRFChaos(t *testing.T) { //todo - currently failing, need to investigate deeper //PodChaosFailMajorityNodes: { // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlink.New(0, defaultOCR2VRFSettings), + // chainlinkCfg, // chaos.NewFailPods, // &chaos.Props{ // LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -85,7 +100,7 @@ func TestOCR2VRFChaos(t *testing.T) { //todo - do we need these chaos tests? //PodChaosFailMajorityDB: { // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlink.New(0, defaultOCR2VRFSettings), + // chainlinkCfg, // chaos.NewFailPods, // &chaos.Props{ // LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -95,7 +110,7 @@ func TestOCR2VRFChaos(t *testing.T) { //}, //NetworkChaosFailMajorityNetwork: { // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlink.New(0, defaultOCR2VRFSettings), + // chainlinkCfg, // chaos.NewNetworkPartition, // &chaos.Props{ // FromLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -105,7 +120,7 @@ func TestOCR2VRFChaos(t *testing.T) { //}, //NetworkChaosFailBlockchainNode: { // ethereum.New(defaultOCR2VRFEthereumSettings), - // chainlink.New(0, defaultOCR2VRFSettings), + // chainlinkCfg, // chaos.NewNetworkPartition, // &chaos.Props{ // FromLabels: &map[string]*string{"app": ptr.Ptr("geth")}, @@ -119,7 +134,7 @@ func TestOCR2VRFChaos(t *testing.T) { testCase := tc t.Run(fmt.Sprintf("OCR2VRF_%s", testCaseName), func(t *testing.T) { t.Parallel() - testNetwork := networks.MustGetSelectedNetworksFromEnv()[0] // Need a new copy of the network for each test + testNetwork := networks.MustGetSelectedNetworkConfig(testconfig.Network)[0] // Need a new copy of the network for each test testEnvironment := environment. New(&environment.Config{ NamespacePrefix: fmt.Sprintf( @@ -150,7 +165,7 @@ func TestOCR2VRFChaos(t *testing.T) { require.NoError(t, err, "Retrieving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &testconfig, chainClient) require.NoError(t, err, "Error tearing down environment") }) diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index a59a0a028c2..97f7c67d1b9 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -3,7 +3,6 @@ package chaos import ( "fmt" "math/big" - "os" "testing" "github.com/onsi/gomega" @@ -12,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/chaos" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" @@ -25,8 +25,8 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -51,14 +51,26 @@ var ( chaosEndRound int64 = 4 ) -func TestMain(m *testing.M) { - defaultOCRSettings["toml"] = networks.AddNetworksConfig(config.BaseOCR1Config, networks.MustGetSelectedNetworksFromEnv()[0]) - os.Exit(m.Run()) +func getDefaultOcrSettings(config *tc.TestConfig) map[string]interface{} { + defaultOCRSettings["toml"] = networks.AddNetworksConfig(baseTOML, config.Pyroscope, networks.MustGetSelectedNetworkConfig(config.Network)[0]) + return defaultAutomationSettings } func TestOCRChaos(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Chaos", tc.OCR) + if err != nil { + t.Fatal(err) + } + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(config.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(config.Pyroscope, target) + } + + chainlinkCfg := chainlink.NewWithOverride(0, getDefaultOcrSettings(&config), config.ChainlinkImage, overrideFn) + testCases := map[string]struct { networkChart environment.ConnectedChart clChart environment.ConnectedChart @@ -77,7 +89,7 @@ func TestOCRChaos(t *testing.T) { // https://github.com/smartcontractkit/chainlink-testing-framework/k8s/blob/master/README.md NetworkChaosFailMajorityNetwork: { ethereum.New(nil), - chainlink.New(0, defaultOCRSettings), + chainlinkCfg, chaos.NewNetworkPartition, &chaos.Props{ FromLabels: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -87,7 +99,7 @@ func TestOCRChaos(t *testing.T) { }, NetworkChaosFailBlockchainNode: { ethereum.New(nil), - chainlink.New(0, defaultOCRSettings), + chainlinkCfg, chaos.NewNetworkPartition, &chaos.Props{ FromLabels: &map[string]*string{"app": ptr.Ptr("geth")}, @@ -97,7 +109,7 @@ func TestOCRChaos(t *testing.T) { }, PodChaosFailMinorityNodes: { ethereum.New(nil), - chainlink.New(0, defaultOCRSettings), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMinority: ptr.Ptr("1")}, @@ -106,7 +118,7 @@ func TestOCRChaos(t *testing.T) { }, PodChaosFailMajorityNodes: { ethereum.New(nil), - chainlink.New(0, defaultOCRSettings), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -115,7 +127,7 @@ func TestOCRChaos(t *testing.T) { }, PodChaosFailMajorityDB: { ethereum.New(nil), - chainlink.New(0, defaultOCRSettings), + chainlinkCfg, chaos.NewFailPods, &chaos.Props{ LabelsSelector: &map[string]*string{ChaosGroupMajority: ptr.Ptr("1")}, @@ -164,7 +176,7 @@ func TestOCRChaos(t *testing.T) { if chainClient != nil { chainClient.GasStats().PrintStats() } - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &config, chainClient) require.NoError(t, err, "Error tearing down environment") }) diff --git a/integration-tests/client/chainlink.go b/integration-tests/client/chainlink.go index 16299a1ac8a..56670812fbc 100644 --- a/integration-tests/client/chainlink.go +++ b/integration-tests/client/chainlink.go @@ -267,6 +267,7 @@ func (c *ChainlinkClient) DeleteSpec(id string) (*http.Response, error) { // MustCreateBridge creates a bridge on the Chainlink node based on the provided attributes and returns error if // the request is unsuccessful func (c *ChainlinkClient) MustCreateBridge(bta *BridgeTypeAttributes) error { + c.l.Debug().Str(NodeURL, c.Config.URL).Str("Name", bta.Name).Msg("Creating Bridge") resp, err := c.CreateBridge(bta) if err != nil { return err @@ -275,7 +276,7 @@ func (c *ChainlinkClient) MustCreateBridge(bta *BridgeTypeAttributes) error { } func (c *ChainlinkClient) CreateBridge(bta *BridgeTypeAttributes) (*http.Response, error) { - c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", bta.Name).Msg("Creating Bridge") + c.l.Debug().Str(NodeURL, c.Config.URL).Str("Name", bta.Name).Msg("Creating Bridge") resp, err := c.APIClient.R(). SetBody(bta). Post("/v2/bridge_types") @@ -288,7 +289,7 @@ func (c *ChainlinkClient) CreateBridge(bta *BridgeTypeAttributes) (*http.Respons // ReadBridge reads a bridge from the Chainlink node based on the provided name func (c *ChainlinkClient) ReadBridge(name string) (*BridgeType, *http.Response, error) { bt := BridgeType{} - c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Reading Bridge") + c.l.Debug().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Reading Bridge") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "name": name, @@ -304,7 +305,7 @@ func (c *ChainlinkClient) ReadBridge(name string) (*BridgeType, *http.Response, // ReadBridges reads bridges from the Chainlink node func (c *ChainlinkClient) ReadBridges() (*Bridges, *resty.Response, error) { result := &Bridges{} - c.l.Info().Str(NodeURL, c.Config.URL).Msg("Getting all bridges") + c.l.Debug().Str(NodeURL, c.Config.URL).Msg("Getting all bridges") resp, err := c.APIClient.R(). SetResult(&result). Get("/v2/bridge_types") @@ -316,7 +317,7 @@ func (c *ChainlinkClient) ReadBridges() (*Bridges, *resty.Response, error) { // DeleteBridge deletes a bridge on the Chainlink node based on the provided name func (c *ChainlinkClient) DeleteBridge(name string) (*http.Response, error) { - c.l.Info().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Deleting Bridge") + c.l.Debug().Str(NodeURL, c.Config.URL).Str("Name", name).Msg("Deleting Bridge") resp, err := c.APIClient.R(). SetPathParams(map[string]string{ "name": name, diff --git a/integration-tests/client/chainlink_k8s.go b/integration-tests/client/chainlink_k8s.go index 27fd956103e..ab4ce341584 100644 --- a/integration-tests/client/chainlink_k8s.go +++ b/integration-tests/client/chainlink_k8s.go @@ -2,7 +2,6 @@ package client import ( - "fmt" "os" "regexp" @@ -42,16 +41,8 @@ func NewChainlinkK8sClient(c *ChainlinkConfig, podName, chartName string) (*Chai // Note: You need to call Run() on the test environment for changes to take effect // Note: This function is not thread safe, call from a single thread func (c *ChainlinkK8sClient) UpgradeVersion(testEnvironment *environment.Environment, newImage, newVersion string) error { - if newVersion == "" { - return fmt.Errorf("new version is empty") - } - if newImage == "" { - newImage = os.Getenv("CHAINLINK_IMAGE") - } log.Info(). Str("Chart Name", c.ChartName). - Str("Old Image", os.Getenv("CHAINLINK_IMAGE")). - Str("Old Version", os.Getenv("CHAINLINK_VERSION")). Str("New Image", newImage). Str("New Version", newVersion). Msg("Upgrading Chainlink Node") diff --git a/integration-tests/client/chainlink_models.go b/integration-tests/client/chainlink_models.go index abc6ef30e41..665ff3c7465 100644 --- a/integration-tests/client/chainlink_models.go +++ b/integration-tests/client/chainlink_models.go @@ -6,10 +6,11 @@ import ( "text/template" "time" + "github.com/pelletier/go-toml/v2" "gopkg.in/guregu/null.v4" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) // EIServiceConfig represents External Initiator service config @@ -628,7 +629,9 @@ func (d *PipelineSpec) String() (string, error) { // VRFV2TxPipelineSpec VRFv2 request with tx callback type VRFV2PlusTxPipelineSpec struct { - Address string + Address string + EstimateGasMultiplier float64 + FromAddress string } // Type returns the type of the pipeline @@ -650,9 +653,10 @@ generate_proof [type=vrfv2plus topics="$(jobRun.logTopics)"] estimate_gas [type=estimategaslimit to="{{ .Address }}" - multiplier="1.1" + multiplier="{{ .EstimateGasMultiplier }}" data="$(generate_proof.output)"] simulate_fulfillment [type=ethcall + from="{{ .FromAddress }}" to="{{ .Address }}" gas="$(estimate_gas)" gasPrice="$(jobSpec.maxGasPrice)" @@ -665,7 +669,9 @@ decode_log->generate_proof->estimate_gas->simulate_fulfillment` // VRFV2TxPipelineSpec VRFv2 request with tx callback type VRFV2TxPipelineSpec struct { - Address string + Address string + EstimateGasMultiplier float64 + FromAddress string } // Type returns the type of the pipeline @@ -687,9 +693,10 @@ vrf [type=vrfv2 topics="$(jobRun.logTopics)"] estimate_gas [type=estimategaslimit to="{{ .Address }}" - multiplier="1.1" + multiplier="{{ .EstimateGasMultiplier }}" data="$(vrf.output)"] simulate [type=ethcall + from="{{ .FromAddress }}" to="{{ .Address }}" gas="$(estimate_gas)" gasPrice="$(jobSpec.maxGasPrice)" @@ -1027,6 +1034,12 @@ func (o *OCR2TaskJobSpec) String() (string, error) { if o.OCR2OracleSpec.FeedID != nil { feedID = o.OCR2OracleSpec.FeedID.Hex() } + relayConfig, err := toml.Marshal(struct { + RelayConfig job.JSONConfig `toml:"relayConfig"` + }{RelayConfig: o.OCR2OracleSpec.RelayConfig}) + if err != nil { + return "", fmt.Errorf("failed to marshal relay config: %w", err) + } specWrap := struct { Name string JobType string @@ -1036,7 +1049,7 @@ func (o *OCR2TaskJobSpec) String() (string, error) { FeedID string Relay string PluginType string - RelayConfig map[string]interface{} + RelayConfig string PluginConfig map[string]interface{} P2PV2Bootstrappers []string OCRKeyBundleID string @@ -1056,7 +1069,7 @@ func (o *OCR2TaskJobSpec) String() (string, error) { FeedID: feedID, Relay: string(o.OCR2OracleSpec.Relay), PluginType: string(o.OCR2OracleSpec.PluginType), - RelayConfig: o.OCR2OracleSpec.RelayConfig, + RelayConfig: string(relayConfig), PluginConfig: o.OCR2OracleSpec.PluginConfig, P2PV2Bootstrappers: o.OCR2OracleSpec.P2PV2Bootstrappers, OCRKeyBundleID: o.OCR2OracleSpec.OCRKeyBundleID.String, @@ -1071,37 +1084,37 @@ func (o *OCR2TaskJobSpec) String() (string, error) { type = "{{ .JobType }}" name = "{{.Name}}" forwardingAllowed = {{.ForwardingAllowed}} -{{if .MaxTaskDuration}} +{{- if .MaxTaskDuration}} maxTaskDuration = "{{ .MaxTaskDuration }}" {{end}} -{{if .PluginType}} +{{- if .PluginType}} pluginType = "{{ .PluginType }}" {{end}} relay = "{{.Relay}}" schemaVersion = 1 contractID = "{{.ContractID}}" -{{if .FeedID}} +{{- if .FeedID}} feedID = "{{.FeedID}}" {{end}} -{{if eq .JobType "offchainreporting2" }} +{{- if eq .JobType "offchainreporting2" }} ocrKeyBundleID = "{{.OCRKeyBundleID}}" {{end}} -{{if eq .JobType "offchainreporting2" }} +{{- if eq .JobType "offchainreporting2" }} transmitterID = "{{.TransmitterID}}" {{end}} -{{if .BlockchainTimeout}} +{{- if .BlockchainTimeout}} blockchainTimeout = "{{.BlockchainTimeout}}" {{end}} -{{if .ContractConfirmations}} +{{- if .ContractConfirmations}} contractConfigConfirmations = {{.ContractConfirmations}} {{end}} -{{if .TrackerPollInterval}} +{{- if .TrackerPollInterval}} contractConfigTrackerPollInterval = "{{.TrackerPollInterval}}" {{end}} -{{if .TrackerSubscribeInterval}} +{{- if .TrackerSubscribeInterval}} contractConfigTrackerSubscribeInterval = "{{.TrackerSubscribeInterval}}" {{end}} -{{if .P2PV2Bootstrappers}} +{{- if .P2PV2Bootstrappers}} p2pv2Bootstrappers = [{{range .P2PV2Bootstrappers}}"{{.}}",{{end}}]{{end}} -{{if .MonitoringEndpoint}} +{{- if .MonitoringEndpoint}} monitoringEndpoint = "{{.MonitoringEndpoint}}" {{end}} -{{if .ObservationSource}} +{{- if .ObservationSource}} observationSource = """ {{.ObservationSource}} """{{end}} @@ -1109,26 +1122,28 @@ observationSource = """ [pluginConfig]{{range $key, $value := .PluginConfig}} {{$key}} = {{$value}}{{end}} {{end}} -[relayConfig]{{range $key, $value := .RelayConfig}} -{{$key}} = {{$value}}{{end}} +{{.RelayConfig}} ` return MarshallTemplate(specWrap, "OCR2 Job", ocr2TemplateString) } // VRFV2PlusJobSpec represents a VRFV2 job type VRFV2PlusJobSpec struct { - Name string `toml:"name"` - CoordinatorAddress string `toml:"coordinatorAddress"` // Address of the VRF CoordinatorV2 contract - PublicKey string `toml:"publicKey"` // Public key of the proving key - ExternalJobID string `toml:"externalJobID"` - ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node - MinIncomingConfirmations int `toml:"minIncomingConfirmations"` - FromAddresses []string `toml:"fromAddresses"` - EVMChainID string `toml:"evmChainID"` - BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` - BackOffInitialDelay time.Duration `toml:"backOffInitialDelay"` - BackOffMaxDelay time.Duration `toml:"backOffMaxDelay"` - PollPeriod time.Duration `toml:"pollPeriod"` + Name string `toml:"name"` + CoordinatorAddress string `toml:"coordinatorAddress"` // Address of the VRF CoordinatorV2 contract + PublicKey string `toml:"publicKey"` // Public key of the proving key + ExternalJobID string `toml:"externalJobID"` + ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node + MinIncomingConfirmations int `toml:"minIncomingConfirmations"` + FromAddresses []string `toml:"fromAddresses"` + EVMChainID string `toml:"evmChainID"` + ForwardingAllowed bool `toml:"forwardingAllowed"` + BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` + BatchFulfillmentGasMultiplier float64 `toml:"batchFulfillmentGasMultiplier"` + BackOffInitialDelay time.Duration `toml:"backOffInitialDelay"` + BackOffMaxDelay time.Duration `toml:"backOffMaxDelay"` + PollPeriod time.Duration `toml:"pollPeriod"` + RequestTimeout time.Duration `toml:"requestTimeout"` } // Type returns the type of the job @@ -1147,8 +1162,11 @@ minIncomingConfirmations = {{.MinIncomingConfirmations}} publicKey = "{{.PublicKey}}" externalJobID = "{{.ExternalJobID}}" batchFulfillmentEnabled = {{.BatchFulfillmentEnabled}} +batchFulfillmentGasMultiplier = {{.BatchFulfillmentGasMultiplier}} backoffInitialDelay = "{{.BackOffInitialDelay}}" backoffMaxDelay = "{{.BackOffMaxDelay}}" +pollPeriod = "{{.PollPeriod}}" +requestTimeout = "{{.RequestTimeout}}" observationSource = """ {{.ObservationSource}} """ @@ -1158,17 +1176,24 @@ observationSource = """ // VRFV2JobSpec represents a VRFV2 job type VRFV2JobSpec struct { - Name string `toml:"name"` - CoordinatorAddress string `toml:"coordinatorAddress"` // Address of the VRF CoordinatorV2 contract - PublicKey string `toml:"publicKey"` // Public key of the proving key - ExternalJobID string `toml:"externalJobID"` - ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node - MinIncomingConfirmations int `toml:"minIncomingConfirmations"` - FromAddresses []string `toml:"fromAddresses"` - EVMChainID string `toml:"evmChainID"` - BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` - BackOffInitialDelay time.Duration `toml:"backOffInitialDelay"` - BackOffMaxDelay time.Duration `toml:"backOffMaxDelay"` + Name string `toml:"name"` + CoordinatorAddress string `toml:"coordinatorAddress"` // Address of the VRF CoordinatorV2 contract + PublicKey string `toml:"publicKey"` // Public key of the proving key + ExternalJobID string `toml:"externalJobID"` + ObservationSource string `toml:"observationSource"` // List of commands for the Chainlink node + MinIncomingConfirmations int `toml:"minIncomingConfirmations"` + FromAddresses []string `toml:"fromAddresses"` + EVMChainID string `toml:"evmChainID"` + UseVRFOwner bool `toml:"useVRFOwner"` + VRFOwner string `toml:"vrfOwnerAddress"` + ForwardingAllowed bool `toml:"forwardingAllowed"` + CustomRevertsPipelineEnabled bool `toml:"customRevertsPipelineEnabled"` + PollPeriod time.Duration `toml:"pollPeriod"` + RequestTimeout time.Duration `toml:"requestTimeout"` + BatchFulfillmentEnabled bool `toml:"batchFulfillmentEnabled"` + BatchFulfillmentGasMultiplier float64 `toml:"batchFulfillmentGasMultiplier"` + BackOffInitialDelay time.Duration `toml:"backOffInitialDelay"` + BackOffMaxDelay time.Duration `toml:"backOffMaxDelay"` } // Type returns the type of the job @@ -1180,6 +1205,7 @@ func (v *VRFV2JobSpec) String() (string, error) { type = "vrf" schemaVersion = 1 name = "{{.Name}}" +forwardingAllowed = {{.ForwardingAllowed}} coordinatorAddress = "{{.CoordinatorAddress}}" fromAddresses = [{{range .FromAddresses}}"{{.}}",{{end}}] evmChainID = "{{.EVMChainID}}" @@ -1187,8 +1213,13 @@ minIncomingConfirmations = {{.MinIncomingConfirmations}} publicKey = "{{.PublicKey}}" externalJobID = "{{.ExternalJobID}}" batchFulfillmentEnabled = {{.BatchFulfillmentEnabled}} +batchFulfillmentGasMultiplier = {{.BatchFulfillmentGasMultiplier}} backoffInitialDelay = "{{.BackOffInitialDelay}}" backoffMaxDelay = "{{.BackOffMaxDelay}}" +pollPeriod = "{{.PollPeriod}}" +requestTimeout = "{{.RequestTimeout}}" +customRevertsPipelineEnabled = true +{{ if .UseVRFOwner }}vrfOwnerAddress = "{{.VRFOwner}}"{{ else }}{{ end }} observationSource = """ {{.ObservationSource}} """ @@ -1420,6 +1451,6 @@ type ReplayResponseData struct { } type ReplayResponseAttributes struct { - Message string `json:"message"` - EVMChainID *utils.Big `json:"evmChainID"` + Message string `json:"message"` + EVMChainID *big.Big `json:"evmChainID"` } diff --git a/integration-tests/client/chainlink_models_test.go b/integration-tests/client/chainlink_models_test.go new file mode 100644 index 00000000000..5dbac2c27c4 --- /dev/null +++ b/integration-tests/client/chainlink_models_test.go @@ -0,0 +1,135 @@ +package client + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +func TestOCR2TaskJobSpec_String(t *testing.T) { + for _, tt := range []struct { + name string + spec OCR2TaskJobSpec + exp string + }{ + { + name: "chain-reader-codec", + spec: OCR2TaskJobSpec{ + OCR2OracleSpec: job.OCR2OracleSpec{ + RelayConfig: map[string]interface{}{ + "chainID": 1337, + "fromBlock": 42, + "chainReader": evmtypes.ChainReaderConfig{ + Contracts: map[string]evmtypes.ChainContractReader{ + "median": { + ContractABI: `[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + } + ], + "name": "RoundRequested", + "type": "event" + } +] +`, + Configs: map[string]*evmtypes.ChainReaderDefinition{ + "LatestTransmissionDetails": { + ChainSpecificName: "latestTransmissionDetails", + OutputModifications: codec.ModifiersConfig{ + &codec.EpochToTimeModifierConfig{ + Fields: []string{"LatestTimestamp_"}, + }, + &codec.RenameModifierConfig{ + Fields: map[string]string{ + "LatestAnswer_": "LatestAnswer", + "LatestTimestamp_": "LatestTimestamp", + }, + }, + }, + }, + "LatestRoundRequested": { + ChainSpecificName: "RoundRequested", + ReadType: evmtypes.Event, + }, + }, + }, + }, + }, + "codec": evmtypes.CodecConfig{ + Configs: map[string]evmtypes.ChainCodecConfig{ + "MedianReport": { + TypeABI: `[ + { + "Name": "Timestamp", + "Type": "uint32" + } +] +`, + }, + }, + }, + }, + PluginConfig: map[string]interface{}{"juelsPerFeeCoinSource": ` // data source 1 + ds1 [type=bridge name="%s"]; + ds1_parse [type=jsonparse path="data"]; + ds1_multiply [type=multiply times=2]; + + // data source 2 + ds2 [type=http method=GET url="%s"]; + ds2_parse [type=jsonparse path="data"]; + ds2_multiply [type=multiply times=2]; + + ds1 -> ds1_parse -> ds1_multiply -> answer1; + ds2 -> ds2_parse -> ds2_multiply -> answer1; + + answer1 [type=median index=0]; +`, + }, + }, + }, + exp: ` +type = "" +name = "" +forwardingAllowed = false +relay = "" +schemaVersion = 1 +contractID = "" + +[relayConfig] +chainID = 1337 +fromBlock = 42 + +[relayConfig.chainReader] +[relayConfig.chainReader.contracts] +[relayConfig.chainReader.contracts.median] +contractABI = "[\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"requester\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"RoundRequested\",\n \"type\": \"event\"\n }\n]\n" + +[relayConfig.chainReader.contracts.median.configs] +LatestRoundRequested = "{\n \"chainSpecificName\": \"RoundRequested\",\n \"readType\": \"event\"\n}\n" +LatestTransmissionDetails = "{\n \"chainSpecificName\": \"latestTransmissionDetails\",\n \"output_modifications\": [\n {\n \"Fields\": [\n \"LatestTimestamp_\"\n ],\n \"Type\": \"epoch to time\"\n },\n {\n \"Fields\": {\n \"LatestAnswer_\": \"LatestAnswer\",\n \"LatestTimestamp_\": \"LatestTimestamp\"\n },\n \"Type\": \"rename\"\n }\n ]\n}\n" + +[relayConfig.codec] +[relayConfig.codec.configs] +[relayConfig.codec.configs.MedianReport] +typeABI = "[\n {\n \"Name\": \"Timestamp\",\n \"Type\": \"uint32\"\n }\n]\n" + +`, + }, + } { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.spec.String() + require.NoError(t, err) + require.Equal(t, tt.exp, got) + }) + } +} diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 528f07ec68e..2acc0a2109e 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -1,11 +1,15 @@ package contracts import ( + "context" "errors" "fmt" "math/big" + "strings" "time" + "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" @@ -17,6 +21,7 @@ import ( ocrConfigHelper "github.com/smartcontractkit/libocr/offchainreporting/confighelper" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_mock_ethlink_aggregator" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_load_test_client" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/functions/generated/functions_v1_events_mock" @@ -83,6 +88,7 @@ type ContractDeployer interface { LoadOffChainAggregator(address *common.Address) (OffchainAggregator, error) DeployVRFContract() (VRF, error) DeployMockETHLINKFeed(answer *big.Int) (MockETHLINKFeed, error) + DeployVRFMockETHLINKFeed(answer *big.Int) (VRFMockETHLINKFeed, error) LoadETHLINKFeed(address common.Address) (MockETHLINKFeed, error) DeployMockGasFeed(answer *big.Int) (MockGasFeed, error) LoadGasFeed(address common.Address) (MockGasFeed, error) @@ -109,15 +115,19 @@ type ContractDeployer interface { DeployUpkeepCounter(testRange *big.Int, interval *big.Int) (UpkeepCounter, error) DeployUpkeepPerformCounterRestrictive(testRange *big.Int, averageEligibilityCadence *big.Int) (UpkeepPerformCounterRestrictive, error) DeployVRFConsumer(linkAddr string, coordinatorAddr string) (VRFConsumer, error) + DeployVRFOwner(coordinatorAddr string) (VRFOwner, error) + DeployVRFCoordinatorTestV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (*EthereumVRFCoordinatorTestV2, error) DeployVRFConsumerV2(linkAddr string, coordinatorAddr string) (VRFConsumerV2, error) DeployVRFv2Consumer(coordinatorAddr string) (VRFv2Consumer, error) DeployVRFv2LoadTestConsumer(coordinatorAddr string) (VRFv2LoadTestConsumer, error) + DeployVRFV2WrapperLoadTestConsumer(linkAddr string, vrfV2WrapperAddr string) (VRFv2WrapperLoadTestConsumer, error) DeployVRFv2PlusLoadTestConsumer(coordinatorAddr string) (VRFv2PlusLoadTestConsumer, error) DeployVRFV2PlusWrapperLoadTestConsumer(linkAddr string, vrfV2PlusWrapperAddr string) (VRFv2PlusWrapperLoadTestConsumer, error) DeployVRFCoordinator(linkAddr string, bhsAddr string) (VRFCoordinator, error) DeployVRFCoordinatorV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (VRFCoordinatorV2, error) DeployVRFCoordinatorV2_5(bhsAddr string) (VRFCoordinatorV2_5, error) DeployVRFCoordinatorV2PlusUpgradedVersion(bhsAddr string) (VRFCoordinatorV2PlusUpgradedVersion, error) + DeployVRFV2Wrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2Wrapper, error) DeployVRFV2PlusWrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2PlusWrapper, error) DeployDKG() (DKG, error) DeployOCR2VRFCoordinator(beaconPeriodBlocksCount *big.Int, linkAddr string) (VRFCoordinatorV3, error) @@ -135,6 +145,7 @@ type ContractDeployer interface { DeployOffchainAggregatorEventsMock() (OffchainAggregatorEventsMock, error) DeployMockAggregatorProxy(aggregatorAddr string) (MockAggregatorProxy, error) DeployOffchainAggregatorV2(linkAddr string, offchainOptions OffchainOptions) (OffchainAggregatorV2, error) + LoadOffChainAggregatorV2(address *common.Address) (OffchainAggregatorV2, error) DeployKeeperRegistryCheckUpkeepGasUsageWrapper(keeperRegistryAddr string) (KeeperRegistryCheckUpkeepGasUsageWrapper, error) DeployKeeperRegistry11Mock() (KeeperRegistry11Mock, error) DeployKeeperRegistrar12Mock() (KeeperRegistrar12Mock, error) @@ -144,6 +155,7 @@ type ContractDeployer interface { DeployMercuryFeeManager(linkAddress common.Address, nativeAddress common.Address, proxyAddress common.Address, rewardManagerAddress common.Address) (MercuryFeeManager, error) DeployMercuryRewardManager(linkAddress common.Address) (MercuryRewardManager, error) DeployLogEmitterContract() (LogEmitter, error) + DeployMultiCallContract() (common.Address, error) } // NewContractDeployer returns an instance of a contract deployer based on the client type @@ -692,6 +704,23 @@ func (e *EthereumContractDeployer) DeployMockETHLINKFeed(answer *big.Int) (MockE }, err } +func (e *EthereumContractDeployer) DeployVRFMockETHLINKFeed(answer *big.Int) (VRFMockETHLINKFeed, error) { + address, _, instance, err := e.client.DeployContract("VRFMockETHLINKAggregator", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return vrf_mock_ethlink_aggregator.DeployVRFMockETHLINKAggregator(auth, backend, answer) + }) + if err != nil { + return nil, err + } + return &EthereumVRFMockETHLINKFeed{ + client: e.client, + feed: instance.(*vrf_mock_ethlink_aggregator.VRFMockETHLINKAggregator), + address: address, + }, err +} + // LoadETHLINKFeed returns deployed on given address EthereumMockETHLINKFeed func (e *EthereumContractDeployer) LoadETHLINKFeed(address common.Address) (MockETHLINKFeed, error) { instance, err := e.client.LoadContract("MockETHLINKFeed", address, func( @@ -1584,6 +1613,25 @@ func (e *EthereumContractDeployer) DeployOffchainAggregatorV2( }, err } +// LoadOffChainAggregatorV2 loads an already deployed offchain aggregator v2 contract +func (e *EthereumContractDeployer) LoadOffChainAggregatorV2(address *common.Address) (OffchainAggregatorV2, error) { + instance, err := e.client.LoadContract("OffChainAggregatorV2", *address, func( + address common.Address, + backend bind.ContractBackend, + ) (interface{}, error) { + return ocr2aggregator.NewOCR2Aggregator(address, backend) + }) + if err != nil { + return nil, err + } + return &EthereumOffchainAggregatorV2{ + client: e.client, + contract: instance.(*ocr2aggregator.OCR2Aggregator), + address: address, + l: e.l, + }, err +} + func (e *EthereumContractDeployer) DeployMercuryVerifierContract(verifierProxyAddr common.Address) (MercuryVerifier, error) { address, _, instance, err := e.client.DeployContract("Mercury Verifier", func( auth *bind.TransactOpts, @@ -1691,3 +1739,32 @@ func (e *EthereumContractDeployer) DeployLogEmitterContract() (LogEmitter, error l: e.l, }, err } + +func (e *EthereumContractDeployer) DeployMultiCallContract() (common.Address, error) { + multiCallABI, err := abi.JSON(strings.NewReader(MultiCallABI)) + if err != nil { + return common.Address{}, err + } + address, tx, _, err := e.client.DeployContract("MultiCall Contract", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + address, tx, contract, err := bind.DeployContract(auth, multiCallABI, common.FromHex(MultiCallBIN), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, contract, err + }) + if err != nil { + return common.Address{}, err + } + r, err := bind.WaitMined(context.Background(), e.client.DeployBackend(), tx) + if err != nil { + return common.Address{}, err + } + if r.Status != types.ReceiptStatusSuccessful { + return common.Address{}, fmt.Errorf("deploy multicall failed") + } + return *address, nil + +} diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index 6136e78b367..0fec424426a 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -71,6 +71,16 @@ func NewContractLoader(bcClient blockchain.EVMClient, logger zerolog.Logger) (Co return &PolygonZkEvmContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil case *blockchain.WeMixClient: return &WeMixContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.LineaClient: + return &LineaContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.CeloClient: + return &CeloContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.ScrollClient: + return &ScrollContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.FantomClient: + return &FantomContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil + case *blockchain.BSCClient: + return &BSCContractLoader{NewEthereumContractLoader(clientImpl, logger)}, nil } return nil, errors.New("unknown blockchain client implementation for contract Loader, register blockchain client in NewContractLoader") } @@ -119,6 +129,31 @@ type WeMixContractLoader struct { *EthereumContractLoader } +// LineaContractLoader wraps for Linea +type LineaContractLoader struct { + *EthereumContractLoader +} + +// CeloContractLoader wraps for Celo +type CeloContractLoader struct { + *EthereumContractLoader +} + +// ScrollContractLoader wraps for Scroll +type ScrollContractLoader struct { + *EthereumContractLoader +} + +// FantomContractLoader wraps for Fantom +type FantomContractLoader struct { + *EthereumContractLoader +} + +// BSCContractLoader wraps for BSC +type BSCContractLoader struct { + *EthereumContractLoader +} + // NewEthereumContractLoader returns an instantiated instance of the ETH contract Loader func NewEthereumContractLoader(ethClient blockchain.EVMClient, logger zerolog.Logger) *EthereumContractLoader { return &EthereumContractLoader{ diff --git a/integration-tests/contracts/contract_models.go b/integration-tests/contracts/contract_models.go index 4c8d610fa1b..3d738033d68 100644 --- a/integration-tests/contracts/contract_models.go +++ b/integration-tests/contracts/contract_models.go @@ -405,6 +405,7 @@ type LogEmitter interface { Address() common.Address EmitLogInts(ints []int) (*types.Transaction, error) EmitLogIntsIndexed(ints []int) (*types.Transaction, error) + EmitLogIntMultiIndexed(ints int, ints2 int, count int) (*types.Transaction, error) EmitLogStrings(strings []string) (*types.Transaction, error) EmitLogInt(payload int) (*types.Transaction, error) EmitLogIntIndexed(payload int) (*types.Transaction, error) diff --git a/integration-tests/contracts/contract_vrf_models.go b/integration-tests/contracts/contract_vrf_models.go index 548cac252b1..2faf97df16f 100644 --- a/integration-tests/contracts/contract_vrf_models.go +++ b/integration-tests/contracts/contract_vrf_models.go @@ -11,9 +11,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2_5" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2_consumer_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_load_test_with_metrics" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2plus_wrapper_load_test_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/dkg" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ocr2vrf/generated/vrf_beacon" @@ -36,6 +38,10 @@ type VRFCoordinator interface { } type VRFCoordinatorV2 interface { + GetRequestConfig(ctx context.Context) (GetRequestConfig, error) + GetConfig(ctx context.Context) (vrf_coordinator_v2.GetConfig, error) + GetFallbackWeiPerUnitLink(ctx context.Context) (*big.Int, error) + GetFeeConfig(ctx context.Context) (vrf_coordinator_v2.GetFeeConfig, error) SetConfig( minimumRequestConfirmations uint16, maxGasLimit uint32, @@ -48,16 +54,26 @@ type VRFCoordinatorV2 interface { oracleAddr string, publicProvingKey [2]*big.Int, ) error + TransferOwnership(to common.Address) error HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) CreateSubscription() (*types.Transaction, error) AddConsumer(subId uint64, consumerAddress string) error Address() string GetSubscription(ctx context.Context, subID uint64) (vrf_coordinator_v2.GetSubscription, error) + GetOwner(ctx context.Context) (common.Address, error) PendingRequestsExist(ctx context.Context, subID uint64) (bool, error) + OwnerCancelSubscription(subID uint64) (*types.Transaction, 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) 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) + OracleWithdraw(recipient common.Address, amount *big.Int) error } type VRFCoordinatorV2_5 interface { @@ -74,7 +90,6 @@ type VRFCoordinatorV2_5 interface { feeConfig vrf_coordinator_v2_5.VRFCoordinatorV25FeeConfig, ) error RegisterProvingKey( - oracleAddr string, publicProvingKey [2]*big.Int, ) error HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) @@ -89,8 +104,8 @@ type VRFCoordinatorV2_5 interface { GetSubscription(ctx context.Context, subID *big.Int) (vrf_coordinator_v2_5.GetSubscription, error) OwnerCancelSubscription(subID *big.Int) (*types.Transaction, error) CancelSubscription(subID *big.Int, to common.Address) (*types.Transaction, error) - OracleWithdraw(recipient common.Address, amount *big.Int) error - OracleWithdrawNative(recipient common.Address, amount *big.Int) error + Withdraw(recipient common.Address) error + WithdrawNative(recipient common.Address) error GetNativeTokenTotalBalance(ctx context.Context) (*big.Int, error) GetLinkTotalBalance(ctx context.Context) (*big.Int, error) FindSubscriptionID(subID *big.Int) (*big.Int, error) @@ -115,7 +130,6 @@ type VRFCoordinatorV2PlusUpgradedVersion interface { feeConfig vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionFeeConfig, ) error RegisterProvingKey( - oracleAddr string, publicProvingKey [2]*big.Int, ) error HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) @@ -135,12 +149,25 @@ type VRFCoordinatorV2PlusUpgradedVersion interface { WaitForRandomWordsRequestedEvent(keyHash [][32]byte, subID []*big.Int, sender []common.Address, timeout time.Duration) (*vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionRandomWordsRequested, error) } +type VRFV2Wrapper interface { + Address() string + SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8) error + GetSubID(ctx context.Context) (uint64, error) +} + type VRFV2PlusWrapper interface { Address() string SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8, stalenessSeconds uint32, fallbackWeiPerUnitLink *big.Int, fulfillmentFlatFeeLinkPPM uint32, fulfillmentFlatFeeNativePPM uint32) error GetSubID(ctx context.Context) (*big.Int, error) } +type VRFOwner interface { + Address() string + SetAuthorizedSenders(senders []common.Address) error + AcceptVRFOwnership() error + WaitForRandomWordsForcedEvent(requestIDs []*big.Int, subIds []uint64, senders []common.Address, timeout time.Duration) (*vrf_owner.VRFOwnerRandomWordsForced, error) +} + type VRFConsumer interface { Address() string RequestRandomness(hash [32]byte, fee *big.Int) error @@ -171,12 +198,31 @@ type VRFv2Consumer interface { type VRFv2LoadTestConsumer interface { Address() string RequestRandomness(hash [32]byte, subID uint64, confs uint16, gasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) + RequestRandomWordsWithForceFulfill( + keyHash [32]byte, + requestConfirmations uint16, + callbackGasLimit uint32, + numWords uint32, + requestCount uint16, + subTopUpAmount *big.Int, + linkAddress common.Address, + ) (*types.Transaction, 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) ResetMetrics() error } +type VRFv2WrapperLoadTestConsumer interface { + Address() string + Fund(ethAmount *big.Float) error + RequestRandomness(requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, 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) + GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) +} + 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) @@ -262,6 +308,13 @@ type BatchBlockhashStore interface { Address() string } +type VRFMockETHLINKFeed interface { + Address() string + LatestRoundData() (*big.Int, error) + LatestRoundDataUpdatedAt() (*big.Int, error) + SetBlockTimestampDeduction(blockTimestampDeduction *big.Int) error +} + type RequestStatus struct { Fulfilled bool RandomWords []*big.Int diff --git a/integration-tests/contracts/ethereum_keeper_contracts.go b/integration-tests/contracts/ethereum_keeper_contracts.go index 7519b5de4cf..a15fcfc7aea 100644 --- a/integration-tests/contracts/ethereum_keeper_contracts.go +++ b/integration-tests/contracts/ethereum_keeper_contracts.go @@ -19,8 +19,8 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink/integration-tests/testreporters" cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_consumer_benchmark" registrar21 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_registrar_wrapper2_1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" @@ -39,9 +39,9 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/streams_lookup_upkeep_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_perform_counter_restrictive_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_transcoder" - "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/integration-tests/testreporters" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_consumer_performance_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/keeper_consumer_wrapper" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/upkeep_counter_wrapper" diff --git a/integration-tests/contracts/ethereum_vrfv2_contracts.go b/integration-tests/contracts/ethereum_vrfv2_contracts.go index d1637c93c87..7501521ac33 100644 --- a/integration-tests/contracts/ethereum_vrfv2_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2_contracts.go @@ -14,10 +14,15 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_test_v2" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_mock_ethlink_aggregator" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_owner" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_consumer_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_coordinator_v2" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_load_test_with_metrics" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrfv2_wrapper_load_test_consumer" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2_consumer_wrapper" ) @@ -29,6 +34,18 @@ type EthereumVRFCoordinatorV2 struct { coordinator *vrf_coordinator_v2.VRFCoordinatorV2 } +type EthereumVRFOwner struct { + address *common.Address + client blockchain.EVMClient + vrfOwner *vrf_owner.VRFOwner +} + +type EthereumVRFCoordinatorTestV2 struct { + address *common.Address + client blockchain.EVMClient + coordinator *vrf_coordinator_test_v2.VRFCoordinatorTestV2 +} + // EthereumVRFConsumerV2 represents VRFv2 consumer contract type EthereumVRFConsumerV2 struct { address *common.Address @@ -50,6 +67,30 @@ type EthereumVRFv2LoadTestConsumer struct { consumer *vrf_load_test_with_metrics.VRFV2LoadTestWithMetrics } +type EthereumVRFV2Wrapper struct { + address *common.Address + client blockchain.EVMClient + wrapper *vrfv2_wrapper.VRFV2Wrapper +} + +type EthereumVRFV2WrapperLoadTestConsumer struct { + address *common.Address + client blockchain.EVMClient + consumer *vrfv2_wrapper_load_test_consumer.VRFV2WrapperLoadTestConsumer +} + +type GetRequestConfig struct { + MinimumRequestConfirmations uint16 + MaxGasLimit uint32 + ProvingKeyHashes [32]byte +} + +type EthereumVRFMockETHLINKFeed struct { + client blockchain.EVMClient + feed *vrf_mock_ethlink_aggregator.VRFMockETHLINKAggregator + address *common.Address +} + // DeployVRFCoordinatorV2 deploys VRFV2 coordinator contract func (e *EthereumContractDeployer) DeployVRFCoordinatorV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (VRFCoordinatorV2, error) { address, _, instance, err := e.client.DeployContract("VRFCoordinatorV2", func( @@ -68,6 +109,40 @@ func (e *EthereumContractDeployer) DeployVRFCoordinatorV2(linkAddr string, bhsAd }, err } +func (e *EthereumContractDeployer) DeployVRFOwner(coordinatorAddr string) (VRFOwner, error) { + address, _, instance, err := e.client.DeployContract("VRFOwner", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return vrf_owner.DeployVRFOwner(auth, backend, common.HexToAddress(coordinatorAddr)) + }) + if err != nil { + return nil, err + } + return &EthereumVRFOwner{ + client: e.client, + vrfOwner: instance.(*vrf_owner.VRFOwner), + address: address, + }, err +} + +func (e *EthereumContractDeployer) DeployVRFCoordinatorTestV2(linkAddr string, bhsAddr string, linkEthFeedAddr string) (*EthereumVRFCoordinatorTestV2, error) { + address, _, instance, err := e.client.DeployContract("VRFCoordinatorTestV2", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return vrf_coordinator_test_v2.DeployVRFCoordinatorTestV2(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(bhsAddr), common.HexToAddress(linkEthFeedAddr)) + }) + if err != nil { + return nil, err + } + return &EthereumVRFCoordinatorTestV2{ + client: e.client, + coordinator: instance.(*vrf_coordinator_test_v2.VRFCoordinatorTestV2), + address: address, + }, err +} + // DeployVRFConsumerV2 deploys VRFv@ consumer contract func (e *EthereumContractDeployer) DeployVRFConsumerV2(linkAddr string, coordinatorAddr string) (VRFConsumerV2, error) { address, _, instance, err := e.client.DeployContract("VRFConsumerV2", func( @@ -121,6 +196,40 @@ func (e *EthereumContractDeployer) DeployVRFv2LoadTestConsumer(coordinatorAddr s }, err } +func (e *EthereumContractDeployer) DeployVRFV2Wrapper(linkAddr string, linkEthFeedAddr string, coordinatorAddr string) (VRFV2Wrapper, error) { + address, _, instance, err := e.client.DeployContract("VRFV2Wrapper", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return vrfv2_wrapper.DeployVRFV2Wrapper(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(linkEthFeedAddr), common.HexToAddress(coordinatorAddr)) + }) + if err != nil { + return nil, err + } + return &EthereumVRFV2Wrapper{ + address: address, + client: e.client, + wrapper: instance.(*vrfv2_wrapper.VRFV2Wrapper), + }, err +} + +func (e *EthereumContractDeployer) DeployVRFV2WrapperLoadTestConsumer(linkAddr string, vrfV2WrapperAddr string) (VRFv2WrapperLoadTestConsumer, error) { + address, _, instance, err := e.client.DeployContract("VRFV2WrapperLoadTestConsumer", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + return vrfv2_wrapper_load_test_consumer.DeployVRFV2WrapperLoadTestConsumer(auth, backend, common.HexToAddress(linkAddr), common.HexToAddress(vrfV2WrapperAddr)) + }) + if err != nil { + return nil, err + } + return &EthereumVRFV2WrapperLoadTestConsumer{ + address: address, + client: e.client, + consumer: instance.(*vrfv2_wrapper_load_test_consumer.VRFV2WrapperLoadTestConsumer), + }, err +} + func (v *EthereumVRFCoordinatorV2) Address() string { return v.address.Hex() } @@ -149,6 +258,72 @@ func (v *EthereumVRFCoordinatorV2) GetSubscription(ctx context.Context, subID ui return subscription, nil } +func (v *EthereumVRFCoordinatorV2) GetOwner(ctx context.Context) (common.Address, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + coordinatorOwnerAddress, err := v.coordinator.Owner(opts) + if err != nil { + return common.Address{}, err + } + return coordinatorOwnerAddress, nil +} + +func (v *EthereumVRFCoordinatorV2) GetRequestConfig(ctx context.Context) (GetRequestConfig, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + minConfirmations, maxGas, keyHashes, err := v.coordinator.GetRequestConfig(opts) + if err != nil { + return GetRequestConfig{}, err + } + requestConfig := GetRequestConfig{ + MinimumRequestConfirmations: minConfirmations, + MaxGasLimit: maxGas, + ProvingKeyHashes: keyHashes[0], + } + + return requestConfig, nil +} + +func (v *EthereumVRFCoordinatorV2) GetConfig(ctx context.Context) (vrf_coordinator_v2.GetConfig, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + config, err := v.coordinator.GetConfig(opts) + if err != nil { + return vrf_coordinator_v2.GetConfig{}, err + } + return config, nil +} + +func (v *EthereumVRFCoordinatorV2) GetFallbackWeiPerUnitLink(ctx context.Context) (*big.Int, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + fallbackWeiPerUnitLink, err := v.coordinator.GetFallbackWeiPerUnitLink(opts) + if err != nil { + return nil, err + } + return fallbackWeiPerUnitLink, nil +} + +func (v *EthereumVRFCoordinatorV2) GetFeeConfig(ctx context.Context) (vrf_coordinator_v2.GetFeeConfig, error) { + opts := &bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + } + config, err := v.coordinator.GetFeeConfig(opts) + if err != nil { + return vrf_coordinator_v2.GetFeeConfig{}, err + } + return config, nil +} + func (v *EthereumVRFCoordinatorV2) SetConfig(minimumRequestConfirmations uint16, maxGasLimit uint32, stalenessSeconds uint32, gasAfterPaymentCalculation uint32, fallbackWeiPerUnitLink *big.Int, feeConfig vrf_coordinator_v2.VRFCoordinatorV2FeeConfig) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { @@ -184,6 +359,18 @@ func (v *EthereumVRFCoordinatorV2) RegisterProvingKey( return v.client.ProcessTransaction(tx) } +func (v *EthereumVRFCoordinatorV2) TransferOwnership(to common.Address) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.coordinator.TransferOwnership(opts, to) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + func (v *EthereumVRFCoordinatorV2) CreateSubscription() (*types.Transaction, error) { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { @@ -224,6 +411,37 @@ func (v *EthereumVRFCoordinatorV2) PendingRequestsExist(ctx context.Context, sub return pendingRequestExists, nil } +func (v *EthereumVRFCoordinatorV2) OracleWithdraw(recipient common.Address, amount *big.Int) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.coordinator.OracleWithdraw(opts, recipient, amount) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + +// OwnerCancelSubscription cancels subscription, +// return funds to the subscription owner, +// down not check if pending requests for a sub exist, +// outstanding requests may fail onchain +func (v *EthereumVRFCoordinatorV2) OwnerCancelSubscription(subID uint64) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.coordinator.OwnerCancelSubscription( + opts, + subID, + ) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + // CancelSubscription cancels subscription by Sub owner, // return funds to specified address, // checks if pending requests for a sub exist @@ -300,6 +518,126 @@ func (v *EthereumVRFCoordinatorV2) WaitForRandomWordsRequestedEvent(keyHash [][3 } } +func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionFunded(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionFunded) + subscription, err := v.coordinator.WatchSubscriptionFunded(nil, eventsChannel, subID) + if err != nil { + return nil, err + } + defer subscription.Unsubscribe() + + for { + select { + case err := <-subscription.Err(): + return nil, err + case <-time.After(timeout): + return nil, fmt.Errorf("timeout waiting for SubscriptionFunded event") + case event := <-eventsChannel: + return event, nil + } + } +} + +func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionCanceledEvent(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCanceled) + subscription, err := v.coordinator.WatchSubscriptionCanceled(nil, eventsChannel, subID) + if err != nil { + return nil, err + } + defer subscription.Unsubscribe() + + for { + select { + case err := <-subscription.Err(): + return nil, err + case <-time.After(timeout): + return nil, fmt.Errorf("timeout waiting for SubscriptionCanceled event") + case sub := <-eventsChannel: + return sub, nil + } + } +} + +func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionCreatedEvent(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionCreated) + subscription, err := v.coordinator.WatchSubscriptionCreated(nil, eventsChannel, subID) + if err != nil { + return nil, err + } + defer subscription.Unsubscribe() + + for { + select { + case err := <-subscription.Err(): + return nil, err + case <-time.After(timeout): + return nil, fmt.Errorf("timeout waiting for SubscriptionCreated event") + case event := <-eventsChannel: + return event, nil + } + } +} + +func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionConsumerAdded(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerAdded) + subscription, err := v.coordinator.WatchSubscriptionConsumerAdded(nil, eventsChannel, subID) + if err != nil { + return nil, err + } + defer subscription.Unsubscribe() + + for { + select { + case err := <-subscription.Err(): + return nil, err + case <-time.After(timeout): + return nil, fmt.Errorf("timeout waiting for SubscriptionConsumerAdded event") + case event := <-eventsChannel: + return event, nil + } + } +} + +func (v *EthereumVRFCoordinatorV2) WaitForSubscriptionConsumerRemoved(subID []uint64, timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2SubscriptionConsumerRemoved) + subscription, err := v.coordinator.WatchSubscriptionConsumerRemoved(nil, eventsChannel, subID) + if err != nil { + return nil, err + } + defer subscription.Unsubscribe() + + for { + select { + case err := <-subscription.Err(): + return nil, err + case <-time.After(timeout): + return nil, fmt.Errorf("timeout waiting for SubscriptionConsumerRemoved event") + case event := <-eventsChannel: + return event, nil + } + } +} + +func (v *EthereumVRFCoordinatorV2) WaitForConfigSetEvent(timeout time.Duration) (*vrf_coordinator_v2.VRFCoordinatorV2ConfigSet, error) { + eventsChannel := make(chan *vrf_coordinator_v2.VRFCoordinatorV2ConfigSet) + 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 ConfigSet event") + case event := <-eventsChannel: + return event, nil + } + } +} + // GetAllRandomWords get all VRFv2 randomness output words func (v *EthereumVRFConsumerV2) GetAllRandomWords(ctx context.Context, num int) ([]*big.Int, error) { words := make([]*big.Int, 0) @@ -461,6 +799,35 @@ func (v *EthereumVRFv2LoadTestConsumer) RequestRandomness( return tx, v.client.ProcessTransaction(tx) } +func (v *EthereumVRFv2LoadTestConsumer) RequestRandomWordsWithForceFulfill( + keyHash [32]byte, + requestConfirmations uint16, + callbackGasLimit uint32, + numWords uint32, + requestCount uint16, + subTopUpAmount *big.Int, + linkAddress common.Address, +) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.consumer.RequestRandomWordsWithForceFulfill( + opts, + requestConfirmations, + keyHash, + callbackGasLimit, + numWords, + requestCount, + subTopUpAmount, + linkAddress, + ) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + func (v *EthereumVRFv2Consumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrf_v2_consumer_wrapper.GetRequestStatus, error) { return v.consumer.GetRequestStatus(&bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), @@ -548,3 +915,219 @@ func (v *EthereumVRFv2LoadTestConsumer) GetLoadTestMetrics(ctx context.Context) fastestFulfillment, }, nil } + +func (v *EthereumVRFV2Wrapper) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFV2Wrapper) SetConfig(wrapperGasOverhead uint32, coordinatorGasOverhead uint32, wrapperPremiumPercentage uint8, keyHash [32]byte, maxNumWords uint8) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.wrapper.SetConfig( + opts, + wrapperGasOverhead, + coordinatorGasOverhead, + wrapperPremiumPercentage, + keyHash, + maxNumWords, + ) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFV2Wrapper) GetSubID(ctx context.Context) (uint64, error) { + return v.wrapper.SUBSCRIPTIONID(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) Fund(ethAmount *big.Float) error { + gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{}) + if err != nil { + return err + } + return v.client.Fund(v.address.Hex(), ethAmount, gasEstimates) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) RequestRandomness(requestConfirmations uint16, callbackGasLimit uint32, numWords uint32, requestCount uint16) (*types.Transaction, error) { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := v.consumer.MakeRequests(opts, callbackGasLimit, requestConfirmations, numWords, requestCount) + if err != nil { + return nil, err + } + return tx, v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) GetRequestStatus(ctx context.Context, requestID *big.Int) (vrfv2_wrapper_load_test_consumer.GetRequestStatus, error) { + return v.consumer.GetRequestStatus(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }, requestID) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) GetLastRequestId(ctx context.Context) (*big.Int, error) { + return v.consumer.SLastRequestId(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) GetWrapper(ctx context.Context) (common.Address, error) { + return v.consumer.IVrfV2Wrapper(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) +} + +func (v *EthereumVRFV2WrapperLoadTestConsumer) GetLoadTestMetrics(ctx context.Context) (*VRFLoadTestMetrics, error) { + requestCount, err := v.consumer.SRequestCount(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) + if err != nil { + return nil, err + } + fulfilmentCount, err := v.consumer.SResponseCount(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) + + if err != nil { + return nil, err + } + averageFulfillmentInMillions, err := v.consumer.SAverageFulfillmentInMillions(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) + if err != nil { + return nil, err + } + slowestFulfillment, err := v.consumer.SSlowestFulfillment(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) + + if err != nil { + return nil, err + } + fastestFulfillment, err := v.consumer.SFastestFulfillment(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: ctx, + }) + if err != nil { + return nil, err + } + + return &VRFLoadTestMetrics{ + requestCount, + fulfilmentCount, + averageFulfillmentInMillions, + slowestFulfillment, + fastestFulfillment, + }, nil +} + +func (v *EthereumVRFOwner) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFOwner) SetAuthorizedSenders(senders []common.Address) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.vrfOwner.SetAuthorizedSenders( + opts, + senders, + ) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFOwner) AcceptVRFOwnership() error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.vrfOwner.AcceptVRFOwnership(opts) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} + +func (v *EthereumVRFOwner) WaitForRandomWordsForcedEvent(requestIDs []*big.Int, subIds []uint64, senders []common.Address, timeout time.Duration) (*vrf_owner.VRFOwnerRandomWordsForced, error) { + eventsChannel := make(chan *vrf_owner.VRFOwnerRandomWordsForced) + subscription, err := v.vrfOwner.WatchRandomWordsForced(nil, eventsChannel, requestIDs, subIds, senders) + 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 RandomWordsForced event") + case event := <-eventsChannel: + return event, nil + } + } +} + +func (v *EthereumVRFCoordinatorTestV2) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFMockETHLINKFeed) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFMockETHLINKFeed) LatestRoundData() (*big.Int, error) { + data, err := v.feed.LatestRoundData(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: context.Background(), + }) + if err != nil { + return nil, err + } + return data.Ans, nil +} + +func (v *EthereumVRFMockETHLINKFeed) LatestRoundDataUpdatedAt() (*big.Int, error) { + data, err := v.feed.LatestRoundData(&bind.CallOpts{ + From: common.HexToAddress(v.client.GetDefaultWallet().Address()), + Context: context.Background(), + }) + if err != nil { + return nil, err + } + return data.UpdatedAt, nil +} + +func (v *EthereumVRFMockETHLINKFeed) SetBlockTimestampDeduction(blockTimestampDeduction *big.Int) error { + opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) + if err != nil { + return err + } + tx, err := v.feed.SetBlockTimestampDeduction(opts, blockTimestampDeduction) + if err != nil { + return err + } + return v.client.ProcessTransaction(tx) +} diff --git a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go index 330166dc79d..31c7f1e4f42 100644 --- a/integration-tests/contracts/ethereum_vrfv2plus_contracts.go +++ b/integration-tests/contracts/ethereum_vrfv2plus_contracts.go @@ -180,15 +180,14 @@ func (v *EthereumVRFCoordinatorV2_5) CancelSubscription(subID *big.Int, to commo return tx, v.client.ProcessTransaction(tx) } -func (v *EthereumVRFCoordinatorV2_5) OracleWithdraw(recipient common.Address, amount *big.Int) error { +func (v *EthereumVRFCoordinatorV2_5) Withdraw(recipient common.Address) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err } - tx, err := v.coordinator.OracleWithdraw( + tx, err := v.coordinator.Withdraw( opts, recipient, - amount, ) if err != nil { return err @@ -196,15 +195,14 @@ func (v *EthereumVRFCoordinatorV2_5) OracleWithdraw(recipient common.Address, am return v.client.ProcessTransaction(tx) } -func (v *EthereumVRFCoordinatorV2_5) OracleWithdrawNative(recipient common.Address, amount *big.Int) error { +func (v *EthereumVRFCoordinatorV2_5) WithdrawNative(recipient common.Address) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err } - tx, err := v.coordinator.OracleWithdrawNative( + tx, err := v.coordinator.WithdrawNative( opts, recipient, - amount, ) if err != nil { return err @@ -249,14 +247,13 @@ func (v *EthereumVRFCoordinatorV2_5) SetLINKAndLINKNativeFeed(linkAddress string } func (v *EthereumVRFCoordinatorV2_5) RegisterProvingKey( - oracleAddr string, publicProvingKey [2]*big.Int, ) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err } - tx, err := v.coordinator.RegisterProvingKey(opts, common.HexToAddress(oracleAddr), publicProvingKey) + tx, err := v.coordinator.RegisterProvingKey(opts, publicProvingKey) if err != nil { return err } @@ -638,14 +635,13 @@ func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) SetLINKAndLINKNativeFeed(l } func (v *EthereumVRFCoordinatorV2PlusUpgradedVersion) RegisterProvingKey( - oracleAddr string, publicProvingKey [2]*big.Int, ) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err } - tx, err := v.coordinator.RegisterProvingKey(opts, common.HexToAddress(oracleAddr), publicProvingKey) + tx, err := v.coordinator.RegisterProvingKey(opts, publicProvingKey) if err != nil { return err } diff --git a/integration-tests/contracts/multicall.go b/integration-tests/contracts/multicall.go new file mode 100644 index 00000000000..b809c20021d --- /dev/null +++ b/integration-tests/contracts/multicall.go @@ -0,0 +1,95 @@ +package contracts + +import ( + "context" + "fmt" + "math/big" + "strings" + + "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/pkg/errors" + "github.com/rs/zerolog/log" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" +) + +const ( + MultiCallABI = "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"returnData\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call3[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call3Value[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3Value\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"blockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBasefee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"basefee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainid\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockCoinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockGasLimit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gaslimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getEthBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLastBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryAggregate\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryBlockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]" + MultiCallBIN = "0x608060405234801561001057600080fd5b50610ee0806100206000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e1461025a578063bce38bd714610275578063c3077fa914610288578063ee82ac5e1461029b57600080fd5b80634d2301cc146101ec57806372425d9d1461022157806382ad56cb1461023457806386d516e81461024757600080fd5b80633408e470116100c65780633408e47014610191578063399542e9146101a45780633e64a696146101c657806342cbb15c146101d957600080fd5b80630f28c97d146100f8578063174dea711461011a578063252dba421461013a57806327e86d6e1461015b575b600080fd5b34801561010457600080fd5b50425b6040519081526020015b60405180910390f35b61012d610128366004610a85565b6102ba565b6040516101119190610bbe565b61014d610148366004610a85565b6104ef565b604051610111929190610bd8565b34801561016757600080fd5b50437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0140610107565b34801561019d57600080fd5b5046610107565b6101b76101b2366004610c60565b610690565b60405161011193929190610cba565b3480156101d257600080fd5b5048610107565b3480156101e557600080fd5b5043610107565b3480156101f857600080fd5b50610107610207366004610ce2565b73ffffffffffffffffffffffffffffffffffffffff163190565b34801561022d57600080fd5b5044610107565b61012d610242366004610a85565b6106ab565b34801561025357600080fd5b5045610107565b34801561026657600080fd5b50604051418152602001610111565b61012d610283366004610c60565b61085a565b6101b7610296366004610a85565b610a1a565b3480156102a757600080fd5b506101076102b6366004610d18565b4090565b60606000828067ffffffffffffffff8111156102d8576102d8610d31565b60405190808252806020026020018201604052801561031e57816020015b6040805180820190915260008152606060208201528152602001906001900390816102f65790505b5092503660005b8281101561047757600085828151811061034157610341610d60565b6020026020010151905087878381811061035d5761035d610d60565b905060200281019061036f9190610d8f565b6040810135958601959093506103886020850185610ce2565b73ffffffffffffffffffffffffffffffffffffffff16816103ac6060870187610dcd565b6040516103ba929190610e32565b60006040518083038185875af1925050503d80600081146103f7576040519150601f19603f3d011682016040523d82523d6000602084013e6103fc565b606091505b50602080850191909152901515808452908501351761046d577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b5050600101610325565b508234146104e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d756c746963616c6c333a2076616c7565206d69736d6174636800000000000060448201526064015b60405180910390fd5b50505092915050565b436060828067ffffffffffffffff81111561050c5761050c610d31565b60405190808252806020026020018201604052801561053f57816020015b606081526020019060019003908161052a5790505b5091503660005b8281101561068657600087878381811061056257610562610d60565b90506020028101906105749190610e42565b92506105836020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166105a66020850185610dcd565b6040516105b4929190610e32565b6000604051808303816000865af19150503d80600081146105f1576040519150601f19603f3d011682016040523d82523d6000602084013e6105f6565b606091505b5086848151811061060957610609610d60565b602090810291909101015290508061067d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b50600101610546565b5050509250929050565b43804060606106a086868661085a565b905093509350939050565b6060818067ffffffffffffffff8111156106c7576106c7610d31565b60405190808252806020026020018201604052801561070d57816020015b6040805180820190915260008152606060208201528152602001906001900390816106e55790505b5091503660005b828110156104e657600084828151811061073057610730610d60565b6020026020010151905086868381811061074c5761074c610d60565b905060200281019061075e9190610e76565b925061076d6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166107906040850185610dcd565b60405161079e929190610e32565b6000604051808303816000865af19150503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b506020808401919091529015158083529084013517610851577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b50600101610714565b6060818067ffffffffffffffff81111561087657610876610d31565b6040519080825280602002602001820160405280156108bc57816020015b6040805180820190915260008152606060208201528152602001906001900390816108945790505b5091503660005b82811015610a105760008482815181106108df576108df610d60565b602002602001015190508686838181106108fb576108fb610d60565b905060200281019061090d9190610e42565b925061091c6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff1661093f6020850185610dcd565b60405161094d929190610e32565b6000604051808303816000865af19150503d806000811461098a576040519150601f19603f3d011682016040523d82523d6000602084013e61098f565b606091505b506020830152151581528715610a07578051610a07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b506001016108c3565b5050509392505050565b6000806060610a2b60018686610690565b919790965090945092505050565b60008083601f840112610a4b57600080fd5b50813567ffffffffffffffff811115610a6357600080fd5b6020830191508360208260051b8501011115610a7e57600080fd5b9250929050565b60008060208385031215610a9857600080fd5b823567ffffffffffffffff811115610aaf57600080fd5b610abb85828601610a39565b90969095509350505050565b6000815180845260005b81811015610aed57602081850181015186830182015201610ad1565b81811115610aff576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b84811015610bb1578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001895281518051151584528401516040858501819052610b9d81860183610ac7565b9a86019a9450505090830190600101610b4f565b5090979650505050505050565b602081526000610bd16020830184610b32565b9392505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610c52577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018452610c40868351610ac7565b95509284019290840190600101610c06565b509398975050505050505050565b600080600060408486031215610c7557600080fd5b83358015158114610c8557600080fd5b9250602084013567ffffffffffffffff811115610ca157600080fd5b610cad86828701610a39565b9497909650939450505050565b838152826020820152606060408201526000610cd96060830184610b32565b95945050505050565b600060208284031215610cf457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610bd157600080fd5b600060208284031215610d2a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112610dc357600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e0257600080fd5b83018035915067ffffffffffffffff821115610e1d57600080fd5b602001915036819003821315610a7e57600080fd5b8183823760009101908152919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112610dc357600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610dc357600080fdfea2646970667358221220bb2b5c71a328032f97c676ae39a1ec2148d3e5d6f73d95e9b17910152d61f16264736f6c634300080c0033" +) + +type CallWithValue struct { + Target common.Address + AllowFailure bool + Value *big.Int + CallData []byte +} + +type Call struct { + Target common.Address + AllowFailure bool + CallData []byte +} + +type Result struct { + Success bool + ReturnData []byte +} + +func WaitForSuccessfulTxMined(evmClient blockchain.EVMClient, tx *types.Transaction) error { + log.Debug().Str("tx", tx.Hash().Hex()).Msg("waiting for tx to be mined") + receipt, err := bind.WaitMined(context.Background(), evmClient.DeployBackend(), tx) + if err != nil { + return err + } + if receipt.Status != types.ReceiptStatusSuccessful { + return fmt.Errorf("tx failed %s", tx.Hash().Hex()) + } + log.Debug().Str("tx", tx.Hash().Hex()).Str("Network", evmClient.GetNetworkName()).Msg("tx mined successfully") + return nil +} + +func MultiCallLogTriggerLoadGen( + evmClient blockchain.EVMClient, + multiCallAddress string, + logTriggerAddress []string, + logTriggerData [][]byte, +) (*types.Transaction, error) { + + contractAddress := common.HexToAddress(multiCallAddress) + multiCallABI, err := abi.JSON(strings.NewReader(MultiCallABI)) + if err != nil { + return nil, err + } + boundContract := bind.NewBoundContract(contractAddress, multiCallABI, evmClient.Backend(), evmClient.Backend(), evmClient.Backend()) + + var call []Call + for i, d := range logTriggerData { + data := Call{Target: common.HexToAddress(logTriggerAddress[i]), AllowFailure: false, CallData: d} + call = append(call, data) + } + + opts, err := evmClient.TransactionOpts(evmClient.GetDefaultWallet()) + if err != nil { + return nil, err + } + + // call aggregate3 to group all msg call data and send them in a single transaction + tx, err := boundContract.Transact(opts, "aggregate3", call) + if err != nil { + return nil, err + } + err = evmClient.MarkTxAsSentOnL2(tx) + if err != nil { + return nil, err + } + err = WaitForSuccessfulTxMined(evmClient, tx) + if err != nil { + return nil, errors.Wrapf(err, "multicall failed for log trigger load gen; multicall %s", contractAddress.Hex()) + } + return tx, nil + +} diff --git a/integration-tests/contracts/test_contracts.go b/integration-tests/contracts/test_contracts.go index 3080668da69..8a6d0b5be02 100644 --- a/integration-tests/contracts/test_contracts.go +++ b/integration-tests/contracts/test_contracts.go @@ -55,6 +55,18 @@ func (e *LogEmitterContract) EmitLogIntsIndexed(ints []int) (*types.Transaction, return tx, e.client.ProcessTransaction(tx) } +func (e *LogEmitterContract) EmitLogIntMultiIndexed(ints int, ints2 int, count int) (*types.Transaction, error) { + opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) + if err != nil { + return nil, err + } + tx, err := e.instance.EmitLog4(opts, big.NewInt(int64(ints)), big.NewInt(int64(ints2)), big.NewInt(int64(count))) + if err != nil { + return nil, err + } + return tx, e.client.ProcessTransaction(tx) +} + func (e *LogEmitterContract) EmitLogStrings(strings []string) (*types.Transaction, error) { opts, err := e.client.TransactionOpts(e.client.GetDefaultWallet()) if err != nil { diff --git a/integration-tests/docker/test_env/cl_node.go b/integration-tests/docker/test_env/cl_node.go index 7dc077ad34b..2ffd49b8776 100644 --- a/integration-tests/docker/test_env/cl_node.go +++ b/integration-tests/docker/test_env/cl_node.go @@ -1,10 +1,14 @@ package test_env import ( + "context" "fmt" + "io" + "maps" "math/big" "net/url" "os" + "regexp" "strings" "testing" "time" @@ -13,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/pelletier/go-toml/v2" + "github.com/pkg/errors" "github.com/rs/zerolog" "github.com/rs/zerolog/log" tc "github.com/testcontainers/testcontainers-go" @@ -22,8 +27,9 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/docker" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/logwatch" + "github.com/smartcontractkit/chainlink-testing-framework/logstream" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" @@ -45,9 +51,9 @@ type ClNode struct { PostgresDb *test_env.PostgresDb `json:"postgresDb"` UserEmail string `json:"userEmail"` UserPassword string `json:"userPassword"` + AlwaysPullImage bool `json:"-"` t *testing.T l zerolog.Logger - lw *logwatch.LogWatch } type ClNodeOption = func(c *ClNode) @@ -58,6 +64,15 @@ func WithSecrets(secretsTOML string) ClNodeOption { } } +func WithNodeEnvVars(ev map[string]string) ClNodeOption { + return func(n *ClNode) { + if n.ContainerEnvs == nil { + n.ContainerEnvs = map[string]string{} + } + maps.Copy(n.ContainerEnvs, ev) + } +} + // Sets custom node container name if name is not empty func WithNodeContainerName(name string) ClNodeOption { return func(c *ClNode) { @@ -76,9 +91,31 @@ func WithDbContainerName(name string) ClNodeOption { } } -func WithLogWatch(lw *logwatch.LogWatch) ClNodeOption { +func WithLogStream(ls *logstream.LogStream) ClNodeOption { return func(c *ClNode) { - c.lw = lw + c.LogStream = ls + } +} + +func WithImage(image string) ClNodeOption { + return func(c *ClNode) { + c.ContainerImage = image + } +} + +func WithVersion(version string) ClNodeOption { + return func(c *ClNode) { + c.ContainerVersion = version + } +} + +func WithPgDBOptions(opts ...test_env.PostgresDbOption) ClNodeOption { + return func(c *ClNode) { + var err error + c.PostgresDb, err = test_env.NewPostgresDb(c.EnvComponent.Networks, opts...) + if err != nil { + c.t.Fatalf("failed to create postgres db: %v", err) + } } } @@ -102,6 +139,7 @@ func NewClNode(networks []string, imageName, imageVersion string, nodeConfig *ch PostgresDb: pgDb, l: log.Logger, } + n.SetDefaultHooks() for _, opt := range opts { opt(n) } @@ -111,7 +149,7 @@ func NewClNode(networks []string, imageName, imageVersion string, nodeConfig *ch func (n *ClNode) SetTestLogger(t *testing.T) { n.l = logging.GetTestLogger(t) n.t = t - n.PostgresDb.WithTestLogger(t) + n.PostgresDb.WithTestInstance(t) } // Restart restarts only CL node, DB container is reused @@ -125,12 +163,13 @@ func (n *ClNode) Restart(cfg *chainlink.Config) error { // UpgradeVersion restarts the cl node with new image and version func (n *ClNode) UpgradeVersion(newImage, newVersion string) error { - if newVersion == "" { - return fmt.Errorf("new version is empty") - } - if newImage == "" { - return fmt.Errorf("new image name is empty") - } + n.l.Info(). + Str("Name", n.ContainerName). + Str("Old Image", newImage). + Str("Old Version", newVersion). + Str("New Image", newImage). + Str("New Version", newVersion). + Msg("Upgrading Chainlink Node") n.ContainerImage = newImage n.ContainerVersion = newVersion return n.Restart(n.NodeConfig) @@ -285,11 +324,7 @@ func (n *ClNode) StartContainer() error { if err != nil { return fmt.Errorf("%s err: %w", ErrStartCLNodeContainer, err) } - if n.lw != nil { - if err := n.lw.ConnectContainer(testcontext.Get(n.t), container, "cl-node", true); err != nil { - return err - } - } + clEndpoint, err := test_env.GetEndpoint(testcontext.Get(n.t), container, "http") if err != nil { return err @@ -324,6 +359,28 @@ func (n *ClNode) StartContainer() error { return nil } +func (n *ClNode) ExecGetVersion() (string, error) { + cmd := []string{"chainlink", "--version"} + _, output, err := n.Container.Exec(context.Background(), cmd) + if err != nil { + return "", errors.Wrapf(err, "could not execute cmd %s", cmd) + } + outputBytes, err := io.ReadAll(output) + if err != nil { + return "", err + } + outputString := strings.TrimSpace(string(outputBytes)) + + // Find version in cmd output + re := regexp.MustCompile("@(.*)") + matches := re.FindStringSubmatch(outputString) + + if len(matches) > 1 { + return matches[1], nil + } + return "", errors.Errorf("could not find chainlink version in command output '%'", output) +} + func (n *ClNode) getContainerRequest(secrets string) ( *tc.ContainerRequest, error) { configFile, err := os.CreateTemp("", "node_config") @@ -373,9 +430,11 @@ func (n *ClNode) getContainerRequest(secrets string) ( apiCredsPath := "/home/api-credentials.txt" return &tc.ContainerRequest{ - Name: n.ContainerName, - Image: fmt.Sprintf("%s:%s", n.ContainerImage, n.ContainerVersion), - ExposedPorts: []string{"6688/tcp"}, + Name: n.ContainerName, + AlwaysPullImage: n.AlwaysPullImage, + Image: fmt.Sprintf("%s:%s", n.ContainerImage, n.ContainerVersion), + ExposedPorts: []string{"6688/tcp"}, + Env: n.ContainerEnvs, Entrypoint: []string{"chainlink", "-c", configPath, "-s", secretsPath, @@ -410,5 +469,12 @@ func (n *ClNode) getContainerRequest(secrets string) ( FileMode: 0644, }, }, + LifecycleHooks: []tc.ContainerLifecycleHooks{ + { + PostStarts: n.PostStartsHooks, + PostStops: n.PostStopsHooks, + PreTerminates: n.PreTerminatesHooks, + }, + }, }, nil } diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index 030a3ae9622..cbe2ed2d462 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -3,30 +3,27 @@ package test_env import ( "encoding/json" "fmt" - "io" "math/big" - "os" - "path/filepath" "runtime/debug" "testing" - "time" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/rs/zerolog" "github.com/rs/zerolog/log" tc "github.com/testcontainers/testcontainers-go" - "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/docker" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/logwatch" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink-testing-framework/logstream" + "github.com/smartcontractkit/chainlink-testing-framework/utils/runid" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + + core_testconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -34,9 +31,9 @@ var ( ) type CLClusterTestEnv struct { - Cfg *TestEnvConfig - Network *tc.DockerNetwork - LogWatch *logwatch.LogWatch + Cfg *TestEnvConfig + Network *tc.DockerNetwork + LogStream *logstream.LogStream /* components */ ClCluster *ClCluster @@ -57,11 +54,9 @@ func NewTestEnv() (*CLClusterTestEnv, error) { if err != nil { return nil, err } - n := []string{network.Name} return &CLClusterTestEnv{ - MockAdapter: test_env.NewKillgrave(n, ""), - Network: network, - l: log.Logger, + Network: network, + l: log.Logger, }, nil } @@ -69,15 +64,19 @@ func NewTestEnv() (*CLClusterTestEnv, error) { // Sets up private ethereum chain and MockAdapter containers with the provided cfg. func (te *CLClusterTestEnv) WithTestEnvConfig(cfg *TestEnvConfig) *CLClusterTestEnv { te.Cfg = cfg - n := []string{te.Network.Name} - te.MockAdapter = test_env.NewKillgrave(n, te.Cfg.MockAdapter.ImpostersPath, test_env.WithContainerName(te.Cfg.MockAdapter.ContainerName)) + if cfg.MockAdapter.ContainerName != "" { + n := []string{te.Network.Name} + te.MockAdapter = test_env.NewKillgrave(n, te.Cfg.MockAdapter.ImpostersPath, test_env.WithContainerName(te.Cfg.MockAdapter.ContainerName), test_env.WithLogStream(te.LogStream)) + } return te } -func (te *CLClusterTestEnv) WithTestLogger(t *testing.T) *CLClusterTestEnv { +func (te *CLClusterTestEnv) WithTestInstance(t *testing.T) *CLClusterTestEnv { te.t = t te.l = logging.GetTestLogger(t) - te.MockAdapter.WithTestLogger(t) + if te.MockAdapter != nil { + te.MockAdapter.WithTestInstance(t) + } return te } @@ -91,7 +90,7 @@ func (te *CLClusterTestEnv) WithPrivateChain(evmNetworks []blockchain.EVMNetwork n := evmNetwork pgc := test_env.NewPrivateGethChain(&n, []string{te.Network.Name}) if te.t != nil { - pgc.GetPrimaryNode().WithTestLogger(te.t) + pgc.GetPrimaryNode().WithTestInstance(te.t) } chains = append(chains, pgc) var privateChain test_env.PrivateChain @@ -151,14 +150,15 @@ func (te *CLClusterTestEnv) StartMockAdapter() error { return te.MockAdapter.StartContainer() } -func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count int, secretsConfig string, opts ...ClNodeOption) error { +// pass config here +func (te *CLClusterTestEnv) StartClCluster(nodeConfig *chainlink.Config, count int, secretsConfig string, testconfig core_testconfig.GlobalTestConfig, opts ...ClNodeOption) error { if te.Cfg != nil && te.Cfg.ClCluster != nil { te.ClCluster = te.Cfg.ClCluster } else { - opts = append(opts, WithSecrets(secretsConfig)) + opts = append(opts, WithSecrets(secretsConfig), WithLogStream(te.LogStream)) te.ClCluster = &ClCluster{} for i := 0; i < count; i++ { - ocrNode, err := NewClNode([]string{te.Network.Name}, os.Getenv("CHAINLINK_IMAGE"), os.Getenv("CHAINLINK_VERSION"), nodeConfig, opts...) + ocrNode, err := NewClNode([]string{te.Network.Name}, *testconfig.GetChainlinkImageConfig().Image, *testconfig.GetChainlinkImageConfig().Version, nodeConfig, opts...) if err != nil { return err } @@ -183,7 +183,6 @@ func (te *CLClusterTestEnv) FundChainlinkNodes(amount *big.Float) error { if err := cl.Fund(te.EVMClient, amount); err != nil { return fmt.Errorf("%s, err: %w", ErrFundCLNode, err) } - time.Sleep(5 * time.Second) } return te.EVMClient.WaitForEvents() } @@ -197,23 +196,22 @@ func (te *CLClusterTestEnv) Terminate() error { // Cleanup cleans the environment up after it's done being used, mainly for returning funds when on live networks and logs. func (te *CLClusterTestEnv) Cleanup() error { te.l.Info().Msg("Cleaning up test environment") + + runIdErr := runid.RemoveLocalRunId() + 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()) + } + if te.t == nil { return fmt.Errorf("cannot cleanup test environment without a testing.T") } + if te.ClCluster == nil || len(te.ClCluster.Nodes) == 0 { return fmt.Errorf("chainlink nodes are nil, unable cleanup chainlink nodes") } te.logWhetherAllContainersAreRunning() - // TODO: This is an imperfect and temporary solution, see TT-590 for a more sustainable solution - // Collect logs if the test fails, or if we just want them - if te.t.Failed() || os.Getenv("TEST_LOG_COLLECT") == "true" { - if err := te.collectTestLogs(); err != nil { - return err - } - } - if te.EVMClient == nil { return fmt.Errorf("evm client is nil, unable to return funds from chainlink nodes during cleanup") } else if te.EVMClient.NetworkSimulated() { @@ -237,6 +235,10 @@ func (te *CLClusterTestEnv) Cleanup() error { func (te *CLClusterTestEnv) logWhetherAllContainersAreRunning() { for _, node := range te.ClCluster.Nodes { + if node.Container == nil { + continue + } + isCLRunning := node.Container.IsRunning() isDBRunning := node.PostgresDb.Container.IsRunning() @@ -250,45 +252,6 @@ func (te *CLClusterTestEnv) logWhetherAllContainersAreRunning() { } } -// collectTestLogs collects the logs from all the Chainlink nodes in the test environment and writes them to local files -func (te *CLClusterTestEnv) collectTestLogs() error { - te.l.Info().Msg("Collecting test logs") - folder := fmt.Sprintf("./logs/%s-%s", te.t.Name(), time.Now().Format("2006-01-02T15-04-05")) - if err := os.MkdirAll(folder, os.ModePerm); err != nil { - return err - } - - eg := &errgroup.Group{} - for _, n := range te.ClCluster.Nodes { - node := n - eg.Go(func() error { - logFileName := filepath.Join(folder, fmt.Sprintf("node-%s.log", node.ContainerName)) - logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return err - } - defer logFile.Close() - logReader, err := node.Container.Logs(testcontext.Get(te.t)) - if err != nil { - return err - } - _, err = io.Copy(logFile, logReader) - if err != nil { - return err - } - te.l.Info().Str("Node", node.ContainerName).Str("File", logFileName).Msg("Wrote Logs") - return nil - }) - } - - if err := eg.Wait(); err != nil { - return err - } - - te.l.Info().Str("Logs Location", folder).Msg("Wrote test logs") - return nil -} - func (te *CLClusterTestEnv) returnFunds() error { te.l.Info().Msg("Attempting to return Chainlink node funds to default network wallets") for _, chainlinkNode := range te.ClCluster.Nodes { diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 685ea5338ae..6195ce22bca 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -13,14 +13,17 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/logwatch" + "github.com/smartcontractkit/chainlink-testing-framework/logstream" "github.com/smartcontractkit/chainlink-testing-framework/networks" + "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) type CleanUpType string @@ -32,8 +35,7 @@ const ( ) type CLTestEnvBuilder struct { - hasLogWatch bool - // hasGeth bool + hasLogStream bool hasKillgrave bool hasForwarders bool clNodeConfig *chainlink.Config @@ -52,6 +54,7 @@ type CLTestEnvBuilder struct { chainOptionsFn []ChainOption evmClientNetworkOption []EVMClientNetworkOption ethereumNetwork *test_env.EthereumNetwork + testConfig tc.GlobalTestConfig /* funding */ ETHFunds *big.Float @@ -59,7 +62,8 @@ type CLTestEnvBuilder struct { func NewCLTestEnvBuilder() *CLTestEnvBuilder { return &CLTestEnvBuilder{ - l: log.Logger, + l: log.Logger, + hasLogStream: true, } } @@ -95,14 +99,15 @@ func (b *CLTestEnvBuilder) WithTestEnv(te *CLClusterTestEnv) (*CLTestEnvBuilder, // WithTestLogger sets the test logger to use for the test. // Useful for parallel tests so the logging will be separated correctly in the results views. -func (b *CLTestEnvBuilder) WithTestLogger(t *testing.T) *CLTestEnvBuilder { +func (b *CLTestEnvBuilder) WithTestInstance(t *testing.T) *CLTestEnvBuilder { b.t = t b.l = logging.GetTestLogger(t) return b } -func (b *CLTestEnvBuilder) WithLogWatcher() *CLTestEnvBuilder { - b.hasLogWatch = true +// WithoutLogStream disables LogStream logging component +func (b *CLTestEnvBuilder) WithoutLogStream() *CLTestEnvBuilder { + b.hasLogStream = false return b } @@ -111,6 +116,11 @@ func (b *CLTestEnvBuilder) WithCLNodes(clNodesCount int) *CLTestEnvBuilder { return b } +func (b *CLTestEnvBuilder) WithTestConfig(cfg tc.GlobalTestConfig) *CLTestEnvBuilder { + b.testConfig = cfg + return b +} + func (b *CLTestEnvBuilder) WithCLNodeOptions(opt ...ClNodeOption) *CLTestEnvBuilder { b.clNodesOpts = append(b.clNodesOpts, opt...) return b @@ -211,6 +221,10 @@ func (b *CLTestEnvBuilder) EVMClientNetworkOptions(opts ...EVMClientNetworkOptio } func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { + if b.testConfig == nil { + return nil, fmt.Errorf("test config must be set") + } + if b.te == nil { var err error b, err = b.WithTestEnv(nil) @@ -221,23 +235,33 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { var err error if b.t != nil { - b.te.WithTestLogger(b.t) + b.te.WithTestInstance(b.t) } - if b.hasLogWatch { - b.te.LogWatch, err = logwatch.NewLogWatch(nil, nil) + if b.hasLogStream { + b.te.LogStream, err = logstream.NewLogStream(b.te.t, b.testConfig.GetLoggingConfig()) if err != nil { return nil, err } } if b.hasKillgrave { + if b.te.Network == nil { + return nil, fmt.Errorf("test environment builder failed: %w", fmt.Errorf("cannot start mock adapter without a network")) + } + + b.te.MockAdapter = test_env.NewKillgrave([]string{b.te.Network.Name}, "", test_env.WithLogStream(b.te.LogStream)) + err = b.te.StartMockAdapter() if err != nil { return nil, err } } + if b.t != nil { + b.te.WithTestInstance(b.t) + } + switch b.cleanUpType { case CleanUpTypeStandard: b.t.Cleanup(func() { @@ -253,6 +277,24 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return b.te, fmt.Errorf("test environment builder failed: %w", fmt.Errorf("explicit cleanup type must be set when building test environment")) } + if b.te.LogStream != nil { + b.t.Cleanup(func() { + b.l.Info().Msg("Shutting down LogStream") + logPath, err := osutil.GetAbsoluteFolderPath("logs") + if err != nil { + b.l.Info().Str("Absolute path", logPath).Msg("LogStream logs folder location") + } + + if b.t.Failed() || *b.testConfig.GetLoggingConfig().TestLogCollect { + // we can't do much if this fails, so we just log the error in logstream + _ = b.te.LogStream.FlushAndShutdown() + b.te.LogStream.PrintLogTargetsLocations() + b.te.LogStream.SaveLogLocationInTestSummary() + } + + }) + } + if b.nonDevGethNetworks != nil { b.te.WithPrivateChain(b.nonDevGethNetworks) err := b.te.StartPrivateChain() @@ -273,27 +315,26 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return nil, fmt.Errorf("cannot create nodes with custom config without nonDevNetworks") } - err = b.te.StartClCluster(b.clNodeConfig, b.clNodesCount, b.secretsConfig, b.clNodesOpts...) + err = b.te.StartClCluster(b.clNodeConfig, b.clNodesCount, b.secretsConfig, b.testConfig, b.clNodesOpts...) if err != nil { return nil, err } return b.te, nil } - networkConfig := networks.MustGetSelectedNetworksFromEnv()[0] + networkConfig := networks.MustGetSelectedNetworkConfig(b.testConfig.GetNetworkConfig())[0] var rpcProvider test_env.RpcProvider if b.ethereumNetwork != nil && networkConfig.Simulated { // TODO here we should save the ethereum network config to te.Cfg, but it doesn't exist at this point // in general it seems we have no methods for saving config to file and we only load it from file // but I don't know how that config file is to be created or whether anyone ever done that - var enCfg test_env.EthereumNetwork b.ethereumNetwork.DockerNetworkNames = []string{b.te.Network.Name} networkConfig, rpcProvider, err = b.te.StartEthereumNetwork(b.ethereumNetwork) if err != nil { return nil, err } b.te.RpcProvider = rpcProvider - b.te.PrivateEthereumConfig = &enCfg + b.te.PrivateEthereumConfig = b.ethereumNetwork } if !b.isNonEVM { @@ -357,7 +398,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } } - err := b.te.StartClCluster(cfg, b.clNodesCount, b.secretsConfig, b.clNodesOpts...) + err := b.te.StartClCluster(cfg, b.clNodesCount, b.secretsConfig, b.testConfig, b.clNodesOpts...) if err != nil { return nil, err } diff --git a/integration-tests/example.env b/integration-tests/example.env index 3e27ac2c7ab..35db6263644 100644 --- a/integration-tests/example.env +++ b/integration-tests/example.env @@ -2,11 +2,8 @@ # `source ./integration-tests/.env` ########## General Test Settings ########## -export CHAINLINK_IMAGE="public.ecr.aws/chainlink/chainlink" # Image repo to pull the Chainlink image from -export CHAINLINK_VERSION="2.4.0" # Version of the Chainlink image to pull export CHAINLINK_ENV_USER="Satoshi-Nakamoto" # Name of the person running the tests (change to your own) export TEST_LOG_LEVEL="info" # info | debug | trace -export TEST_LOG_COLLECT="false" # true | false, whether to collect the test logs after the test is complete, this will always be done if the test fails, regardless of this setting ########## Soak/Chaos/Load Test Specific Settings ########## # Remote Runner @@ -19,51 +16,7 @@ export SLACK_API_KEY="xoxb-example-key" # API key used to report soak test resul export SLACK_CHANNEL="C000000000" # Channel ID for the slack bot to post test results export SLACK_USER="U000000000" # User ID of the person running the soak tests to properly notify them -# OCR Soak Test Settings -export OCR_TEST_DURATION="15m" # For an OCRv1 soak test, how long to run the test for -export OCR_CHAINLINK_NODE_FUNDING=".01" # For an OCRv1 soak test, how much ETH to send to each node -export OCR_TIME_BETWEEN_ROUNDS="1m" # For an OCRv1 soak test, how long to wait between starting new rounds - -# Node Version Upgrade Settings -export TEST_UPGRADE_IMAGE="" # Image path to use for the node version upgrade test, likely empty -export TEST_UPGRADE_VERSION="2.0.0" # Version of the Chainlink image to upgrade to for upgrade tests. Should be newer than the current version - ########## Network Settings ########## - -# Select a pre-defined network(s) -export SELECTED_NETWORKS="SIMULATED" - -# General private values that will be retrieved when running on non-simulated networks -export EVM_URLS="wss://evm.url,wss://other.url" # Comma-sparated list of websocket URLs to use when running on live networks -export EVM_HTTP_URLS="https://evm.url,https://other.url" # Comma-sparated list of HTTP URLs to use when running on live networks -export EVM_KEYS="private,funding,keys" # Comma-separated list of private keys to use when running on live networks - -# Specific private values retrieved when running on specified chains -# Goerli -export GOERLI_URLS="wss://goerli.io/ws" -export GOERLI_HTTP_URLS="http://goerli.io/ws" -export GOERLI_KEYS="goerli,funding,keys" -# Sepolia -export SEPOLIA_URLS="wss://sepolia.io/ws" -export SEPOLIA_HTTP_URLS="http://sepolia.io/ws" -export SEPOLIA_KEYS="sepolia,funding,keys" -# Klaytn Baobab -export KLAYTN_BAOBAB_URLS="wss://klaytn.io/ws" -export KLAYTN_BAOBAB_HTTP_URLS="http://klaytn.io/ws" -export KLAYTN_BAOBAB_KEYS="klaytn,funding,keys" -# Metis Stardust -export METIS_STARDUST_URLS="wss://metis.io/ws" -export METIS_STARDUST_HTTP_URLS="http://metis.io/ws" -export METIS_STARDUST_KEYS="metis,funding,keys" -# Arbitrum Goerli -export ARBITRUM_GOERLI_URLS="wss://arbitrum.io/ws" -export ARBITRUM_GOERLI_HTTP_URLS="http://arbitrum.io/ws" -export ARBITRUM_GOERLI_KEYS="arbitrum,funding,keys" -# Optimism Goerli -export OPTIMISM_GOERLI_URLS="wss://optimism.io/ws" -export OPTIMISM_GOERLI_HTTP_URLS="http://optimism.io/ws" -export OPTIMISM_GOERLI_KEYS="optimism,funding,keys" - # General EVM Settings, used only for quick prototyping when using GENERAL as the SELECTED_NETWORK export EVM_NAME="General EVM" export EVM_CHAIN_ID="1" diff --git a/integration-tests/go.mod b/integration-tests/go.mod index f95557b2bb1..36ce802621d 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -6,44 +6,50 @@ go 1.21.4 replace github.com/smartcontractkit/chainlink/v2 => ../ require ( - cosmossdk.io/errors v1.0.0 github.com/K-Phoen/grabana v0.21.17 + github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df github.com/cli/go-gh/v2 v2.0.0 - github.com/ethereum/go-ethereum v1.12.0 + github.com/ethereum/go-ethereum v1.13.8 github.com/go-resty/resty/v2 v2.7.0 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.4.0 github.com/jmoiron/sqlx v1.3.5 - github.com/kelseyhightower/envconfig v1.4.0 github.com/lib/pq v1.10.9 github.com/manifoldco/promptui v0.9.0 github.com/onsi/gomega v1.30.0 - github.com/pelletier/go-toml/v2 v2.1.0 + github.com/pelletier/go-toml/v2 v2.1.1 + github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.30.0 github.com/scylladb/go-reflectx v1.0.1 github.com/segmentio/ksuid v1.0.4 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/chainlink-automation v1.0.1 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 - github.com/smartcontractkit/chainlink-testing-framework v1.20.0 + github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240124161023-948579cbaffa + github.com/smartcontractkit/chainlink-testing-framework v1.23.2 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 + github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 - github.com/smartcontractkit/wasp v0.3.6 + github.com/smartcontractkit/wasp v0.4.1 github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.4 + github.com/test-go/testify v1.1.4 github.com/testcontainers/testcontainers-go v0.23.0 github.com/umbracle/ethgo v0.1.3 go.dedis.ch/kyber/v3 v3.1.0 go.uber.org/ratelimit v0.2.0 go.uber.org/zap v1.26.0 golang.org/x/sync v0.5.0 + golang.org/x/text v0.14.0 gopkg.in/guregu/null.v4 v4.0.0 ) -// Pin K8s versions as their updates are highly disruptive and go mod keeps wanting to update them +// avoids ambigious imports of indirect dependencies +exclude github.com/hashicorp/consul v1.2.1 + replace ( + github.com/testcontainers/testcontainers-go => github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56 + // Pin K8s versions as their updates are highly disruptive and go mod keeps wanting to update them k8s.io/api => k8s.io/api v0.25.11 k8s.io/client-go => k8s.io/client-go v0.25.11 k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d @@ -54,6 +60,7 @@ require ( cosmossdk.io/api v0.3.1 // indirect cosmossdk.io/core v0.5.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.3 // indirect + cosmossdk.io/errors v1.0.0 // indirect cosmossdk.io/math v1.0.1 // indirect dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.0.0 // indirect @@ -71,13 +78,17 @@ require ( github.com/DataDog/zstd v1.5.2 // indirect github.com/K-Phoen/sdk v0.12.2 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect - github.com/VictoriaMetrics/fastcache v1.10.0 // indirect + github.com/Microsoft/hcsshim v0.11.1 // indirect + github.com/VictoriaMetrics/fastcache v1.12.1 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect github.com/aws/aws-sdk-go v1.45.25 // indirect github.com/aws/constructs-go/constructs/v10 v10.1.255 // indirect @@ -85,11 +96,11 @@ require ( github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 // 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/btcsuite/btcd v0.23.4 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/bytedance/sonic v1.9.1 // indirect + github.com/buger/jsonparser v1.1.1 // indirect + github.com/bytedance/sonic v1.10.1 // indirect github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b // indirect github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 // indirect github.com/cdk8s-team/cdk8s-core-go/cdk8s/v2 v2.7.5 // indirect @@ -99,17 +110,22 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cli/safeexec v1.0.0 // indirect github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect + github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect github.com/cockroachdb/redact v1.1.3 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft v0.37.2 // indirect github.com/cometbft/cometbft-db v0.7.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect - github.com/containerd/containerd v1.7.3 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect + github.com/containerd/containerd v1.7.7 // indirect + github.com/containerd/log v0.1.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect @@ -122,9 +138,10 @@ require ( github.com/cosmos/ics23/go v0.9.1-0.20221207100636-b1abd8678aab // indirect github.com/cosmos/ledger-cosmos-go v0.12.1 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect + github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/deckarep/golang-set/v2 v2.3.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/dennwc/varint v1.0.0 // indirect @@ -132,6 +149,7 @@ require ( github.com/dgraph-io/badger/v2 v2.2007.4 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect @@ -141,13 +159,14 @@ require ( github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/esote/minmaxheap v1.0.0 // indirect + github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect + github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb // indirect github.com/fatih/camelcase v1.0.0 // indirect github.com/fatih/color v1.16.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fvbommel/sortorder v1.0.2 // indirect github.com/fxamacker/cbor/v2 v2.5.0 // indirect @@ -156,15 +175,17 @@ require ( github.com/gagliardetto/solana-go v1.4.1-0.20220428092759-5250b4abbb27 // 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 github.com/getsentry/sentry-go v0.19.0 // indirect github.com/gin-contrib/sessions v0.0.5 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.9.1 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-errors/errors v1.4.2 // indirect + github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect - github.com/go-ldap/ldap/v3 v3.4.5 // indirect + github.com/go-ldap/ldap/v3 v3.4.6 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.3.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -180,28 +201,28 @@ require ( github.com/go-openapi/validate v0.22.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/go-stack/stack v1.8.1 // indirect - github.com/go-webauthn/webauthn v0.9.1 // indirect - github.com/go-webauthn/x v0.1.4 // indirect + github.com/go-playground/validator/v10 v10.15.5 // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/go-webauthn/webauthn v0.9.4 // indirect + github.com/go-webauthn/x v0.1.5 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect github.com/gogo/status v1.1.1 // indirect - github.com/golang-jwt/jwt/v5 v5.1.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect github.com/google/gnostic v0.6.9 // indirect + github.com/google/go-github/v41 v41.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-tpm v0.9.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect + github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/mux v1.8.0 // indirect @@ -211,7 +232,8 @@ require ( github.com/gosimple/slug v1.13.1 // indirect github.com/gosimple/unidecode v1.0.1 // indirect github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f // indirect - github.com/grafana/loki v1.6.2-0.20231201111602-11ef833ed3e4 // indirect + github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 // indirect + github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503 // indirect github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 // indirect github.com/grafana/pyroscope-go v1.0.4 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.4 // indirect @@ -226,8 +248,10 @@ require ( github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect github.com/hashicorp/consul/api v1.25.1 // indirect + github.com/hashicorp/consul/sdk v0.14.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-envparse v0.1.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-msgpack v0.5.5 // indirect @@ -242,17 +266,12 @@ require ( github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect - github.com/holiman/uint256 v1.2.3 // indirect + github.com/holiman/uint256 v1.2.4 // indirect github.com/huandu/skiplist v1.2.0 // indirect - github.com/huin/goupnp v1.0.3 // indirect + github.com/huandu/xstrings v1.4.0 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/ipfs/go-cid v0.0.7 // indirect - github.com/ipfs/go-datastore v0.4.5 // indirect - github.com/ipfs/go-ipfs-util v0.0.2 // indirect - github.com/ipfs/go-ipns v0.0.2 // indirect - github.com/ipfs/go-log v1.0.4 // indirect - github.com/ipfs/go-log/v2 v2.1.1 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.14.1 // indirect github.com/jackc/pgio v1.0.0 // indirect @@ -262,62 +281,24 @@ require ( github.com/jackc/pgtype v1.14.0 // indirect github.com/jackc/pgx/v4 v4.18.1 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/jbenet/goprocess v0.1.4 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/julienschmidt/httprouter v1.3.0 // indirect + github.com/kelseyhightower/envconfig v1.4.0 // indirect github.com/klauspost/compress v1.17.2 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect - github.com/koron/go-ssdp v0.0.2 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/leanovate/gopter v0.2.10-0.20210127095200-9abe2343507a // indirect github.com/leodido/go-urn v1.2.4 // indirect - github.com/libp2p/go-addr-util v0.0.2 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-conn-security-multistream v0.2.0 // indirect - github.com/libp2p/go-eventbus v0.2.1 // indirect - github.com/libp2p/go-flow-metrics v0.0.3 // indirect - github.com/libp2p/go-libp2p v0.13.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 // indirect - github.com/libp2p/go-libp2p-autonat v0.4.0 // indirect - github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect - github.com/libp2p/go-libp2p-circuit v0.4.0 // indirect - github.com/libp2p/go-libp2p-core v0.8.5 // indirect - github.com/libp2p/go-libp2p-discovery v0.5.0 // indirect - github.com/libp2p/go-libp2p-kad-dht v0.11.1 // indirect - github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect - github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect - github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect - github.com/libp2p/go-libp2p-nat v0.0.6 // indirect - github.com/libp2p/go-libp2p-noise v0.1.2 // indirect - github.com/libp2p/go-libp2p-peerstore v0.2.7 // indirect - github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect - github.com/libp2p/go-libp2p-record v0.1.3 // indirect - github.com/libp2p/go-libp2p-swarm v0.4.0 // indirect - github.com/libp2p/go-libp2p-tls v0.1.3 // indirect - github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 // indirect - github.com/libp2p/go-libp2p-yamux v0.5.1 // indirect - github.com/libp2p/go-mplex v0.3.0 // indirect - github.com/libp2p/go-msgio v0.0.6 // indirect - github.com/libp2p/go-nat v0.0.5 // indirect - github.com/libp2p/go-netroute v0.1.4 // indirect - github.com/libp2p/go-openssl v0.0.7 // indirect - github.com/libp2p/go-reuseport v0.0.2 // indirect - github.com/libp2p/go-reuseport-transport v0.0.4 // indirect - github.com/libp2p/go-sockaddr v0.1.0 // indirect - github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect - github.com/libp2p/go-tcp-transport v0.2.1 // indirect - github.com/libp2p/go-ws-transport v0.4.0 // indirect - github.com/libp2p/go-yamux/v2 v2.0.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // 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 @@ -326,13 +307,14 @@ require ( github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/miekg/dns v1.1.56 // indirect github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect - github.com/minio/sha256-simd v1.0.1 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/patternmatcher v0.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/term v0.5.0 // indirect @@ -343,16 +325,6 @@ require ( github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/mtibben/percent v0.2.1 // indirect - github.com/multiformats/go-base32 v0.0.3 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect - github.com/multiformats/go-multiaddr v0.3.3 // indirect - github.com/multiformats/go-multiaddr-dns v0.2.0 // indirect - github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multiaddr-net v0.2.0 // indirect - github.com/multiformats/go-multibase v0.0.3 // indirect - github.com/multiformats/go-multihash v0.0.14 // indirect - github.com/multiformats/go-multistream v0.2.2 // indirect - github.com/multiformats/go-varint v0.0.6 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/mwitkow/grpc-proxy v0.0.0-20230212185441-f345521cb9c9 // indirect @@ -360,7 +332,7 @@ require ( github.com/oklog/ulid v1.3.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc4 // indirect + github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/opencontainers/runc v1.1.7 // indirect github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect @@ -372,7 +344,6 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/alertmanager v0.26.0 // indirect @@ -382,7 +353,7 @@ require ( github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97 // indirect github.com/prometheus/procfs v0.12.0 // indirect - github.com/prometheus/prometheus v0.48.0 // indirect + github.com/prometheus/prometheus v0.48.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect @@ -392,27 +363,29 @@ require ( 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.10 // indirect + github.com/shirou/gopsutil/v3 v3.23.11 // 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/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect - github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect - github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect - github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect - github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect + github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 // indirect + github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect + github.com/smartcontractkit/chainlink-feeds v0.0.0-20240119021347-3c541a78cdb8 // indirect + github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba // indirect + github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect github.com/smartcontractkit/wsrpc v0.7.2 // indirect github.com/soheilhy/cmux v0.1.5 // indirect - github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect - github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/sony/gobreaker v0.5.0 // indirect github.com/spf13/afero v1.9.5 // indirect - github.com/spf13/cast v1.5.1 // 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/spf13/viper v1.15.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect github.com/stretchr/objx v0.5.0 // 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 github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect github.com/tendermint/go-amino v0.16.0 // indirect @@ -428,11 +401,9 @@ require ( github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect - github.com/ugorji/go/codec v1.2.11 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/umbracle/fastrlp v0.0.0-20220527094140-59d5dd30e722 // indirect github.com/valyala/fastjson v1.4.1 // indirect - github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect - github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xlab/treeprint v1.1.0 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect @@ -460,15 +431,15 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/goleak v1.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect + go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect golang.org/x/arch v0.6.0 // indirect - golang.org/x/crypto v0.16.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.15.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/term v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.16.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect @@ -482,8 +453,7 @@ require ( gopkg.in/guregu/null.v2 v2.1.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect - gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.28.2 // indirect @@ -498,6 +468,7 @@ require ( k8s.io/utils v0.0.0-20230711102312-30195339c3c7 // indirect nhooyr.io/websocket v1.8.7 // indirect pgregory.net/rapid v0.5.5 // indirect + rsc.io/tmplfunc v0.0.3 // indirect sigs.k8s.io/controller-runtime v0.13.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.12.1 // indirect @@ -507,10 +478,6 @@ require ( ) replace ( - // Fixes go mod tidy issue for ambiguous imports from go-ethereum - // See https://github.com/ugorji/go/issues/279 - github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.22.1 - github.com/go-kit/log => github.com/go-kit/log v0.2.1 // replicating the replace directive on cosmos SDK @@ -521,4 +488,7 @@ replace ( // until merged upstream: https://github.com/mwitkow/grpc-proxy/pull/69 github.com/mwitkow/grpc-proxy => github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f + + // type func(a Label, b Label) bool of func(a, b Label) bool {…} does not match inferred type func(a Label, b Label) int for func(a E, b E) int + github.com/prometheus/prometheus => github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510 ) diff --git a/integration-tests/go.sum b/integration-tests/go.sum index b275f6b653a..3a7652dc967 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -79,29 +79,38 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9 github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= -github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw= +github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1 h1:UPeCRD+XY7QlaGQte2EVI2iOcWvUYA2XY8w5T/8v0NQ= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4 v4.2.1/go.mod h1:oGV6NlB0cvi1ZbYRR2UN44QHxWFyGk+iylgD0qaMXjA= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork v1.1.0 h1:QM6sE5k2ZT/vI5BEe0r7mqjsUSnhVBFbOsVkEuaEfiA= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1 h1:bWh0Z2rOEDfB/ywv/l0iHN1JgyazE6kW/aIA89+CEK0= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2 v2.2.1/go.mod h1:Bzf34hhAE9NSxailk8xVeLEZbUjOXcC+GnU1mMKdhLw= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw= +github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs= +github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8= +github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= +github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= @@ -114,8 +123,8 @@ github.com/CosmWasm/wasmvm v1.2.4/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= -github.com/Depado/ginprom v1.7.11 h1:qOhxW/NJZkNkkG4TQrzAZklX8SUTjTfLA73zIUNIpww= -github.com/Depado/ginprom v1.7.11/go.mod h1:49mxL3NTQwDrhpDbY4V1mAIB3us9B+b2hP1+ph+Sla8= +github.com/Depado/ginprom v1.8.0 h1:zaaibRLNI1dMiiuj1MKzatm8qrcHzikMlCc1anqOdyo= +github.com/Depado/ginprom v1.8.0/go.mod h1:XBaKzeNBqPF4vxJpNLincSQZeMDnZp1tIbU0FU0UKgg= github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= @@ -125,29 +134,36 @@ github.com/K-Phoen/grabana v0.21.17 h1:mO/9DvJWC/qpTF/X5jQDm5eKgCBaCGypP/tEfXAvK github.com/K-Phoen/grabana v0.21.17/go.mod h1:vbASQt9UiQhX4lC3/opLpJMJ8m+hsTUU2FwkQMytHK4= github.com/K-Phoen/sdk v0.12.2 h1:0QofDlKE+lloyBOzhjEEMW21061zts/WIpfpQ5NLLAs= github.com/K-Phoen/sdk v0.12.2/go.mod h1:qmM0wO23CtoDux528MXPpYvS4XkRWkWX6rvX9Za8EVU= -github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.10.0-rc.8 h1:YSZVvlIIDD1UxQpJp0h+dnpLUw+TrY0cx8obKsp3bek= -github.com/Microsoft/hcsshim v0.10.0-rc.8/go.mod h1:OEthFdQv/AD2RAdzR6Mm1N1KPCztGKDurW1Z8b8VGMM= +github.com/Microsoft/hcsshim v0.11.1 h1:hJ3s7GbWlGK4YVV92sO88BQSyF4ZLVy7/awqOlPxFbA= +github.com/Microsoft/hcsshim v0.11.1/go.mod h1:nFJmaO4Zr5Y7eADdFOpYswDDlNVbvcIJJNJLECr5JQg= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.6 h1:U68crOE3y3MPttCMQGywZOLrTeF5HHJ3/vDBCJn9/bA= -github.com/OneOfOne/xxhash v1.2.6/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= +github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8= +github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= -github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= -github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= +github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56 h1:HItfr1XKD/4xnsJE56m3uxnkMQ9lbg8xDnkf9qoZCH0= +github.com/Tofel/testcontainers-go v0.0.0-20231130110817-e6fbf9498b56/go.mod h1:ICriE9bLX5CLxL9OFQ2N+2N+f+803LNJ1utJb1+Inx0= +github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40= +github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/Workiva/go-datastructures v1.1.0 h1:hu20UpgZneBhQ3ZvwiOGlqJSKIosin2Rd5wAKUHEO/k= +github.com/Workiva/go-datastructures v1.1.0/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= @@ -161,6 +177,11 @@ github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAu github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= +github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= +github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI= +github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo= +github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= @@ -179,6 +200,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= +github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o= github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc= github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -193,6 +216,8 @@ github.com/aws/jsii-runtime-go v1.75.0/go.mod h1:TKCyrtM0pygEPo4rDZzbMSDNCDNTSYS 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/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0= +github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df/go.mod h1:hiVxq5OP2bUGBRNS3Z/bt/reCLFNbdcST6gISi1fiOM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -203,32 +228,28 @@ github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 h1:41iFGWnSlI2gVpmOtVTJZNodLdLQLn/KsJqFvXwnd/s= github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.10.0 h1:ePXTeiPEazB5+opbv5fr8umg2R/1NlzgDsyepwsSr88= +github.com/bits-and-blooms/bitset v1.10.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.2 h1:XLMbX8JQEiwMcYft2EGi8zPUkoa0abKIU6/BJSRsjzQ= github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3 h1:SDlJ7bAm4ewvrmZtR0DaiYbQGdKPeaaIm7bM+qRhFeU= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.3/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bxcodec/faker v2.0.1+incompatible h1:P0KUpUw5w6WJXwrPfv35oc91i4d8nf40Nwln+M/+faA= github.com/bxcodec/faker v2.0.1+incompatible/go.mod h1:BNzfpVdTwnFJ6GtfYTcQu6l6rHShT+veBxNCnjCx5XM= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= +github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY= github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g= @@ -245,7 +266,6 @@ github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= @@ -253,8 +273,11 @@ github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHe github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657 h1:CyuI+igIjadM/GRnE2o0q+WCwipDh0n2cUYFPAvxziM= github.com/chaos-mesh/chaos-mesh/api/v1alpha1 v0.0.0-20220226050744-799408773657/go.mod h1:JRiumF+RFsH1mrrP8FUsi9tExPylKkO/oSRWeQEUdLE= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= @@ -285,17 +308,20 @@ github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b80 github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cockroachdb/apd/v3 v3.1.0/go.mod h1:6qgPBMXjATAdD/VefbRP9NoSLKjbB4LCoA7gN4LpHs4= -github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8= github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk= github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 h1:ytcWPaNPhNoGMWEhDvS3zToKcDpRsLuRolQJBVGdozk= -github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lgvnQ2+oGlE/EyZy4+2/CxRh9KfvCXnag1vtpxVM= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A= +github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo= github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ= github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= @@ -305,10 +331,16 @@ github.com/cometbft/cometbft-db v0.7.0 h1:uBjbrBx4QzU0zOEnU8KxoDl18dMNgDh+zZRUE0 github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= -github.com/containerd/containerd v1.7.3 h1:cKwYKkP1eTj54bP3wCdXXBymmKRQMrWjkLSWZZJDa8o= -github.com/containerd/containerd v1.7.3/go.mod h1:32FOM4/O0RkNg7AjQj3hDzN9cUGtu+HMvaKUNiqCZB8= -github.com/containerd/continuity v0.4.1 h1:wQnVrjIyQ8vhU2sgOiL5T07jo+ouqc2bnKsv5/EqGhU= -github.com/containerd/continuity v0.4.1/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/containerd/containerd v1.7.7 h1:QOC2K4A42RQpcrZyptP6z9EJZnlHfHJUfZrAAHe15q4= +github.com/containerd/containerd v1.7.7/go.mod h1:3c4XZv6VeT9qgf9GMTxNTMFxGJrGpI2vz1yk4ye+YY8= +github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM= +github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -351,6 +383,10 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 h1:d28BXYi+wUpz1KBmiF9bWrjEMacUEREV6MBi2ODnrfQ= +github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= +github.com/crate-crypto/go-kzg-4844 v0.7.0 h1:C0vgZRk4q4EZ/JgPfzuSoxdCq3C3mOZMBShovmncxvA= +github.com/crate-crypto/go-kzg-4844 v0.7.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc= github.com/creachadair/taskgroup v0.4.2 h1:jsBLdAJE42asreGss2xZGZ8fJra7WtwnHWeJFxv2Li8= github.com/creachadair/taskgroup v0.4.2/go.mod h1:qiXUOSrbwAY3u0JPGTzObbE3yf9hcXHDKBZ2ZjpCbgM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -370,16 +406,12 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g= github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= @@ -387,24 +419,21 @@ github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFM github.com/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT/t/lKtH99JQmKIb0v9WL3VaYkJ36CfHlVECI= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70 h1:CuJS05R9jmNlUK8GOxrEELPbfXm0EuGh/30LjkjN5vo= github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70/go.mod h1:EoK/8RFbMEteaCaz89uessDTnCWjbbcr+DXcBh4el5o= -github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= -github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.104.1 h1:SZNxjAsskM/su0YW9P8Wx3gU0W1Z13b6tZlYNpl5BnA= -github.com/digitalocean/godo v1.104.1/go.mod h1:VAI/L5YDzMuPRU01lEEUSQ/sp5Z//1HnnFv/RBTEdbg= +github.com/digitalocean/godo v1.99.0 h1:gUHO7n9bDaZFWvbzOum4bXE0/09ZuYA9yA8idQHX57E= +github.com/digitalocean/godo v1.99.0/go.mod h1:SsS2oXo2rznfM/nORlZ/6JaUJZFhmKTib1YhopUc8NA= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= @@ -441,8 +470,10 @@ github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7 github.com/esote/minmaxheap v1.0.0 h1:rgA7StnXXpZG6qlM0S7pUmEv1KpWe32rYT4x8J8ntaA= github.com/esote/minmaxheap v1.0.0/go.mod h1:Ln8+i7fS1k3PLgZI2JAo0iA1as95QnIYiGCrqSJ5FZk= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/go-ethereum v1.12.0 h1:bdnhLPtqETd4m3mS8BGMNvBTf36bO5bx/hxE2zljOa0= -github.com/ethereum/go-ethereum v1.12.0/go.mod h1:/oo2X/dZLJjf2mJ6YT9wcWxa4nNJDBKDBU6sFIpx1Gs= +github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= +github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= +github.com/ethereum/go-ethereum v1.13.8 h1:1od+thJel3tM52ZUNQwvpYOeRHlbkVFZ5S8fhi0Lgsg= +github.com/ethereum/go-ethereum v1.13.8/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -456,6 +487,8 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb h1:IT4JYU7k4ikYg1SCxNI1/Tieq/NFvh6dzLdgi7eu0tM= +github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= @@ -470,12 +503,10 @@ github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNpjmVH56sVtS/RfclBAYocb4as= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= @@ -499,14 +530,16 @@ github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89 github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2GihuqhwdILrV+7GJel5lyPV3u1+PgzrWLc0TkE= +github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM= github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c= github.com/getsentry/sentry-go v0.19.0 h1:BcCH3CN5tXt5aML+gwmbFwVptLLQA+eT866fCO9wVOM= github.com/getsentry/sentry-go v0.19.0/go.mod h1:y3+lGEFEFexZtpbG1GUE2WD/f9zGyKYwpEqryTOC/nE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= -github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= +github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk= +github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI= github.com/gin-contrib/expvar v0.0.1 h1:IuU5ArEgihz50vG8Onrwz22kJr7Mcvgv9xSSpfU5g+w= github.com/gin-contrib/expvar v0.0.1/go.mod h1:8o2CznfQi1JjktORdHr2/abg3wSV6OCnXh0yGypvvVw= github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE= @@ -520,8 +553,8 @@ github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/ github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= -github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= @@ -529,14 +562,16 @@ github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3Bop github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= +github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= -github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= +github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= +github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= @@ -600,24 +635,24 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= +github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-webauthn/webauthn v0.9.1 h1:KuZjvUX9JTuFjB2n7kZhM6n76BClLUFbFM8SLKnrXpo= -github.com/go-webauthn/webauthn v0.9.1/go.mod h1:m315kRGbUljOytw8b9FGWG9QzErjI5v02pNFCF3lwpI= -github.com/go-webauthn/x v0.1.4 h1:sGmIFhcY70l6k7JIDfnjVBiAAFEssga5lXIUXe0GtAs= -github.com/go-webauthn/x v0.1.4/go.mod h1:75Ug0oK6KYpANh5hDOanfDI+dvPWHk788naJVG/37H8= +github.com/go-webauthn/webauthn v0.9.4 h1:YxvHSqgUyc5AK2pZbqkWWR55qKeDPhP8zLDr6lpIc2g= +github.com/go-webauthn/webauthn v0.9.4/go.mod h1:LqupCtzSef38FcxzaklmOn7AykGKhAhr9xlRbdbgnTw= +github.com/go-webauthn/x v0.1.5 h1:V2TCzDU2TGLd0kSZOXdrqDVV5JB9ILnKxA9S53CSBw0= +github.com/go-webauthn/x v0.1.5/go.mod h1:qbzWwcFcv4rTwtCLOZd+icnr6B7oSsAGZJqlt8cukqY= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= @@ -673,8 +708,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.1.0 h1:UGKbA/IPjtS6zLcdB7i5TyACMgSbOTiR8qzXgw8HWQU= -github.com/golang-jwt/jwt/v5 v5.1.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -713,7 +748,6 @@ 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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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= @@ -744,6 +778,8 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg= +github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -753,10 +789,6 @@ github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSN github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.18/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -773,27 +805,29 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 h1:pUa4ghanp6q4IJHwE9RwLgmVFfReJN+KbQ8ExNEUUoQ= -github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= +github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= 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.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/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/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gophercloud/gophercloud v1.7.0 h1:fyJGKh0LBvIZKLvBWvQdIgkaV5yTM3Jh9EYUh+UNCAs= -github.com/gophercloud/gophercloud v1.7.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= +github.com/gophercloud/gophercloud v1.5.0 h1:cDN6XFCLKiiqvYpjQLq9AiM7RDRbIC9450WpPH+yvXo= +github.com/gophercloud/gophercloud v1.5.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -816,8 +850,10 @@ github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6 github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f h1:gyojr97YeWZ70pKNakWv5/tKwBHuLy3icnIeCo9gQr4= github.com/grafana/dskit v0.0.0-20231120170505-765e343eda4f/go.mod h1:8dsy5tQOkeNQyjXpm5mQsbCu3H5uzeBD35MzRQFznKU= -github.com/grafana/loki v1.6.2-0.20231201111602-11ef833ed3e4 h1:YbfISHhpbiDvoFNxDPCicPOU/+9s4rdv9Fq/V3iRvTo= -github.com/grafana/loki v1.6.2-0.20231201111602-11ef833ed3e4/go.mod h1:Tx2uhmS+H0pGmtqX94/KaDkRHWhIowt4iYtJLctAbEY= +github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586 h1:/of8Z8taCPftShATouOrBVy6GaTTjgQd/VfNiZp/VXQ= +github.com/grafana/gomemcache v0.0.0-20231023152154-6947259a0586/go.mod h1:PGk3RjYHpxMM8HFPhKKo+vve3DdlPUELZLSDEFehPuU= +github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503 h1:gdrsYbmk8822v6qvPwZO5DC6QjnAW7uKJ9YXnoUmV8c= +github.com/grafana/loki v1.6.2-0.20231215164305-b51b7d7b5503/go.mod h1:d8seWXCEXkL42mhuIJYcGi6DxfehzoIpLrMQWJojvOo= github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4 h1:wQ0FnSeebhJIBkgYOD06Mxk9HV2KhtEG0hp/7R+5RUQ= github.com/grafana/loki/pkg/push v0.0.0-20231201111602-11ef833ed3e4/go.mod h1:f3JSoxBTPXX5ec4FxxeC19nTBSxoTz+cBgS3cYLMcr0= github.com/grafana/pyroscope-go v1.0.4 h1:oyQX0BOkL+iARXzHuCdIF5TQ7/sRSel1YFViMHC7Bm0= @@ -853,8 +889,6 @@ github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= -github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= -github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE= github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= @@ -872,6 +906,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY= +github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc= github.com/hashicorp/go-getter v1.7.1 h1:SWiSWN/42qdpR0MdhaOc/bLR48PLuP1ZQtYLRlM69uY= github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= @@ -909,7 +945,6 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4= github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -920,8 +955,8 @@ github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR/prTM= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= -github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c h1:Nc3Mt2BAnq0/VoLEntF/nipX+K1S7pG+RgwiitSv6v0= -github.com/hashicorp/nomad/api v0.0.0-20230721134942-515895c7690c/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= +github.com/hashicorp/nomad/api v0.0.0-20230718173136-3a687930bd3e h1:sr4lujmn9heD030xx/Pd4B/JSmvRhFzuotNXaaV0WLs= +github.com/hashicorp/nomad/api v0.0.0-20230718173136-3a687930bd3e/go.mod h1:O23qLAZuCx4htdY9zBaO4cJPXgleSFEdq6D/sezGgYE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= @@ -931,24 +966,28 @@ github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7H github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/henvic/httpretty v0.0.6 h1:JdzGzKZBajBfnvlMALXXMVQWxWMF/ofTy8C3/OSUTxs= github.com/henvic/httpretty v0.0.6/go.mod h1:X38wLjWXHkXT7r2+uK8LjCMne9rsuNaBLJ+5cU2/Pmo= -github.com/hetznercloud/hcloud-go/v2 v2.4.0 h1:MqlAE+w125PLvJRCpAJmEwrIxoVdUdOyuFUhE/Ukbok= -github.com/hetznercloud/hcloud-go/v2 v2.4.0/go.mod h1:l7fA5xsncFBzQTyw29/dw5Yr88yEGKKdc6BHf24ONS0= +github.com/hetznercloud/hcloud-go/v2 v2.0.0 h1:Sg1DJ+MAKvbYAqaBaq9tPbwXBS2ckPIaMtVdUjKu+4g= +github.com/hetznercloud/hcloud-go/v2 v2.0.0/go.mod h1:4iUG2NG8b61IAwNx6UsMWQ6IfIf/i1RsG0BbsKAyR5Q= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7 h1:3JQNjnMRil1yD0IfZKHF9GxxWKDJGj8I0IqOUol//sw= +github.com/holiman/billy v0.0.0-20230718173358-1c7e68d277a7/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= -github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= +github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU= +github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw= github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= -github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= @@ -958,51 +997,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/ionos-cloud/sdk-go/v6 v6.1.9 h1:Iq3VIXzeEbc8EbButuACgfLMiY5TPVWUPNrF+Vsddo4= -github.com/ionos-cloud/sdk-go/v6 v6.1.9/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= -github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= -github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= -github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= -github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= -github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.5 h1:cwOUcGMLdLPWgu3SlrCckCMznaGADbPqE0r8h768/Dg= -github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= -github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= -github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= -github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= -github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= -github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= -github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= -github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= -github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= -github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= -github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= -github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= -github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs= -github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U= -github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= -github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= -github.com/ipfs/go-log v1.0.4 h1:6nLQdX4W8P9yZZFH7mO+X/PzjN8Laozm/lMJ6esdgzY= -github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= -github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= -github.com/ipfs/go-log/v2 v2.1.1 h1:G4TtqN+V9y9HY9TA6BwbCVyyBZ2B9MbCjR2MtGx8FR0= -github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= +github.com/ionos-cloud/sdk-go/v6 v6.1.8 h1:493wE/BkZxJf7x79UCE0cYGPZoqQcPiEBALvt7uVGY0= +github.com/ionos-cloud/sdk-go/v6 v6.1.8/go.mod h1:EzEgRIDxBELvfoa/uBN0kOQaqovLjUWEB7iW4/Q+t4k= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= @@ -1057,20 +1053,8 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= -github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= -github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= -github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= -github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= -github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= -github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= -github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= -github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= -github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= @@ -1091,7 +1075,6 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -1105,7 +1088,6 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= @@ -1117,7 +1099,6 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= @@ -1130,14 +1111,12 @@ github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.2 h1:fL3wAoyT6hXHQlORyXUW4Q23kkQpJRgEAYcZB5BR71o= -github.com/koron/go-ssdp v0.0.2/go.mod h1:XoLfkAiA2KeZsYh4DbHxD7h3nR2AZNqVQOa+LJuqPYs= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -1166,225 +1145,22 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= -github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU= -github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= -github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= -github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= -github.com/libp2p/go-conn-security-multistream v0.2.0 h1:uNiDjS58vrvJTg9jO6bySd1rMKejieG7v45ekqHbZ1M= -github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= -github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= -github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= -github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= -github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= -github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM= -github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= -github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= -github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= -github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= -github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0= -github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s= -github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324 h1:2H/P+forDWBHije1WULwPfGduByUmC4fthndHVRpYNU= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20201026210036-4f868c957324/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= -github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= -github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= -github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= -github.com/libp2p/go-libp2p-autonat v0.4.0 h1:3y8XQbpr+ssX8QfZUHekjHCYK64sj6/4hnf/awD4+Ug= -github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= -github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= -github.com/libp2p/go-libp2p-blankhost v0.2.0 h1:3EsGAi0CBGcZ33GwRuXEYJLLPoVWyXJ1bcJzAJjINkk= -github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= -github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= -github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= -github.com/libp2p/go-libp2p-circuit v0.4.0 h1:eqQ3sEYkGTtybWgr6JLqJY6QLtPWRErvFjFDfAOO1wc= -github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= -github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= -github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= -github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= -github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= -github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= -github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= -github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= -github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= -github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= -github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw= -github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= -github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= -github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= -github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ= -github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= -github.com/libp2p/go-libp2p-kad-dht v0.11.1 h1:FsriVQhOUZpCotWIjyFSjEDNJmUzuMma/RyyTDZanwc= -github.com/libp2p/go-libp2p-kad-dht v0.11.1/go.mod h1:5ojtR2acDPqh/jXf5orWy8YGb8bHQDS+qeDcoscL/PI= -github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= -github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= -github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= -github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= -github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= -github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= -github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= -github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= -github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs= -github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= -github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc= -github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= -github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= -github.com/libp2p/go-libp2p-nat v0.0.6 h1:wMWis3kYynCbHoyKLPBEMu4YRLltbm8Mk08HGSfvTkU= -github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= -github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= -github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= -github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= -github.com/libp2p/go-libp2p-noise v0.1.2 h1:IH9GRihQJTx56obm+GnpdPX4KeVIlvpXrP6xnJ0wxWk= -github.com/libp2p/go-libp2p-noise v0.1.2/go.mod h1:9B10b7ueo7TIxZHHcjcDCo5Hd6kfKT2m77by82SFRfE= -github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= -github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= -github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= -github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= -github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= -github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-peerstore v0.2.7 h1:83JoLxyR9OYTnNfB5vvFqvMUv/xDNa6NoPHnENhBsGw= -github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k= -github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= -github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= -github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= -github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= -github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= -github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= -github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= -github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= -github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= -github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= -github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= -github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= -github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= -github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA= -github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= -github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= -github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= -github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ= -github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= -github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM= -github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= -github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= -github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s= -github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= -github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= -github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= -github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= -github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= -github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= -github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= -github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0= -github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= -github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= -github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= -github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= -github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= -github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= -github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU= -github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.6 h1:lQ7Uc0kS1wb1EfRxO2Eir/RJoHkHn7t6o+EiwsYIKJA= -github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= -github.com/libp2p/go-nat v0.0.5 h1:qxnwkco8RLKqVh1NmjQ+tJ8p8khNLFxuElYG/TwqW4Q= -github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.4 h1:47V0+hJfYaqj1WO0A+cDkRc9xr9qKiK7i8zaoGv8Mmo= -github.com/libp2p/go-netroute v0.1.4/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= -github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= -github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= -github.com/libp2p/go-reuseport v0.0.2 h1:XSG94b1FJfGA01BUrT82imejHQyTxO4jEWqheyCXYvU= -github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= -github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= -github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= -github.com/libp2p/go-reuseport-transport v0.0.4 h1:OZGz0RB620QDGpv300n1zaOcKGGAoGVf8h9txtt/1uM= -github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.0 h1:Y4s3/jNoryVRKEBrkJ576F17CPOaMIzUeCsg7dlTDj0= -github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= -github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= -github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY= -github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= -github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= -github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= -github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= -github.com/libp2p/go-tcp-transport v0.2.1 h1:ExZiVQV+h+qL16fzCWtd1HSzPsqWottJ8KXwWaVi8Ns= -github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= -github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= -github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k= -github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= -github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU= -github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/linode/linodego v1.23.0 h1:s0ReCZtuN9Z1IoUN9w1RLeYO1dMZUGPwOQ/IBFsBHtU= -github.com/linode/linodego v1.23.0/go.mod h1:0U7wj/UQOqBNbKv1FYTXiBUXueR8DY4HvIotwE0ENgg= +github.com/linode/linodego v1.19.0 h1:n4WJrcr9+30e9JGZ6DI0nZbm5SdAj1kSwvvt/998YUw= +github.com/linode/linodego v1.19.0/go.mod h1:XZFR+yJ9mm2kwf6itZ6SCpu+6w3KnIevV0Uu5HNWJgQ= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= @@ -1408,7 +1184,6 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -1430,32 +1205,22 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= -github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -1475,8 +1240,14 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= -github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= -github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= +github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= +github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= @@ -1498,10 +1269,6 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P 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= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= @@ -1510,59 +1277,6 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.12.0 h1:KuQRUE3PgxRFWhq4gHvZtPSLCGDqM5q/cYr1pZ39ytc= github.com/muesli/termenv v0.12.0/go.mod h1:WCCv32tusQ/EEZ5S8oUIIrC/nIuBcxCVqlN4Xfkv+7A= -github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= -github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= -github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= -github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs= -github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA= -github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= -github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= -github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= -github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= -github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= -github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.2.0 h1:MSXRGN0mFymt6B1yo/6BPnIRpLPEnKgQNvVfCX5VDJk= -github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk= -github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= -github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= -github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= -github.com/multiformats/go-multistream v0.2.2 h1:TCYu1BHTDr1F/Qm75qwYISQdzGcRdC21nFgQW7l7GBo= -github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -1586,10 +1300,7 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -1597,11 +1308,7 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= @@ -1609,15 +1316,14 @@ github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= -github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= +github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/opencontainers/runc v1.1.7 h1:y2EZDS8sNng4Ksf0GUYNhKbTShZJPJg1FiXJNH/uoCk= github.com/opencontainers/runc v1.1.7/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e h1:4cPxUYdgaGzZIT5/j0IfqOrrXmq6bG8AwvwisMXpdrg= github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= @@ -1627,8 +1333,8 @@ github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= -github.com/ovh/go-ovh v1.4.3 h1:Gs3V823zwTFpzgGLZNI6ILS4rmxZgJwJCz54Er9LwD0= -github.com/ovh/go-ovh v1.4.3/go.mod h1:AkPXVtgwB6xlKblMjRKJJmjRp+ogrE7fz2lVgcQY8SY= +github.com/ovh/go-ovh v1.4.1 h1:VBGa5wMyQtTP7Zb+w97zRCh9sLtM/2YKRyy+MEJmWaM= +github.com/ovh/go-ovh v1.4.1/go.mod h1:6bL6pPyUT7tBfI0pqOegJgRjgjuO+mOo+MyXd1EEC0M= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -1640,13 +1346,15 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= +github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08 h1:hDSdbBuw3Lefr6R18ax0tZ2BJeNB3NehB3trOwYBsdU= github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ= +github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= @@ -1703,8 +1411,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/prometheus v0.48.0 h1:yrBloImGQ7je4h8M10ujGh4R6oxYQJQKlMuETwNskGk= -github.com/prometheus/prometheus v0.48.0/go.mod h1:SRw624aMAxTfryAcP8rOjg4S/sHHaetx2lyJJ2nM83g= +github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510 h1:6ksZ7t1hNOzGPPs8DK7SvXQf6UfWzi+W5Z7PCBl8gx4= +github.com/prometheus/prometheus v0.47.2-0.20231010075449-4b9c19fe5510/go.mod h1:UC0TwJiF90m2T3iYPQBKnGu8gv3s55dF/EgpTq8gyvo= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/pyroscope-io/client v0.7.1 h1:yFRhj3vbgjBxehvxQmedmUWJQ4CAfCHhn+itPsuWsHw= github.com/pyroscope-io/client v0.7.1/go.mod h1:4h21iOU4pUOq0prKyDlvYRL+SCKsBc5wKiEtV+rJGqU= @@ -1752,8 +1460,8 @@ github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFo github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21 h1:yWfiTPwYxB0l5fGMhl/G+liULugVIHD9AU77iNLrURQ= -github.com/scaleway/scaleway-sdk-go v1.0.0-beta.21/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.20 h1:a9hSJdJcd16e0HoMsnFvaHvxB3pxSD+SC7+CISp7xY0= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.20/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cjj1iZQ= github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= @@ -1770,9 +1478,11 @@ github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08O github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= -github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= +github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= +github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -1790,45 +1500,45 @@ github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumvbfM1u/etVq42Afwq/jtNSBSOA8n5jntnNPo= github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= -github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk= -github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4 h1:qau0/AHvPwMR3p6gWsFWC4qVfEtSEALtBetTOpHA2IU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20231201152724-d550085eb3c4/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc= -github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ= -github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE= -github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI= -github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34= -github.com/smartcontractkit/chainlink-testing-framework v1.20.0 h1:gQPQRKJuMh6QTAIMkqZ7v5WkjEmbcoMIX/V6WPVrvuI= -github.com/smartcontractkit/chainlink-testing-framework v1.20.0/go.mod h1:+FVgkz6phTc+piVT57AcQfr3I8xvZgZ1lOpRPOu/dLQ= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429 h1:xkejUBZhcBpBrTSfxc91Iwzadrb6SXw8ks69bHIQ9Ww= +github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429/go.mod h1:wJmVvDf4XSjsahWtfUq3wvIAYEAuhr7oxmxYnEL/LGQ= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240124161023-948579cbaffa h1:9g7e1C3295ALDK8Gs42fIKSSJfI+H1RoBmivGWTvIZo= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240124161023-948579cbaffa/go.mod h1:05rRF84QKlIOF5LfTBPkHdw4UpBI2G3zxRcuZ65bPjk= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0 h1:NALwENz6vQ972DuD9AZjqRjyNSxH9ptNapizQGLI+2s= +github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240120192246-4bb04c997ca0/go.mod h1:NcVAT/GETDBvIoAej5K6OYqAtDOkF6vO5pYw/hLuYVU= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ= +github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o= +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.20240122152632-38444d2ad8ba h1:6rnQrD8NaLfLOPHszW1hbpviqpU8011gzdZk6wKP1xY= +github.com/smartcontractkit/chainlink-solana v1.0.3-0.20240122152632-38444d2ad8ba/go.mod h1:OZfzyayUdwsVBqxvbEMqwUntQT8HbFbgyqoudvwfVN0= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007 h1:KwB0H2P/gxJgt823Ku1fTcFLDKMj6zsP3wbQGlBOm4U= +github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20240119162652-3a7274645007/go.mod h1:EbZAlb/2K6mKr26u3+3cLBe/caJaqCHw786On94C43g= +github.com/smartcontractkit/chainlink-testing-framework v1.23.2 h1:haXPd9Pg++Zs5/QIZnhFd9RElmz/d0+4nNeletUg9ZM= +github.com/smartcontractkit/chainlink-testing-framework v1.23.2/go.mod h1:StIOdxvwd8AMO6xuBtmD6FQfJXktEn/mJJEr7728BTc= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8= github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs= github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss= 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-20231107151413-13e0202ae8d7 h1:21V61XOYSxpFmFqlhr5IaEh1uQ1F6CewJ30D/U/P34c= -github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1 h1:3y9WsXkZ5lxFrmfH7DQHs/q308lylKId5l/3VC0QAdM= +github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1/go.mod h1:kC0qmVPUaVkFqGiZMNhmRmjdphuUmeyLEdlWFOQzFWI= 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.3.6 h1:1TLWfrTzqZwNvyyoKzPZ8FLQat2lNz640eM+mMh2YxM= -github.com/smartcontractkit/wasp v0.3.6/go.mod h1:L/cyUGfpaWxy/2twOVJLRt2mySJEIqGrFj9nyvRLpSo= +github.com/smartcontractkit/wasp v0.4.1 h1:qgIx2s+eCwH0OaBKaHEAHUQ1Z47bAgDu+ICS9IOqvGQ= +github.com/smartcontractkit/wasp v0.4.1/go.mod h1:3qiofyI3pkbrc48a3CVshbMfgl74SiuPL/tm30d9Wb4= github.com/smartcontractkit/wsrpc v0.7.2 h1:iBXzMeg7vc5YoezIQBq896y25BARw7OKbhrb6vPbtRQ= github.com/smartcontractkit/wsrpc v0.7.2/go.mod h1:sj7QX2NQibhkhxTfs3KOhAj/5xwgqMipTvJVSssT9i0= 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/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= +github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= +github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -1836,8 +1546,9 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= @@ -1854,7 +1565,6 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= 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/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= 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= @@ -1880,7 +1590,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= +github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= @@ -1892,8 +1603,6 @@ github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125 h1:3SNcvBmEPE1YlB github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= -github.com/testcontainers/testcontainers-go v0.23.0 h1:ERYTSikX01QczBLPZpqsETTBO7lInqEP349phDOVJVs= -github.com/testcontainers/testcontainers-go v0.23.0/go.mod h1:3gzuZfb7T9qfcH2pHpV4RLlWrPjeWNQah6XlYQ32c4I= github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a h1:YuO+afVc3eqrjiCUizNCxI53bl/BnPiVwXqLzqYTqgU= github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a/go.mod h1:/sfW47zCZp9FrtGcWyo1VjbgDaodxX9ovZvgLb/MxaA= github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e h1:BuzhfgfWQbX0dWzYzT1zsORLnHRv3bcRcsaUk0VmXA8= @@ -1926,8 +1635,8 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulule/limiter/v3 v3.11.2 h1:P4yOrxoEMJbOTfRJR2OzjL90oflzYPPmWg+dvwN2tHA= @@ -1940,8 +1649,8 @@ github.com/unrolled/secure v1.13.0 h1:sdr3Phw2+f8Px8HE5sd1EHdj1aV3yUwed/uZXChLFs github.com/unrolled/secure v1.13.0/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= -github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= @@ -1952,15 +1661,6 @@ github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= -github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= -github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= -github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= -github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= -github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= 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= @@ -1990,6 +1690,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE= +github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= @@ -2034,6 +1736,9 @@ go.opentelemetry.io/collector/pdata v1.0.0-rcv0016 h1:qCPXSQCoD3qeWFb1RuIks8fw9A go.opentelemetry.io/collector/pdata v1.0.0-rcv0016/go.mod h1:OdN0alYOlYhHXu6BDlGehrZWgtBuiDsz/rlNeJeXiNg= go.opentelemetry.io/collector/semconv v0.87.0 h1:BsG1jdLLRCBRlvUujk4QA86af7r/ZXnizczQpEs/gg8= go.opentelemetry.io/collector/semconv v0.87.0/go.mod h1:j/8THcqVxFna1FpvA2zYIsUperEtOaRaqoLYIN4doWw= +go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1 h1:mMv2jG58h6ZI5t5S9QCVGdzCmAsTakMa3oxVgpSD44g= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.46.1/go.mod h1:oqRuNKG0upTaDPbLVCG8AD0G2ETrfDtmh7jViy7ox6M= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= @@ -2062,7 +1767,6 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -2079,12 +1783,12 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 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.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= 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.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= +go4.org/netipx v0.0.0-20230125063823-8449b0a6169f/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc= golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= @@ -2092,29 +1796,18 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= @@ -2124,13 +1817,15 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm 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-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= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -2172,18 +1867,15 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -2213,7 +1905,6 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -2238,8 +1929,9 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su 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= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2282,18 +1974,14 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2325,7 +2013,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2361,7 +2048,6 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2372,11 +2058,12 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -2384,8 +2071,10 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2400,7 +2089,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2410,7 +2100,6 @@ golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -2438,7 +2127,6 @@ golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -2517,8 +2205,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.147.0 h1:Can3FaQo9LlVqxJCodNmeZW/ib3/qKAY3rFeXiHo5gc= -google.golang.org/api v0.147.0/go.mod h1:pQ/9j83DcmPd/5C9e2nFOdjjNkDZ1G+zkbK2uvdkJMs= +google.golang.org/api v0.149.0 h1:b2CqT6kG+zqJIVKRQ3ELJVLN1PwHZ6DJ3dW8yl82rgY= +google.golang.org/api v0.149.0/go.mod h1:Mwn1B7JTXrzXtnvmzQE2BD6bYZQ8DShKZDZbeN9I7qI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2593,7 +2281,6 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= @@ -2649,13 +2336,9 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= -gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -2708,12 +2391,15 @@ k8s.io/utils v0.0.0-20230711102312-30195339c3c7 h1:ZgnF1KZsYxWIifwSNZFZgNtWE89WI k8s.io/utils v0.0.0-20230711102312-30195339c3c7/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= pgregory.net/rapid v0.5.5 h1:jkgx1TjbQPD/feRoK+S/mXw9e1uj6WilpHrXJowi6oA= pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= +rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/controller-runtime v0.13.0 h1:iqa5RNciy7ADWnIc8QxCbOX5FEKVR3uxVxKHRMc2WIQ= sigs.k8s.io/controller-runtime v0.13.0/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/integration-tests/k8s/connect.go b/integration-tests/k8s/connect.go index 34eafc42e24..db9ccecb174 100644 --- a/integration-tests/k8s/connect.go +++ b/integration-tests/k8s/connect.go @@ -54,7 +54,7 @@ func ConnectRemote(l zerolog.Logger) (blockchain.EVMClient, *client2.MockserverC URLs: []string{cfg.NetworkWSURL}, HTTPURLs: []string{cfg.NetworkHTTPURL}, ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, + Timeout: blockchain.StrDuration{Duration: 2 * time.Minute}, MinimumConfirmations: 1, GasEstimationBuffer: 10000, } diff --git a/integration-tests/load/README.md b/integration-tests/load/README.md index 1ed1ee8b94e..3738a1d9ace 100644 --- a/integration-tests/load/README.md +++ b/integration-tests/load/README.md @@ -1,9 +1,11 @@ -## Performance tests for CL jobs +# Performance tests for CL jobs This folder container performance e2e tests for different job types, currently implemented: + - VRFv2 All the tests have 4 groups: + - one product soak - one product load - multiple product instances soak @@ -12,11 +14,13 @@ All the tests have 4 groups: When you develop an e2e performance suite for a new product you can implement the tests one by one to answer the questions: What are performance characteristics of a one instance of a product (jobs + contracts): + - is our product stable at all, no memory leaks, no flaking performance under some RPS? (test #1) - what are the limits for one product instance, figuring out the max/optimal performance params by increasing RPS and varying configuration (test #2) - update test #1 with optimal params and workload to constantly run in CI What are performance and capacity characteristics of Chainlink node(s) that run multiple products of the same type simultaneously: + - how many products of the same type we can run at once at a stable load with optimal configuration? (test #3) - what are the limits if we add more and more products of the same type, each product have a stable RPS, we vary only amount of products - update test #3 with optimal params and workload to constantly run in CI @@ -24,9 +28,9 @@ What are performance and capacity characteristics of Chainlink node(s) that run Implementing test #1 is **mandatory** for each product. Tests #2,#3,#4 are optional if you need to figure out your product scaling or node/cluster capacity. - ## Usage -``` + +```sh export LOKI_TOKEN=... export LOKI_URL=... @@ -34,10 +38,12 @@ go test -v -run TestVRFV2Load/vrfv2_soak_test ``` ### Dashboards + Each product has its own generated dashboard in `cmd/dashboard.go` Deploying dashboard: -``` + +```sh export GRAFANA_URL=... export GRAFANA_TOKEN=... export DATA_SOURCE_NAME=grafanacloud-logs @@ -56,8 +62,9 @@ If you need to assert some metrics in `Prometheus/Loki`, here is an [example](ht Do not mix workload logic with assertions, separate them. ### Implementation + To implement a standard e2e performance suite for a new product please look at `gun.go` and `vu.go`. Gun should be working with one instance of your product. -VU(Virtual user) creates a new instance of your product and works with it in `Call()` \ No newline at end of file +VU(Virtual user) creates a new instance of your product and works with it in `Call()` diff --git a/integration-tests/load/automationv2_1/automationv2_1_test.go b/integration-tests/load/automationv2_1/automationv2_1_test.go index 5fde9befba5..ffce754c9de 100644 --- a/integration-tests/load/automationv2_1/automationv2_1_test.go +++ b/integration-tests/load/automationv2_1/automationv2_1_test.go @@ -5,7 +5,6 @@ import ( "fmt" "math" "math/big" - "os" "strconv" "strings" "testing" @@ -14,6 +13,7 @@ import ( geth "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/pelletier/go-toml/v2" "github.com/slack-go/slack" "github.com/stretchr/testify/require" @@ -24,23 +24,25 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper" + ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/actions/automationv2" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" contractseth "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + aconfig "github.com/smartcontractkit/chainlink/integration-tests/testconfig/automation" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/simple_log_upkeep_counter_wrapper" ) const ( @@ -77,16 +79,16 @@ ListenAddresses = ["0.0.0.0:6690"]` minimumDbSpec = map[string]interface{}{ "resources": map[string]interface{}{ "requests": map[string]interface{}{ - "cpu": "1000m", - "memory": "1Gi", + "cpu": "4000m", + "memory": "4Gi", }, "limits": map[string]interface{}{ - "cpu": "1000m", - "memory": "1Gi", + "cpu": "4000m", + "memory": "4Gi", }, }, "stateful": true, - "capacity": "5Gi", + "capacity": "10Gi", } recNodeSpec = map[string]interface{}{ @@ -102,58 +104,65 @@ ListenAddresses = ["0.0.0.0:6690"]` }, } - recDbSpec = map[string]interface{}{ - "resources": map[string]interface{}{ - "requests": map[string]interface{}{ - "cpu": "2000m", - "memory": "2Gi", - }, - "limits": map[string]interface{}{ - "cpu": "2000m", - "memory": "2Gi", - }, + recDbSpec = minimumDbSpec + + gethNodeSpec = map[string]interface{}{ + "requests": map[string]interface{}{ + "cpu": "8000m", + "memory": "8Gi", + }, + "limits": map[string]interface{}{ + "cpu": "16000m", + "memory": "16Gi", }, - "stateful": true, - "capacity": "10Gi", } ) -var ( - numberofNodes, _ = strconv.Atoi(getEnv("NUMBEROFNODES", "6")) // Number of nodes in the DON - numberOfUpkeeps, _ = strconv.Atoi(getEnv("NUMBEROFUPKEEPS", "100")) // Number of log triggered upkeeps - duration, _ = strconv.Atoi(getEnv("DURATION", "900")) // Test duration in seconds - blockTime, _ = strconv.Atoi(getEnv("BLOCKTIME", "1")) // Block time in seconds for geth simulated dev network - numberOfEvents, _ = strconv.Atoi(getEnv("NUMBEROFEVENTS", "1")) // Number of events to emit per trigger - specType = getEnv("SPECTYPE", "minimum") // minimum, recommended, local specs for the test - logLevel = getEnv("LOGLEVEL", "info") // log level for the chainlink nodes - pyroscope, _ = strconv.ParseBool(getEnv("PYROSCOPE", "false")) // enable pyroscope for the chainlink nodes -) - func TestLogTrigger(t *testing.T) { ctx := tests.Context(t) l := logging.GetTestLogger(t) + loadedTestConfig, err := tc.GetConfig("Load", tc.Automation) + if err != nil { + t.Fatal(err) + } + + version := *loadedTestConfig.ChainlinkImage.Version + image := *loadedTestConfig.ChainlinkImage.Image + l.Info().Msg("Starting automation v2.1 log trigger load test") - l.Info().Str("TEST_INPUTS", os.Getenv("TEST_INPUTS")).Int("Number of Nodes", numberofNodes). - Int("Number of Upkeeps", numberOfUpkeeps). - Int("Duration", duration). - Int("Block Time", blockTime). - Int("Number of Events", numberOfEvents). - Str("Spec Type", specType). - Str("Log Level", logLevel). - Str("Image", os.Getenv(config.EnvVarCLImage)). - Str("Tag", os.Getenv(config.EnvVarCLTag)). + l.Info(). + Int("Number of Nodes", *loadedTestConfig.Automation.General.NumberOfNodes). + Int("Duration", *loadedTestConfig.Automation.General.Duration). + Int("Block Time", *loadedTestConfig.Automation.General.BlockTime). + Str("Spec Type", *loadedTestConfig.Automation.General.SpecType). + Str("Log Level", *loadedTestConfig.Automation.General.ChainlinkNodeLogLevel). + Str("Image", image). + Str("Tag", version). Msg("Test Config") - testConfig := fmt.Sprintf("Number of Nodes: %d\nNumber of Upkeeps: %d\nDuration: %d\nBlock Time: %d\n"+ - "Number of Events: %d\nSpec Type: %s\nLog Level: %s\nImage: %s\nTag: %s\n", numberofNodes, numberOfUpkeeps, duration, - blockTime, numberOfEvents, specType, logLevel, os.Getenv(config.EnvVarCLImage), os.Getenv(config.EnvVarCLTag)) - - testNetwork := networks.MustGetSelectedNetworksFromEnv()[0] + testConfigFormat := `Number of Nodes: %d +Duration: %d +Block Time: %d +Spec Type: %s +Log Level: %s +Image: %s +Tag: %s + +Load Config: +%s` + + prettyLoadConfig, err := toml.Marshal(loadedTestConfig.Automation.Load) + require.NoError(t, err, "Error marshalling load config") + + testConfig := fmt.Sprintf(testConfigFormat, *loadedTestConfig.Automation.General.NumberOfNodes, *loadedTestConfig.Automation.General.Duration, + *loadedTestConfig.Automation.General.BlockTime, *loadedTestConfig.Automation.General.SpecType, *loadedTestConfig.Automation.General.ChainlinkNodeLogLevel, image, version, string(prettyLoadConfig)) + l.Info().Str("testConfig", testConfig).Msg("Test Config") + + testNetwork := networks.MustGetSelectedNetworkConfig(loadedTestConfig.Network)[0] testType := "load" - loadDuration := time.Duration(duration) * time.Second + loadDuration := time.Duration(*loadedTestConfig.Automation.General.Duration) * time.Second automationDefaultLinkFunds := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(int64(10000))) //10000 LINK - automationDefaultUpkeepGasLimit := uint32(1_000_000) registrySettings := &contracts.KeeperRegistrySettings{ PaymentPremiumPPB: uint32(0), @@ -172,7 +181,7 @@ func TestLogTrigger(t *testing.T) { } testEnvironment := environment.New(&environment.Config{ - TTL: time.Hour * 24, // 1 day, + TTL: loadDuration + time.Hour*6, NamespacePrefix: fmt.Sprintf( "automation-%s-%s", testType, @@ -182,48 +191,21 @@ func TestLogTrigger(t *testing.T) { PreventPodEviction: true, }) - if testEnvironment.WillUseRemoteRunner() { - key := "TEST_INPUTS" - err := os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) - require.NoError(t, err, "failed to set the environment variable TEST_INPUTS for remote runner") - - key = config.EnvVarPyroscopeServer - err = os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) - require.NoError(t, err, "failed to set the environment variable PYROSCOPE_SERVER for remote runner") - - key = config.EnvVarPyroscopeKey - err = os.Setenv(fmt.Sprintf("TEST_%s", key), os.Getenv(key)) - require.NoError(t, err, "failed to set the environment variable PYROSCOPE_KEY for remote runner") - - key = "GRAFANA_DASHBOARD_URL" - err = os.Setenv(fmt.Sprintf("TEST_%s", key), getEnv(key, "")) - require.NoError(t, err, "failed to set the environment variable GRAFANA_DASHBOARD_URL for remote runner") - } - testEnvironment. AddHelm(ethereum.New(ðereum.Props{ NetworkName: testNetwork.Name, Simulated: testNetwork.Simulated, WsURLs: testNetwork.URLs, Values: map[string]interface{}{ - "resources": map[string]interface{}{ - "requests": map[string]interface{}{ - "cpu": "4000m", - "memory": "4Gi", - }, - "limits": map[string]interface{}{ - "cpu": "8000m", - "memory": "8Gi", - }, - }, + "resources": gethNodeSpec, "geth": map[string]interface{}{ - "blocktime": blockTime, - "capacity": "10Gi", + "blocktime": *loadedTestConfig.Automation.General.BlockTime, + "capacity": "20Gi", }, }, })) - err := testEnvironment.Run() + err = testEnvironment.Run() require.NoError(t, err, "Error launching test environment") if testEnvironment.WillUseRemoteRunner() { @@ -235,7 +217,7 @@ func TestLogTrigger(t *testing.T) { dbSpec = minimumDbSpec ) - switch specType { + switch *loadedTestConfig.Automation.General.SpecType { case "recommended": nodeSpec = recNodeSpec dbSpec = recDbSpec @@ -247,27 +229,34 @@ func TestLogTrigger(t *testing.T) { } - if !pyroscope { - err = os.Setenv(config.EnvVarPyroscopeServer, "") - require.NoError(t, err, "Error setting pyroscope server env var") + if *loadedTestConfig.Pyroscope.Enabled { + loadedTestConfig.Pyroscope.Environment = &testEnvironment.Cfg.Namespace } - err = os.Setenv(config.EnvVarPyroscopeEnvironment, testEnvironment.Cfg.Namespace) - require.NoError(t, err, "Error setting pyroscope environment env var") + numberOfUpkeeps := *loadedTestConfig.Automation.General.NumberOfNodes - for i := 0; i < numberofNodes+1; i++ { // +1 for the OCR boot node + for i := 0; i < numberOfUpkeeps+1; i++ { // +1 for the OCR boot node var nodeTOML string if i == 1 || i == 3 { - nodeTOML = fmt.Sprintf("%s\n\n[Log]\nLevel = \"%s\"", baseTOML, logLevel) + nodeTOML = fmt.Sprintf("%s\n\n[Log]\nLevel = \"%s\"", baseTOML, *loadedTestConfig.Automation.General.ChainlinkNodeLogLevel) } else { nodeTOML = fmt.Sprintf("%s\n\n[Log]\nLevel = \"info\"", baseTOML) } - nodeTOML = networks.AddNetworksConfig(nodeTOML, testNetwork) - testEnvironment.AddHelm(chainlink.New(i, map[string]any{ - "toml": nodeTOML, - "chainlink": nodeSpec, - "db": dbSpec, - })) + nodeTOML = networks.AddNetworksConfig(nodeTOML, loadedTestConfig.Pyroscope, testNetwork) + + var overrideFn = func(_ interface{}, target interface{}) { + ctfconfig.MustConfigOverrideChainlinkVersion(loadedTestConfig.ChainlinkImage, target) + ctfconfig.MightConfigOverridePyroscopeKey(loadedTestConfig.Pyroscope, target) + } + + cd := chainlink.NewWithOverride(i, map[string]any{ + "toml": nodeTOML, + "chainlink": nodeSpec, + "db": dbSpec, + "prometheus": *loadedTestConfig.Automation.General.UsePrometheus, + }, loadedTestConfig.ChainlinkImage, overrideFn) + + testEnvironment.AddHelm(cd) } err = testEnvironment.Run() @@ -284,6 +273,9 @@ func TestLogTrigger(t *testing.T) { chainClient.ParallelTransactions(true) + multicallAddress, err := contractDeployer.DeployMultiCallContract() + require.NoError(t, err, "Error deploying multicall contract") + a := automationv2.NewAutomationTestK8s(chainClient, contractDeployer, chainlinkNodes) a.RegistrySettings = *registrySettings a.RegistrarSettings = contracts.KeeperRegistrarSettings{ @@ -316,13 +308,17 @@ func TestLogTrigger(t *testing.T) { F: 1, } + startTimeTestSetup := time.Now() + l.Info().Str("START_TIME", startTimeTestSetup.String()).Msg("Test setup started") + a.SetupAutomationDeployment(t) - err = actions.FundChainlinkNodesAddress(chainlinkNodes[1:], chainClient, big.NewFloat(100), 0) + err = actions.FundChainlinkNodesAddress(chainlinkNodes[1:], chainClient, big.NewFloat(*loadedTestConfig.Common.ChainlinkNodeFunding), 0) require.NoError(t, err, "Error funding chainlink nodes") consumerContracts := make([]contracts.KeeperConsumer, 0) triggerContracts := make([]contracts.LogEmitter, 0) + triggerAddresses := make([]common.Address, 0) utilsABI, err := automation_utils_2_1.AutomationUtilsMetaData.GetAbi() require.NoError(t, err, "Error getting automation utils abi") @@ -335,43 +331,62 @@ func TestLogTrigger(t *testing.T) { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } + var bytes1 = [32]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + } + upkeepConfigs := make([]automationv2.UpkeepConfig, 0) + loadConfigs := make([]aconfig.Load, 0) + cEVMClient, err := blockchain.ConcurrentEVMClient(testNetwork, testEnvironment, chainClient, l) + require.NoError(t, err, "Error building concurrent chain client") + + for _, u := range loadedTestConfig.Automation.Load { + for i := 0; i < *u.NumberOfUpkeeps; i++ { + consumerContract, err := contractDeployer.DeployAutomationSimpleLogTriggerConsumer() + require.NoError(t, err, "Error deploying automation consumer contract") + consumerContracts = append(consumerContracts, consumerContract) + l.Debug(). + Str("Contract Address", consumerContract.Address()). + Int("Number", i+1). + Int("Out Of", *u.NumberOfUpkeeps). + Msg("Deployed Automation Log Trigger Consumer Contract") + + loadCfg := aconfig.Load{ + NumberOfEvents: u.NumberOfEvents, + NumberOfSpamMatchingEvents: u.NumberOfSpamMatchingEvents, + NumberOfSpamNonMatchingEvents: u.NumberOfSpamNonMatchingEvents, + CheckBurnAmount: u.CheckBurnAmount, + PerformBurnAmount: u.PerformBurnAmount, + UpkeepGasLimit: u.UpkeepGasLimit, + SharedTrigger: u.SharedTrigger, + } - for i := 0; i < numberOfUpkeeps; i++ { - consumerContract, err := contractDeployer.DeployAutomationSimpleLogTriggerConsumer() - require.NoError(t, err, "Error deploying automation consumer contract") - consumerContracts = append(consumerContracts, consumerContract) - l.Debug(). - Str("Contract Address", consumerContract.Address()). - Int("Number", i+1). - Int("Out Of", numberOfUpkeeps). - Msg("Deployed Automation Log Trigger Consumer Contract") - - cEVMClient, err := blockchain.ConcurrentEVMClient(testNetwork, testEnvironment, chainClient, l) - require.NoError(t, err, "Error building concurrent chain client") - - cContractDeployer, err := contracts.NewContractDeployer(cEVMClient, l) - require.NoError(t, err, "Error building concurrent contract deployer") - - triggerContract, err := cContractDeployer.DeployLogEmitterContract() - require.NoError(t, err, "Error deploying log emitter contract") - triggerContracts = append(triggerContracts, triggerContract) - l.Debug(). - Str("Contract Address", triggerContract.Address().Hex()). - Int("Number", i+1). - Int("Out Of", numberOfUpkeeps). - Msg("Deployed Automation Log Trigger Emitter Contract") - } + loadConfigs = append(loadConfigs, loadCfg) - err = chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for contracts to deploy") + if *u.SharedTrigger && i > 0 { + triggerAddresses = append(triggerAddresses, triggerAddresses[len(triggerAddresses)-1]) + continue + } + triggerContract, err := contractDeployer.DeployLogEmitterContract() + require.NoError(t, err, "Error deploying log emitter contract") + triggerContracts = append(triggerContracts, triggerContract) + triggerAddresses = append(triggerAddresses, triggerContract.Address()) + l.Debug(). + Str("Contract Address", triggerContract.Address().Hex()). + Int("Number", i+1). + Int("Out Of", *u.NumberOfUpkeeps). + Msg("Deployed Automation Log Trigger Emitter Contract") + } + err = chainClient.WaitForEvents() + require.NoError(t, err, "Failed waiting for contracts to deploy") + } for i, consumerContract := range consumerContracts { logTriggerConfigStruct := automation_utils_2_1.LogTriggerConfig{ - ContractAddress: triggerContracts[i].Address(), - FilterSelector: 0, - Topic0: emitterABI.Events["Log1"].ID, - Topic1: bytes0, + ContractAddress: triggerAddresses[i], + FilterSelector: 1, + Topic0: emitterABI.Events["Log4"].ID, + Topic1: bytes1, Topic2: bytes0, Topic3: bytes0, } @@ -379,18 +394,29 @@ func TestLogTrigger(t *testing.T) { require.NoError(t, err, "Error encoding log trigger config") l.Debug().Bytes("Encoded Log Trigger Config", encodedLogTriggerConfig).Msg("Encoded Log Trigger Config") + checkDataStruct := simple_log_upkeep_counter_wrapper.CheckData{ + CheckBurnAmount: loadConfigs[i].CheckBurnAmount, + PerformBurnAmount: loadConfigs[i].PerformBurnAmount, + EventSig: bytes1, + } + + encodedCheckDataStruct, err := consumerABI.Methods["_checkDataConfig"].Inputs.Pack(&checkDataStruct) + require.NoError(t, err, "Error encoding check data struct") + l.Debug().Bytes("Encoded Check Data Struct", encodedCheckDataStruct).Msg("Encoded Check Data Struct") + upkeepConfig := automationv2.UpkeepConfig{ UpkeepName: fmt.Sprintf("LogTriggerUpkeep-%d", i), EncryptedEmail: []byte("test@mail.com"), UpkeepContract: common.HexToAddress(consumerContract.Address()), - GasLimit: automationDefaultUpkeepGasLimit, + GasLimit: *loadConfigs[i].UpkeepGasLimit, AdminAddress: common.HexToAddress(chainClient.GetDefaultWallet().Address()), TriggerType: uint8(1), - CheckData: []byte("0"), + CheckData: encodedCheckDataStruct, TriggerConfig: encodedLogTriggerConfig, OffchainConfig: []byte("0"), FundingAmount: automationDefaultLinkFunds, } + l.Debug().Interface("Upkeep Config", upkeepConfig).Msg("Upkeep Config") upkeepConfigs = append(upkeepConfigs, upkeepConfig) } @@ -413,35 +439,58 @@ func TestLogTrigger(t *testing.T) { p := wasp.NewProfile() + configs := make([]LogTriggerConfig, 0) + var numberOfEventsEmitted int64 + var numberOfEventsEmittedPerSec int64 + for i, triggerContract := range triggerContracts { - g, err := wasp.NewGenerator(&wasp.Config{ - T: t, - LoadType: wasp.RPS, - GenName: fmt.Sprintf("log_trigger_gen_%s", triggerContract.Address().String()), - CallTimeout: time.Second * 10, - Schedule: wasp.Plain( - 1, - loadDuration, - ), - Gun: NewLogTriggerUser( - triggerContract, - consumerContracts[i], - l, - numberOfEvents, - ), - CallResultBufLen: 1000000, - }) - p.Add(g, err) + c := LogTriggerConfig{ + Address: triggerContract.Address().String(), + NumberOfEvents: int64(*loadConfigs[i].NumberOfEvents), + NumberOfSpamMatchingEvents: int64(*loadConfigs[i].NumberOfSpamMatchingEvents), + NumberOfSpamNonMatchingEvents: int64(*loadConfigs[i].NumberOfSpamNonMatchingEvents), + } + numberOfEventsEmittedPerSec = numberOfEventsEmittedPerSec + int64(*loadConfigs[i].NumberOfEvents) + configs = append(configs, c) } - l.Info().Msg("Starting load generators") - startTime := time.Now() - err = sendSlackNotification("Started", l, testEnvironment.Cfg.Namespace, strconv.Itoa(numberofNodes), - strconv.FormatInt(startTime.UnixMilli(), 10), "now", - []slack.Block{extraBlockWithText("\bTest Config\b\n```" + testConfig + "```")}) + endTimeTestSetup := time.Now() + testSetupDuration := endTimeTestSetup.Sub(startTimeTestSetup) + l.Info(). + Str("END_TIME", endTimeTestSetup.String()). + Str("Duration", testSetupDuration.String()). + Msg("Test setup ended") + + ts, err := sendSlackNotification("Started", l, &loadedTestConfig, testEnvironment.Cfg.Namespace, strconv.Itoa(*loadedTestConfig.Automation.General.NumberOfNodes), + strconv.FormatInt(startTimeTestSetup.UnixMilli(), 10), "now", + []slack.Block{extraBlockWithText("\bTest Config\b\n```" + testConfig + "```")}, slack.MsgOptionBlocks()) if err != nil { l.Error().Err(err).Msg("Error sending slack notification") } + + g, err := wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: "log_trigger_gen", + CallTimeout: time.Minute * 3, + Schedule: wasp.Plain( + 1, + loadDuration, + ), + Gun: NewLogTriggerUser( + l, + configs, + cEVMClient, + multicallAddress.Hex(), + ), + CallResultBufLen: 1000, + }) + p.Add(g, err) + + startTimeTestEx := time.Now() + l.Info().Str("START_TIME", startTimeTestEx.String()).Msg("Test execution started") + + l.Info().Msg("Starting load generators") _, err = p.Run(true) require.NoError(t, err, "Error running load generators") @@ -449,22 +498,25 @@ func TestLogTrigger(t *testing.T) { l.Info().Str("STOP_WAIT_TIME", StopWaitTime.String()).Msg("Waiting for upkeeps to be performed") time.Sleep(StopWaitTime) l.Info().Msg("Finished waiting 60s for upkeeps to be performed") - endTime := time.Now() - testDuration := endTime.Sub(startTime) - l.Info().Str("Duration", testDuration.String()).Msg("Test Duration") + endTimeTestEx := time.Now() + testExDuration := endTimeTestEx.Sub(startTimeTestEx) + l.Info(). + Str("END_TIME", endTimeTestEx.String()). + Str("Duration", testExDuration.String()). + Msg("Test execution ended") + + l.Info().Str("Duration", testExDuration.String()).Msg("Test Execution Duration") endBlock, err := chainClient.LatestBlockNumber(ctx) require.NoError(t, err, "Error getting latest block number") l.Info().Uint64("Starting Block", startBlock).Uint64("Ending Block", endBlock).Msg("Test Block Range") - upkeepDelays := make([][]int64, 0) - var numberOfEventsEmitted int - var batchSize uint64 = 500 + startTimeTestReport := time.Now() + l.Info().Str("START_TIME", startTimeTestReport.String()).Msg("Test reporting started") - for _, gen := range p.Generators { - numberOfEventsEmitted += len(gen.GetData().OKData.Data) - } - numberOfEventsEmitted = numberOfEventsEmitted * numberOfEvents - l.Info().Int("Number of Events Emitted", numberOfEventsEmitted).Msg("Number of Events Emitted") + upkeepDelaysFast := make([][]int64, 0) + upkeepDelaysRecovery := make([][]int64, 0) + + var batchSize uint64 = 500 if endBlock-startBlock < batchSize { batchSize = endBlock - startBlock @@ -500,7 +552,7 @@ func TestLogTrigger(t *testing.T) { timeout = time.Duration(math.Min(float64(timeout)*2, float64(2*time.Minute))) continue } - l.Info(). + l.Debug(). Interface("FilterQuery", filterQuery). Str("Contract Address", consumerContract.Address()). Str("Timeout", timeout.String()). @@ -510,7 +562,8 @@ func TestLogTrigger(t *testing.T) { } if len(logs) > 0 { - delay := make([]int64, 0) + delayFast := make([]int64, 0) + delayRecovery := make([]int64, 0) for _, log := range logs { eventDetails, err := consumerABI.EventByID(log.Topics[0]) require.NoError(t, err, "Error getting event details") @@ -521,51 +574,143 @@ func TestLogTrigger(t *testing.T) { if eventDetails.Name == "PerformingUpkeep" { parsedLog, err := consumer.ParsePerformingUpkeep(log) require.NoError(t, err, "Error parsing log") - delay = append(delay, parsedLog.TimeToPerform.Int64()) + if parsedLog.IsRecovered { + delayRecovery = append(delayRecovery, parsedLog.TimeToPerform.Int64()) + } else { + delayFast = append(delayFast, parsedLog.TimeToPerform.Int64()) + } } } - upkeepDelays = append(upkeepDelays, delay) + upkeepDelaysFast = append(upkeepDelaysFast, delayFast) + upkeepDelaysRecovery = append(upkeepDelaysRecovery, delayRecovery) } } - l.Info().Interface("Upkeep Delays", upkeepDelays).Msg("Upkeep Delays") + for _, triggerContract := range triggerContracts { + var ( + logs []types.Log + address = triggerContract.Address() + timeout = 5 * time.Second + ) + for fromBlock := startBlock; fromBlock < endBlock; fromBlock += batchSize + 1 { + filterQuery := geth.FilterQuery{ + Addresses: []common.Address{address}, + FromBlock: big.NewInt(0).SetUint64(fromBlock), + ToBlock: big.NewInt(0).SetUint64(fromBlock + batchSize), + Topics: [][]common.Hash{{emitterABI.Events["Log4"].ID}, {bytes1}, {bytes1}}, + } + err = fmt.Errorf("initial error") // to ensure our for loop runs at least once + for err != nil { + var ( + logsInBatch []types.Log + ) + ctx2, cancel := context.WithTimeout(ctx, timeout) + logsInBatch, err = chainClient.FilterLogs(ctx2, filterQuery) + cancel() + if err != nil { + l.Error().Err(err). + Interface("FilterQuery", filterQuery). + Str("Contract Address", triggerContract.Address().Hex()). + Str("Timeout", timeout.String()). + Msg("Error getting logs") + timeout = time.Duration(math.Min(float64(timeout)*2, float64(2*time.Minute))) + continue + } + l.Debug(). + Interface("FilterQuery", filterQuery). + Str("Contract Address", triggerContract.Address().Hex()). + Str("Timeout", timeout.String()). + Msg("Collected logs") + logs = append(logs, logsInBatch...) + } + } + numberOfEventsEmitted = numberOfEventsEmitted + int64(len(logs)) + } + + l.Info().Int64("Number of Events Emitted", numberOfEventsEmitted).Msg("Number of Events Emitted") + + l.Info(). + Interface("Upkeep Delays Fast", upkeepDelaysFast). + Interface("Upkeep Delays Recovered", upkeepDelaysRecovery). + Msg("Upkeep Delays") var allUpkeepDelays []int64 + var allUpkeepDelaysFast []int64 + var allUpkeepDelaysRecovery []int64 - for _, upkeepDelay := range upkeepDelays { + for _, upkeepDelay := range upkeepDelaysFast { allUpkeepDelays = append(allUpkeepDelays, upkeepDelay...) + allUpkeepDelaysFast = append(allUpkeepDelaysFast, upkeepDelay...) } - avg, median, ninetyPct, ninetyNinePct, maximum := testreporters.IntListStats(allUpkeepDelays) - eventsMissed := numberOfEventsEmitted - len(allUpkeepDelays) + for _, upkeepDelay := range upkeepDelaysRecovery { + allUpkeepDelays = append(allUpkeepDelays, upkeepDelay...) + allUpkeepDelaysRecovery = append(allUpkeepDelaysRecovery, upkeepDelay...) + } + + avgF, medianF, ninetyPctF, ninetyNinePctF, maximumF := testreporters.IntListStats(allUpkeepDelaysFast) + avgR, medianR, ninetyPctR, ninetyNinePctR, maximumR := testreporters.IntListStats(allUpkeepDelaysRecovery) + eventsMissed := (numberOfEventsEmitted) - int64(len(allUpkeepDelays)) percentMissed := float64(eventsMissed) / float64(numberOfEventsEmitted) * 100 l.Info(). - Float64("Average", avg).Int64("Median", median). - Int64("90th Percentile", ninetyPct).Int64("99th Percentile", ninetyNinePct). - Int64("Max", maximum).Msg("Upkeep Delays in seconds") - + Float64("Average", avgF).Int64("Median", medianF). + Int64("90th Percentile", ninetyPctF).Int64("99th Percentile", ninetyNinePctF). + Int64("Max", maximumF).Msg("Upkeep Delays Fast Execution in seconds") + l.Info(). + Float64("Average", avgR).Int64("Median", medianR). + Int64("90th Percentile", ninetyPctR).Int64("99th Percentile", ninetyNinePctR). + Int64("Max", maximumR).Msg("Upkeep Delays Recovery Execution in seconds") l.Info(). Int("Total Perform Count", len(allUpkeepDelays)). - Int("Total Events Emitted", numberOfEventsEmitted). - Int("Total Events Missed", eventsMissed). + Int("Perform Count Fast Execution", len(allUpkeepDelaysFast)). + Int("Perform Count Recovery Execution", len(allUpkeepDelaysRecovery)). + Int64("Total Events Emitted", numberOfEventsEmitted). + Int64("Total Events Missed", eventsMissed). Float64("Percent Missed", percentMissed). Msg("Test completed") - testReport := fmt.Sprintf("Upkeep Delays in seconds\nAverage: %f\nMedian: %d\n90th Percentile: %d\n"+ - "99th Percentile: %d\nMax: %d\nTotal Perform Count: %d\n\nTotal Events Emitted: %d\nTotal Events Missed: %d\n"+ - "Percent Missed: %f\nTest Duration: %s\n", - avg, median, ninetyPct, ninetyNinePct, maximum, len(allUpkeepDelays), numberOfEventsEmitted, - eventsMissed, percentMissed, testDuration.String()) + testReportFormat := `Upkeep Delays in seconds - Fast Execution +Average: %f +Median: %d +90th Percentile: %d +99th Percentile: %d +Max: %d + +Upkeep Delays in seconds - Recovery Execution +Average: %f +Median: %d +90th Percentile: %d +99th Percentile: %d +Max: %d + +Total Perform Count: %d +Perform Count Fast Execution: %d +Perform Count Recovery Execution: %d +Total Log Triggering Events Emitted: %d +Total Events Missed: %d +Percent Missed: %f +Test Duration: %s` + + endTimeTestReport := time.Now() + testReDuration := endTimeTestReport.Sub(startTimeTestReport) + l.Info(). + Str("END_TIME", endTimeTestReport.String()). + Str("Duration", testReDuration.String()). + Msg("Test reporting ended") + + testReport := fmt.Sprintf(testReportFormat, avgF, medianF, ninetyPctF, ninetyNinePctF, maximumF, + avgR, medianR, ninetyPctR, ninetyNinePctR, maximumR, len(allUpkeepDelays), len(allUpkeepDelaysFast), + len(allUpkeepDelaysRecovery), numberOfEventsEmitted, eventsMissed, percentMissed, testExDuration.String()) - err = sendSlackNotification("Finished", l, testEnvironment.Cfg.Namespace, strconv.Itoa(numberofNodes), - strconv.FormatInt(startTime.UnixMilli(), 10), strconv.FormatInt(endTime.UnixMilli(), 10), - []slack.Block{extraBlockWithText("\bTest Report\b\n```" + testReport + "```")}) + _, err = sendSlackNotification("Finished", l, &loadedTestConfig, testEnvironment.Cfg.Namespace, strconv.Itoa(*loadedTestConfig.Automation.General.NumberOfNodes), + strconv.FormatInt(startTimeTestSetup.UnixMilli(), 10), strconv.FormatInt(time.Now().UnixMilli(), 10), + []slack.Block{extraBlockWithText("\bTest Report\b\n```" + testReport + "```")}, slack.MsgOptionTS(ts)) if err != nil { l.Error().Err(err).Msg("Error sending slack notification") } t.Cleanup(func() { - if err = actions.TeardownRemoteSuite(t, testEnvironment.Cfg.Namespace, chainlinkNodes, nil, chainClient); err != nil { + if err = actions.TeardownRemoteSuite(t, testEnvironment.Cfg.Namespace, chainlinkNodes, nil, &loadedTestConfig, chainClient); err != nil { l.Error().Err(err).Msg("Error when tearing down remote suite") } }) diff --git a/integration-tests/load/automationv2_1/gun.go b/integration-tests/load/automationv2_1/gun.go index a2863a6064b..c80c9cf7cc1 100644 --- a/integration-tests/load/automationv2_1/gun.go +++ b/integration-tests/load/automationv2_1/gun.go @@ -1,43 +1,104 @@ package automationv2_1 import ( + "math/big" + "sync" + "github.com/rs/zerolog" "github.com/smartcontractkit/wasp" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) +type LogTriggerConfig struct { + Address string + NumberOfEvents int64 + NumberOfSpamMatchingEvents int64 + NumberOfSpamNonMatchingEvents int64 +} + type LogTriggerGun struct { - triggerContract contracts.LogEmitter - upkeepContract contracts.KeeperConsumer - logger zerolog.Logger - numberOfEvents int + data [][]byte + addresses []string + multiCallAddress string + evmClient blockchain.EVMClient + logger zerolog.Logger +} + +func generateCallData(int1 int64, int2 int64, count int64) []byte { + abi, err := log_emitter.LogEmitterMetaData.GetAbi() + if err != nil { + panic(err) + } + data, err := abi.Pack("EmitLog4", big.NewInt(int1), big.NewInt(int2), big.NewInt(count)) + if err != nil { + panic(err) + } + return data } func NewLogTriggerUser( - triggerContract contracts.LogEmitter, - upkeepContract contracts.KeeperConsumer, logger zerolog.Logger, - numberOfEvents int, + TriggerConfigs []LogTriggerConfig, + evmClient blockchain.EVMClient, + multicallAddress string, ) *LogTriggerGun { + var data [][]byte + var addresses []string + + for _, c := range TriggerConfigs { + if c.NumberOfEvents > 0 { + d := generateCallData(1, 1, c.NumberOfEvents) + data = append(data, d) + addresses = append(addresses, c.Address) + } + if c.NumberOfSpamMatchingEvents > 0 { + d := generateCallData(1, 2, c.NumberOfSpamMatchingEvents) + data = append(data, d) + addresses = append(addresses, c.Address) + } + if c.NumberOfSpamNonMatchingEvents > 0 { + d := generateCallData(2, 2, c.NumberOfSpamNonMatchingEvents) + data = append(data, d) + addresses = append(addresses, c.Address) + } + } + return &LogTriggerGun{ - triggerContract: triggerContract, - upkeepContract: upkeepContract, - logger: logger, - numberOfEvents: numberOfEvents, + addresses: addresses, + data: data, + logger: logger, + multiCallAddress: multicallAddress, + evmClient: evmClient, } } -func (m *LogTriggerGun) Call(_ *wasp.Generator) *wasp.CallResult { - m.logger.Debug().Str("Trigger address", m.triggerContract.Address().String()).Msg("Triggering upkeep") - payload := make([]int, 0) - for i := 0; i < m.numberOfEvents; i++ { - payload = append(payload, 1) +func (m *LogTriggerGun) Call(_ *wasp.Generator) *wasp.Response { + var wg sync.WaitGroup + var dividedData [][][]byte + d := m.data + chunkSize := 100 + for i := 0; i < len(d); i += chunkSize { + end := i + chunkSize + if end > len(d) { + end = len(d) + } + dividedData = append(dividedData, d[i:end]) } - _, err := m.triggerContract.EmitLogInts(payload) - if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + for _, a := range dividedData { + wg.Add(1) + go func(a [][]byte, m *LogTriggerGun) *wasp.Response { + defer wg.Done() + _, err := contracts.MultiCallLogTriggerLoadGen(m.evmClient, m.multiCallAddress, m.addresses, a) + if err != nil { + return &wasp.Response{Error: err.Error(), Failed: true} + } + return &wasp.Response{} + }(a, m) } - - return &wasp.CallResult{} + wg.Wait() + return &wasp.Response{} } diff --git a/integration-tests/load/automationv2_1/helpers.go b/integration-tests/load/automationv2_1/helpers.go index 3c08199a9cf..bd5bfe58667 100644 --- a/integration-tests/load/automationv2_1/helpers.go +++ b/integration-tests/load/automationv2_1/helpers.go @@ -2,47 +2,37 @@ package automationv2_1 import ( "fmt" - "os" - "strings" "github.com/rs/zerolog" "github.com/slack-go/slack" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" reportModel "github.com/smartcontractkit/chainlink-testing-framework/testreporters" - "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) -func getEnv(key, fallback string) string { - if inputs, ok := os.LookupEnv("TEST_INPUTS"); ok { - values := strings.Split(inputs, ",") - for _, value := range values { - if strings.Contains(value, key) { - return strings.Split(value, "=")[1] - } - } - } - return fallback -} - func extraBlockWithText(text string) slack.Block { return slack.NewSectionBlock(slack.NewTextBlockObject( "mrkdwn", text, false, false), nil, nil) } -func sendSlackNotification(header string, l zerolog.Logger, namespace string, numberOfNodes, - startingTime string, endingTime string, extraBlocks []slack.Block) error { +func sendSlackNotification(header string, l zerolog.Logger, config *tc.TestConfig, namespace string, numberOfNodes, + startingTime string, endingTime string, extraBlocks []slack.Block, msgOption slack.MsgOption) (string, error) { slackClient := slack.New(reportModel.SlackAPIKey) headerText := ":chainlink-keepers: Automation Load Test " + header + " :white_check_mark:" - formattedDashboardUrl := fmt.Sprintf("%s?orgId=1&from=%s&to=%s&var-namespace=%s&var-number_of_nodes=%s", testreporters.DashboardUrl, startingTime, endingTime, namespace, numberOfNodes) - l.Info().Str("Dashboard", formattedDashboardUrl).Msg("Dashboard URL") + grafanaUrl, err := config.GetGrafanaBaseURL() + if err != nil { + return "", err + } - pyroscopeServer := os.Getenv(config.EnvVarPyroscopeServer) - pyroscopeEnvironment := os.Getenv(config.EnvVarPyroscopeEnvironment) + dashboardUrl, err := config.GetGrafanaDashboardURL() + if err != nil { + return "", err + } - formattedPyroscopeUrl := fmt.Sprintf("%s/?query=chainlink-node.cpu{Environment=\"%s\"}&from=%s&to=%s", pyroscopeServer, pyroscopeEnvironment, startingTime, endingTime) + formattedDashboardUrl := fmt.Sprintf("%s%s?orgId=1&from=%s&to=%s&var-namespace=%s&var-number_of_nodes=%s", grafanaUrl, dashboardUrl, startingTime, endingTime, namespace, numberOfNodes) + l.Info().Str("Dashboard", formattedDashboardUrl).Msg("Dashboard URL") var notificationBlocks []slack.Block @@ -51,7 +41,11 @@ func sendSlackNotification(header string, l zerolog.Logger, namespace string, nu notificationBlocks = append(notificationBlocks, slack.NewContextBlock("context_block", slack.NewTextBlockObject("plain_text", namespace, false, false))) notificationBlocks = append(notificationBlocks, slack.NewDividerBlock()) - if pyroscopeServer != "" { + if *config.Pyroscope.Enabled { + pyroscopeServer := *config.Pyroscope.ServerUrl + pyroscopeEnvironment := *config.Pyroscope.Environment + + formattedPyroscopeUrl := fmt.Sprintf("%s/?query=chainlink-node.cpu{Environment=\"%s\"}&from=%s&to=%s", pyroscopeServer, pyroscopeEnvironment, startingTime, endingTime) l.Info().Str("Pyroscope", formattedPyroscopeUrl).Msg("Dashboard URL") notificationBlocks = append(notificationBlocks, slack.NewSectionBlock(slack.NewTextBlockObject("mrkdwn", fmt.Sprintf("<%s|Pyroscope>", @@ -65,7 +59,7 @@ func sendSlackNotification(header string, l zerolog.Logger, namespace string, nu notificationBlocks = append(notificationBlocks, extraBlocks...) } - ts, err := reportModel.SendSlackMessage(slackClient, slack.MsgOptionBlocks(notificationBlocks...)) + ts, err := reportModel.SendSlackMessage(slackClient, slack.MsgOptionBlocks(notificationBlocks...), msgOption) l.Info().Str("ts", ts).Msg("Sent Slack Message") - return err + return ts, err } diff --git a/integration-tests/load/functions/config.go b/integration-tests/load/functions/config.go deleted file mode 100644 index ad7e7446afb..00000000000 --- a/integration-tests/load/functions/config.go +++ /dev/null @@ -1,125 +0,0 @@ -package loadfunctions - -import ( - "fmt" - "math/big" - "os" - - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - "github.com/smartcontractkit/chainlink/v2/core/store/models" -) - -const ( - DefaultConfigFilename = "config.toml" - - ErrReadPerfConfig = "failed to read TOML config for performance tests" - ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" -) - -type PerformanceConfig struct { - Soak *Soak `toml:"Soak"` - SecretsSoak *SecretsSoak `toml:"SecretsSoak"` - RealSoak *RealSoak `toml:"RealSoak"` - Stress *Stress `toml:"Stress"` - SecretsStress *SecretsStress `toml:"SecretsStress"` - RealStress *RealStress `toml:"RealStress"` - GatewayListSoak *GatewayListSoak `toml:"GatewayListSoak"` - GatewaySetSoak *GatewaySetSoak `toml:"GatewaySetSoak"` - Common *Common `toml:"Common"` - MumbaiPrivateKey string -} - -type Common struct { - Funding - LINKTokenAddr string `toml:"link_token_addr"` - Coordinator string `toml:"coordinator_addr"` - Router string `toml:"router_addr"` - LoadTestClient string `toml:"client_addr"` - SubscriptionID uint64 `toml:"subscription_id"` - DONID string `toml:"don_id"` - GatewayURL string `toml:"gateway_url"` - Receiver string `toml:"receiver"` - FunctionsCallPayloadHTTP string `toml:"functions_call_payload_http"` - FunctionsCallPayloadWithSecrets string `toml:"functions_call_payload_with_secrets"` - FunctionsCallPayloadReal string `toml:"functions_call_payload_real"` - SecretsSlotID uint8 `toml:"secrets_slot_id"` - SecretsVersionID uint64 `toml:"secrets_version_id"` - // Secrets these are for CI secrets - Secrets string `toml:"secrets"` -} - -type Funding struct { - NodeFunds *big.Float `toml:"node_funds"` - SubFunds *big.Int `toml:"sub_funds"` -} - -type Soak struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` -} - -type SecretsSoak struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` -} - -type RealSoak struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` -} - -type Stress struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` -} - -type SecretsStress struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` -} - -type RealStress struct { - RPS int64 `toml:"rps"` - RequestsPerCall uint32 `toml:"requests_per_call"` - Duration *models.Duration `toml:"duration"` -} - -type GatewayListSoak struct { - RPS int64 `toml:"rps"` - Duration *models.Duration `toml:"duration"` -} - -type GatewaySetSoak struct { - RPS int64 `toml:"rps"` - Duration *models.Duration `toml:"duration"` -} - -func ReadConfig() (*PerformanceConfig, error) { - var cfg *PerformanceConfig - d, err := os.ReadFile(DefaultConfigFilename) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) - } - log.Debug().Interface("PerformanceConfig", cfg).Msg("Parsed performance config") - mpk := os.Getenv("MUMBAI_KEYS") - murls := os.Getenv("MUMBAI_URLS") - snet := os.Getenv("SELECTED_NETWORKS") - if mpk == "" || murls == "" || snet == "" { - return nil, fmt.Errorf( - "ensure variables are set:\nMUMBAI_KEYS variable, private keys, comma separated\nSELECTED_NETWORKS=MUMBAI\nMUMBAI_URLS variable, websocket urls, comma separated", - ) - } - cfg.MumbaiPrivateKey = mpk - return cfg, nil -} diff --git a/integration-tests/load/functions/functions_test.go b/integration-tests/load/functions/functions_test.go index dc52846d3c9..d3b82cde33b 100644 --- a/integration-tests/load/functions/functions_test.go +++ b/integration-tests/load/functions/functions_test.go @@ -6,12 +6,15 @@ import ( "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestFunctionsLoad(t *testing.T) { - cfg, err := ReadConfig() - require.NoError(t, err) - ft, err := SetupLocalLoadTestEnv(cfg) + generalConfig, err := tc.GetConfig(tc.NoKey, tc.Functions) + require.NoError(t, err, "failed to get config") + + ft, err := SetupLocalLoadTestEnv(&generalConfig, &generalConfig) require.NoError(t, err) ft.EVMClient.ParallelTransactions(false) @@ -20,10 +23,14 @@ func TestFunctionsLoad(t *testing.T) { "commit": "functions_healthcheck", } - MonitorLoadStats(t, ft, labels) + MonitorLoadStats(t, ft, labels, &generalConfig) t.Run("mumbai functions soak test http", func(t *testing.T) { - _, err := wasp.NewProfile(). + config, err := tc.GetConfig("Soak", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki + _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, LoadType: wasp.RPS, @@ -31,28 +38,32 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.Soak.RPS, - cfg.Soak.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeHTTPPayload, - cfg.Soak.RequestsPerCall, - cfg.Common.FunctionsCallPayloadHTTP, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadHTTP, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) }) t.Run("mumbai functions stress test http", func(t *testing.T) { + config, err := tc.GetConfig("Stress", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -61,29 +72,33 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.Stress.RPS, - cfg.Stress.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeHTTPPayload, - cfg.Stress.RequestsPerCall, - cfg.Common.FunctionsCallPayloadHTTP, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadHTTP, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) }) t.Run("mumbai functions soak test only secrets", func(t *testing.T) { - _, err := wasp.NewProfile(). + config, err := tc.GetConfig("SecretsSoak", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki + _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, LoadType: wasp.RPS, @@ -91,28 +106,32 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.SecretsSoak.RPS, - cfg.SecretsSoak.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeSecretsOnlyPayload, - cfg.SecretsSoak.RequestsPerCall, - cfg.Common.FunctionsCallPayloadWithSecrets, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadWithSecrets, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) }) t.Run("mumbai functions stress test only secrets", func(t *testing.T) { + config, err := tc.GetConfig("SecretsStress", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -121,29 +140,33 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.SecretsStress.RPS, - cfg.SecretsStress.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeSecretsOnlyPayload, - cfg.SecretsStress.RequestsPerCall, - cfg.Common.FunctionsCallPayloadWithSecrets, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadWithSecrets, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) }) t.Run("mumbai functions soak test real", func(t *testing.T) { - _, err := wasp.NewProfile(). + config, err := tc.GetConfig("RealSoak", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki + _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, LoadType: wasp.RPS, @@ -151,28 +174,32 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.RealSoak.RPS, - cfg.RealSoak.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeReal, - cfg.RealSoak.RequestsPerCall, - cfg.Common.FunctionsCallPayloadReal, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadReal, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{"1", "2", "3", "4"}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) }) t.Run("mumbai functions stress test real", func(t *testing.T) { + config, err := tc.GetConfig("RealStress", tc.Functions) + require.NoError(t, err, "failed to get config") + cfg := config.Functions + cfgl := config.Logging.Loki _, err = wasp.NewProfile(). Add(wasp.NewGenerator(&wasp.Config{ T: t, @@ -181,22 +208,22 @@ func TestFunctionsLoad(t *testing.T) { RateLimitUnitDuration: 5 * time.Second, CallTimeout: 3 * time.Minute, Schedule: wasp.Plain( - cfg.RealStress.RPS, - cfg.RealStress.Duration.Duration(), + *cfg.Performance.RPS, + cfg.Performance.Duration.Duration, ), Gun: NewSingleFunctionCallGun( ft, ModeReal, - cfg.RealStress.RequestsPerCall, - cfg.Common.FunctionsCallPayloadReal, - cfg.Common.SecretsSlotID, - cfg.Common.SecretsVersionID, + *cfg.Performance.RequestsPerCall, + *cfg.Common.FunctionsCallPayloadReal, + *cfg.Common.SecretsSlotID, + *cfg.Common.SecretsVersionID, []string{"1", "2", "3", "4"}, - cfg.Common.SubscriptionID, - StringToByte32(cfg.Common.DONID), + *cfg.Common.SubscriptionID, + StringToByte32(*cfg.Common.DONID), ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })). Run(true) require.NoError(t, err) diff --git a/integration-tests/load/functions/gateway_gun.go b/integration-tests/load/functions/gateway_gun.go index 3dafb458a50..cc6132e94e7 100644 --- a/integration-tests/load/functions/gateway_gun.go +++ b/integration-tests/load/functions/gateway_gun.go @@ -4,7 +4,6 @@ import ( "crypto/ecdsa" "fmt" "math/rand" - "os" "strconv" "time" @@ -12,12 +11,14 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy" "github.com/smartcontractkit/wasp" + + "github.com/smartcontractkit/chainlink/integration-tests/types" ) /* SingleFunctionCallGun is a gun that constantly requests randomness for one feed */ type GatewaySecretsSetGun struct { - Cfg *PerformanceConfig + Cfg types.FunctionsTestConfig Resty *resty.Client SlotID uint Method string @@ -26,7 +27,7 @@ type GatewaySecretsSetGun struct { DONPublicKey []byte } -func NewGatewaySecretsSetGun(cfg *PerformanceConfig, method string, pKey *ecdsa.PrivateKey, tdh2PubKey *tdh2easy.PublicKey, donPubKey []byte) *GatewaySecretsSetGun { +func NewGatewaySecretsSetGun(cfg types.FunctionsTestConfig, method string, pKey *ecdsa.PrivateKey, tdh2PubKey *tdh2easy.PublicKey, donPubKey []byte) *GatewaySecretsSetGun { return &GatewaySecretsSetGun{ Cfg: cfg, Resty: resty.New(), @@ -37,7 +38,7 @@ func NewGatewaySecretsSetGun(cfg *PerformanceConfig, method string, pKey *ecdsa. } } -func callSecretsSet(m *GatewaySecretsSetGun) *wasp.CallResult { +func callSecretsSet(m *GatewaySecretsSetGun) *wasp.Response { randNum := strconv.Itoa(rand.Intn(100000)) randSlot := uint(rand.Intn(5)) version := uint64(time.Now().UnixNano()) @@ -57,49 +58,60 @@ func callSecretsSet(m *GatewaySecretsSetGun) *wasp.CallResult { secret, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} + } + network := m.Cfg.GetNetworkConfig().SelectedNetworks[0] + if len(m.Cfg.GetNetworkConfig().WalletKeys[network]) < 1 { + panic(fmt.Sprintf("no wallet keys found for %s", network)) } + + cfg := m.Cfg.GetFunctionsConfig() _, _, err = UploadS4Secrets(m.Resty, &S4SecretsCfg{ - GatewayURL: m.Cfg.Common.GatewayURL, - PrivateKey: os.Getenv("MUMBAI_KEYS"), + GatewayURL: *cfg.Common.GatewayURL, + PrivateKey: m.Cfg.GetNetworkConfig().WalletKeys[network][0], MessageID: randNum, Method: "secrets_set", - DonID: m.Cfg.Common.DONID, + DonID: *cfg.Common.DONID, S4SetSlotID: randSlot, S4SetVersion: version, S4SetExpirationPeriod: expiration, S4SetPayload: secrets, }) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } -func callSecretsList(m *GatewaySecretsSetGun) *wasp.CallResult { +func callSecretsList(m *GatewaySecretsSetGun) *wasp.Response { randNum := strconv.Itoa(rand.Intn(100000)) randSlot := uint(rand.Intn(5)) version := uint64(time.Now().UnixNano()) expiration := int64(60 * 60 * 1000) + network := m.Cfg.GetNetworkConfig().SelectedNetworks[0] + if len(m.Cfg.GetNetworkConfig().WalletKeys[network]) < 1 { + panic(fmt.Sprintf("no wallet keys found for %s", network)) + } + cfg := m.Cfg.GetFunctionsConfig() if err := ListS4Secrets(m.Resty, &S4SecretsCfg{ - GatewayURL: fmt.Sprintf(m.Cfg.Common.GatewayURL), - RecieverAddr: m.Cfg.Common.Receiver, - PrivateKey: os.Getenv("MUMBAI_KEYS"), + GatewayURL: *cfg.Common.GatewayURL, + RecieverAddr: *cfg.Common.Receiver, + PrivateKey: m.Cfg.GetNetworkConfig().WalletKeys[network][0], MessageID: randNum, Method: m.Method, - DonID: m.Cfg.Common.DONID, + DonID: *cfg.Common.DONID, S4SetSlotID: randSlot, S4SetVersion: version, S4SetExpirationPeriod: expiration, }); err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } // Call implements example gun call, assertions on response bodies should be done here -func (m *GatewaySecretsSetGun) Call(_ *wasp.Generator) *wasp.CallResult { - var res *wasp.CallResult +func (m *GatewaySecretsSetGun) Call(_ *wasp.Generator) *wasp.Response { + var res *wasp.Response switch m.Method { case "secrets_set": res = callSecretsSet(m) diff --git a/integration-tests/load/functions/gateway_test.go b/integration-tests/load/functions/gateway_test.go index c8e63f92f2b..be5d148386c 100644 --- a/integration-tests/load/functions/gateway_test.go +++ b/integration-tests/load/functions/gateway_test.go @@ -6,13 +6,17 @@ import ( "github.com/smartcontractkit/wasp" "github.com/stretchr/testify/require" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions" ) func TestGatewayLoad(t *testing.T) { - cfg, err := ReadConfig() + listConfig, err := tc.GetConfig("GatewayList", tc.Functions) require.NoError(t, err) - ft, err := SetupLocalLoadTestEnv(cfg) + cfgl := listConfig.Logging.Loki + + require.NoError(t, err) + ft, err := SetupLocalLoadTestEnv(&listConfig, &listConfig) require.NoError(t, err) ft.EVMClient.ParallelTransactions(false) @@ -25,36 +29,39 @@ func TestGatewayLoad(t *testing.T) { LoadType: wasp.RPS, GenName: functions.MethodSecretsList, Schedule: wasp.Plain( - cfg.GatewayListSoak.RPS, - cfg.GatewayListSoak.Duration.Duration(), + *listConfig.Functions.Performance.RPS, + listConfig.Functions.Performance.Duration.Duration, ), Gun: NewGatewaySecretsSetGun( - cfg, + &listConfig, functions.MethodSecretsList, ft.EthereumPrivateKey, ft.ThresholdPublicKey, ft.DONPublicKey, ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), } + setConfig, err := tc.GetConfig("GatewaySet", tc.Functions) + require.NoError(t, err) + secretsSetCfg := &wasp.Config{ LoadType: wasp.RPS, GenName: functions.MethodSecretsSet, Schedule: wasp.Plain( - cfg.GatewaySetSoak.RPS, - cfg.GatewaySetSoak.Duration.Duration(), + *setConfig.Functions.Performance.RPS, + setConfig.Functions.Performance.Duration.Duration, ), Gun: NewGatewaySecretsSetGun( - cfg, + &setConfig, functions.MethodSecretsSet, ft.EthereumPrivateKey, ft.ThresholdPublicKey, ft.DONPublicKey, ), Labels: labels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), } t.Run("gateway secrets list soak test", func(t *testing.T) { diff --git a/integration-tests/load/functions/onchain_monitoring.go b/integration-tests/load/functions/onchain_monitoring.go index c4b4bdb78c0..12a10ce0042 100644 --- a/integration-tests/load/functions/onchain_monitoring.go +++ b/integration-tests/load/functions/onchain_monitoring.go @@ -6,6 +6,8 @@ import ( "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) /* Monitors on-chain stats of LoadConsumer and pushes them to Loki every second */ @@ -23,7 +25,7 @@ type LoadStats struct { Empty uint32 } -func MonitorLoadStats(t *testing.T, ft *FunctionsTest, labels map[string]string) { +func MonitorLoadStats(t *testing.T, ft *FunctionsTest, labels map[string]string, config tc.GlobalTestConfig) { go func() { updatedLabels := make(map[string]string) for k, v := range labels { @@ -32,7 +34,9 @@ func MonitorLoadStats(t *testing.T, ft *FunctionsTest, labels map[string]string) updatedLabels["type"] = LokiTypeLabel updatedLabels["go_test_name"] = t.Name() updatedLabels["gen_name"] = "performance" - lc, err := wasp.NewLokiClient(wasp.NewEnvLokiConfig()) + cfgl := config.GetLoggingConfig().Loki + lokiConfig := wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken) + lc, err := wasp.NewLokiClient(lokiConfig) if err != nil { log.Error().Err(err).Msg(ErrLokiClient) return @@ -46,16 +50,20 @@ func MonitorLoadStats(t *testing.T, ft *FunctionsTest, labels map[string]string) if err != nil { log.Error().Err(err).Msg(ErrMetrics) } - log.Info(). - Hex("LastReqID", []byte(stats.LastRequestID)). - Str("LastResponse", stats.LastResponse). - Str("LastError", stats.LastError). - Uint32("Total", stats.Total). - Uint32("Succeeded", stats.Succeeded). - Uint32("Errored", stats.Errored). - Uint32("Empty", stats.Empty).Msg("On-chain stats for load test client") - if err := lc.HandleStruct(wasp.LabelsMapToModel(updatedLabels), time.Now(), stats); err != nil { - log.Error().Err(err).Msg(ErrLokiPush) + if stats != nil { + log.Info(). + Hex("LastReqID", []byte(stats.LastRequestID)). + Str("LastResponse", stats.LastResponse). + Str("LastError", stats.LastError). + Uint32("Total", stats.Total). + Uint32("Succeeded", stats.Succeeded). + Uint32("Errored", stats.Errored). + Uint32("Empty", stats.Empty).Msg("On-chain stats for load test client") + if err := lc.HandleStruct(wasp.LabelsMapToModel(updatedLabels), time.Now(), stats); err != nil { + log.Error().Err(err).Msg(ErrLokiPush) + } + } else { + log.Warn().Msg("No stats to push to Loki") } } }() diff --git a/integration-tests/load/functions/request_gun.go b/integration-tests/load/functions/request_gun.go index bd4cf5f35aa..6b79a2f19ee 100644 --- a/integration-tests/load/functions/request_gun.go +++ b/integration-tests/load/functions/request_gun.go @@ -48,7 +48,7 @@ func NewSingleFunctionCallGun( } } -func (m *SingleFunctionCallGun) callReal() *wasp.CallResult { +func (m *SingleFunctionCallGun) callReal() *wasp.Response { err := m.ft.LoadTestClient.SendRequestWithDONHostedSecrets( m.times, m.source, @@ -59,12 +59,12 @@ func (m *SingleFunctionCallGun) callReal() *wasp.CallResult { m.jobId, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } -func (m *SingleFunctionCallGun) callWithSecrets() *wasp.CallResult { +func (m *SingleFunctionCallGun) callWithSecrets() *wasp.Response { err := m.ft.LoadTestClient.SendRequestWithDONHostedSecrets( m.times, m.source, @@ -75,12 +75,12 @@ func (m *SingleFunctionCallGun) callWithSecrets() *wasp.CallResult { m.jobId, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } -func (m *SingleFunctionCallGun) callWithHttp() *wasp.CallResult { +func (m *SingleFunctionCallGun) callWithHttp() *wasp.Response { err := m.ft.LoadTestClient.SendRequest( m.times, m.source, @@ -90,13 +90,13 @@ func (m *SingleFunctionCallGun) callWithHttp() *wasp.CallResult { m.jobId, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } // Call implements example gun call, assertions on response bodies should be done here -func (m *SingleFunctionCallGun) Call(_ *wasp.Generator) *wasp.CallResult { +func (m *SingleFunctionCallGun) Call(_ *wasp.Generator) *wasp.Response { switch m.mode { case ModeSecretsOnlyPayload: return m.callWithSecrets() diff --git a/integration-tests/load/functions/setup.go b/integration-tests/load/functions/setup.go index c0be47ca836..e6711907592 100644 --- a/integration-tests/load/functions/setup.go +++ b/integration-tests/load/functions/setup.go @@ -5,7 +5,6 @@ import ( "fmt" "math/big" mrand "math/rand" - "os" "strconv" "time" @@ -18,7 +17,9 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink/integration-tests/contracts" - chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/utils" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/types" + chainlinkutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" ) type FunctionsTest struct { @@ -50,8 +51,9 @@ type S4SecretsCfg struct { S4SetPayload string } -func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { - bc, err := blockchain.NewEVMClientFromNetwork(networks.MustGetSelectedNetworksFromEnv()[0], log.Logger) +func SetupLocalLoadTestEnv(globalConfig tc.GlobalTestConfig, functionsConfig types.FunctionsTestConfig) (*FunctionsTest, error) { + selectedNetwork := networks.MustGetSelectedNetworkConfig(globalConfig.GetNetworkConfig())[0] + bc, err := blockchain.NewEVMClientFromNetwork(selectedNetwork, log.Logger) if err != nil { return nil, err } @@ -67,28 +69,31 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, err } - lt, err := cl.LoadLINKToken(cfg.Common.LINKTokenAddr) + + cfg := functionsConfig.GetFunctionsConfig() + + lt, err := cl.LoadLINKToken(*cfg.Common.LINKTokenAddr) if err != nil { return nil, err } - coord, err := cl.LoadFunctionsCoordinator(cfg.Common.Coordinator) + coord, err := cl.LoadFunctionsCoordinator(*cfg.Common.Coordinator) if err != nil { return nil, err } - router, err := cl.LoadFunctionsRouter(cfg.Common.Router) + router, err := cl.LoadFunctionsRouter(*cfg.Common.Router) if err != nil { return nil, err } var loadTestClient contracts.FunctionsLoadTestClient - if cfg.Common.LoadTestClient != "" { - loadTestClient, err = cl.LoadFunctionsLoadTestClient(cfg.Common.LoadTestClient) + if cfg.Common.LoadTestClient != nil && *cfg.Common.LoadTestClient != "" { + loadTestClient, err = cl.LoadFunctionsLoadTestClient(*cfg.Common.LoadTestClient) } else { - loadTestClient, err = cd.DeployFunctionsLoadTestClient(cfg.Common.Router) + loadTestClient, err = cd.DeployFunctionsLoadTestClient(*cfg.Common.Router) } if err != nil { return nil, err } - if cfg.Common.SubscriptionID == 0 { + if cfg.Common.SubscriptionID == nil { log.Info().Msg("Creating new subscription") subID, err := router.CreateSubscriptionWithConsumer(loadTestClient.Address()) if err != nil { @@ -98,13 +103,13 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, fmt.Errorf("failed to encode subscription ID for funding: %w", err) } - _, err = lt.TransferAndCall(router.Address(), big.NewInt(0).Mul(cfg.Common.Funding.SubFunds, big.NewInt(1e18)), encodedSubId) + _, err = lt.TransferAndCall(router.Address(), big.NewInt(0).Mul(cfg.Common.SubFunds, big.NewInt(1e18)), encodedSubId) if err != nil { return nil, fmt.Errorf("failed to transferAndCall router, LINK funding: %w", err) } - cfg.Common.SubscriptionID = subID + cfg.Common.SubscriptionID = &subID } - pKey, pubKey, err := parseEthereumPrivateKey(os.Getenv("MUMBAI_KEYS")) + pKey, pubKey, err := parseEthereumPrivateKey(selectedNetwork.PrivateKeys[0]) if err != nil { return nil, fmt.Errorf("failed to load Ethereum private key: %w", err) } @@ -123,17 +128,17 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { return nil, fmt.Errorf("failed to unmarshal tdh2 public key: %w", err) } var encryptedSecrets string - if cfg.Common.Secrets != "" { - encryptedSecrets, err = EncryptS4Secrets(pKey, tdh2pk, donPubKey, cfg.Common.Secrets) + if cfg.Common.Secrets != nil && *cfg.Common.Secrets != "" { + encryptedSecrets, err = EncryptS4Secrets(pKey, tdh2pk, donPubKey, *cfg.Common.Secrets) if err != nil { return nil, fmt.Errorf("failed to generate tdh2 secrets: %w", err) } slotID, slotVersion, err := UploadS4Secrets(resty.New(), &S4SecretsCfg{ - GatewayURL: cfg.Common.GatewayURL, - PrivateKey: cfg.MumbaiPrivateKey, + GatewayURL: *cfg.Common.GatewayURL, + PrivateKey: selectedNetwork.PrivateKeys[0], MessageID: strconv.Itoa(mrand.Intn(100000-1) + 1), Method: "secrets_set", - DonID: cfg.Common.DONID, + DonID: *cfg.Common.DONID, S4SetSlotID: uint(mrand.Intn(5)), S4SetVersion: uint64(time.Now().UnixNano()), S4SetExpirationPeriod: 60 * 60 * 1000, @@ -142,8 +147,8 @@ func SetupLocalLoadTestEnv(cfg *PerformanceConfig) (*FunctionsTest, error) { if err != nil { return nil, fmt.Errorf("failed to upload secrets to S4: %w", err) } - cfg.Common.SecretsSlotID = slotID - cfg.Common.SecretsVersionID = slotVersion + cfg.Common.SecretsSlotID = &slotID + cfg.Common.SecretsVersionID = &slotVersion log.Info(). Uint8("SlotID", slotID). Uint64("SlotVersion", slotVersion). diff --git a/integration-tests/load/log_poller/config.toml b/integration-tests/load/log_poller/config.toml deleted file mode 100644 index 2e328001943..00000000000 --- a/integration-tests/load/log_poller/config.toml +++ /dev/null @@ -1,22 +0,0 @@ -[general] -generator = "looped" -contracts = 10 -events_per_tx = 10 - -[chaos] -experiment_count = 10 - -[looped] -[looped.contract] -execution_count = 300 - -[looped.fuzz] -min_emit_wait_time_ms = 100 -max_emit_wait_time_ms = 500 - -[wasp] -[wasp.load] -call_timeout = "3m" -rate_limit_unit_duration = "2s" -LPS = 30 -duration = "1m" \ No newline at end of file diff --git a/integration-tests/load/log_poller/log_poller_test.go b/integration-tests/load/log_poller/log_poller_test.go deleted file mode 100644 index 04366848f0e..00000000000 --- a/integration-tests/load/log_poller/log_poller_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package logpoller - -import ( - "testing" - - "github.com/ethereum/go-ethereum/accounts/abi" - - "github.com/stretchr/testify/require" - - lp_helpers "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" -) - -func TestLoadTestLogPoller(t *testing.T) { - cfg, err := lp_helpers.ReadConfig(lp_helpers.DefaultConfigFilename) - require.NoError(t, err) - - eventsToEmit := []abi.Event{} - for _, event := range lp_helpers.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } - - cfg.General.EventsToEmit = eventsToEmit - - lp_helpers.ExecuteBasicLogPollerTest(t, cfg) -} diff --git a/integration-tests/load/ocr/README.md b/integration-tests/load/ocr/README.md index 20446992dc2..61951ba700f 100644 --- a/integration-tests/load/ocr/README.md +++ b/integration-tests/load/ocr/README.md @@ -3,15 +3,15 @@ ## Setup These tests can connect to any cluster create with [chainlink-cluster](../../../charts/chainlink-cluster/README.md) -Create your cluster +Create your cluster, if you already have one just use `kubefwd` ``` -kubectl create ns my-cluster -devspace use namespace my-cluster +kubectl create ns cl-cluster +devspace use namespace cl-cluster devspace deploy -sudo kubefwd svc -n my-cluster +sudo kubefwd svc -n cl-cluster ``` -Change environment connection configuration [here](connection.toml) +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 diff --git a/integration-tests/load/ocr/config.go b/integration-tests/load/ocr/config.go deleted file mode 100644 index 2991df3774a..00000000000 --- a/integration-tests/load/ocr/config.go +++ /dev/null @@ -1,72 +0,0 @@ -package ocr - -import ( - "encoding/base64" - "fmt" - "os" - - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - "github.com/smartcontractkit/chainlink/v2/core/store/models" -) - -const ( - DefaultConfigFilename = "config.toml" - ErrReadPerfConfig = "failed to read TOML config for performance tests" - ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" -) - -type PerformanceConfig struct { - Load *Load `toml:"Load"` - Volume *Volume `toml:"Volume"` - Common *Common `toml:"Common"` -} - -type Common struct { - ETHFunds int `toml:"eth_funds"` -} - -type Load struct { - TestDuration *models.Duration `toml:"test_duration"` - Rate int64 `toml:"rate"` - RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` - VerificationInterval *models.Duration `toml:"verification_interval"` - VerificationTimeout *models.Duration `toml:"verification_timeout"` - EAChangeInterval *models.Duration `toml:"ea_change_interval"` -} - -type Volume struct { - TestDuration *models.Duration `toml:"test_duration"` - Rate int64 `toml:"rate"` - VURequestsPerUnit int `toml:"vu_requests_per_unit"` - RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` - VerificationInterval *models.Duration `toml:"verification_interval"` - VerificationTimeout *models.Duration `toml:"verification_timeout"` - EAChangeInterval *models.Duration `toml:"ea_change_interval"` -} - -func ReadConfig() (*PerformanceConfig, error) { - var cfg *PerformanceConfig - rawConfig := os.Getenv("CONFIG") - var d []byte - var err error - if rawConfig == "" { - d, err = os.ReadFile(DefaultConfigFilename) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } else { - d, err = base64.StdEncoding.DecodeString(rawConfig) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) - } - - log.Debug().Interface("Config", cfg).Msg("Parsed config") - return cfg, nil -} diff --git a/integration-tests/load/ocr/config.toml b/integration-tests/load/ocr/config.toml deleted file mode 100644 index df8364b3ee4..00000000000 --- a/integration-tests/load/ocr/config.toml +++ /dev/null @@ -1,20 +0,0 @@ -[Load] -test_duration = "3m" -rate_limit_unit_duration = "1m" -rate = 3 -verification_interval = "5s" -verification_timeout = "3m" -ea_change_interval = "5s" - -[Volume] -test_duration = "3m" -rate_limit_unit_duration = "1m" -vu_requests_per_unit = 10 -rate = 1 -verification_interval = "5s" -verification_timeout = "3m" - -ea_change_interval = "5s" - -[Common] -eth_funds = 3 \ No newline at end of file diff --git a/integration-tests/load/ocr/gun.go b/integration-tests/load/ocr/gun.go index a2eb1ff2200..ed92e328024 100644 --- a/integration-tests/load/ocr/gun.go +++ b/integration-tests/load/ocr/gun.go @@ -30,7 +30,7 @@ func NewGun(l zerolog.Logger, cc blockchain.EVMClient, ocrInstances []contracts. } } -func (m *Gun) Call(_ *wasp.Generator) *wasp.CallResult { +func (m *Gun) Call(_ *wasp.Generator) *wasp.Response { m.roundNum.Add(1) requestedRound := m.roundNum.Load() m.l.Info(). @@ -39,17 +39,17 @@ func (m *Gun) Call(_ *wasp.Generator) *wasp.CallResult { Msg("starting new round") err := m.ocrInstances[0].RequestNewRound() if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } for { time.Sleep(5 * time.Second) lr, err := m.ocrInstances[0].GetLatestRound(context.Background()) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } m.l.Info().Interface("LatestRound", lr).Msg("latest round") if lr.RoundId.Int64() >= requestedRound { - return &wasp.CallResult{} + return &wasp.Response{} } } } diff --git a/integration-tests/load/ocr/ocr_test.go b/integration-tests/load/ocr/ocr_test.go index 6bf1487125d..c6edf9122b9 100644 --- a/integration-tests/load/ocr/ocr_test.go +++ b/integration-tests/load/ocr/ocr_test.go @@ -3,12 +3,14 @@ package ocr import ( "testing" - "github.com/smartcontractkit/chainlink/integration-tests/k8s" + "github.com/stretchr/testify/require" "github.com/smartcontractkit/wasp" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + + "github.com/smartcontractkit/chainlink/integration-tests/k8s" ) var ( @@ -18,7 +20,7 @@ var ( } ) -func TestOCRPerformance(t *testing.T) { +func TestOCRLoad(t *testing.T) { l := logging.GetTestLogger(t) cc, msClient, cd, bootstrapNode, workerNodes, err := k8s.ConnectRemote(l) require.NoError(t, err) @@ -26,45 +28,52 @@ func TestOCRPerformance(t *testing.T) { require.NoError(t, err) ocrInstances, err := SetupFeed(cc, msClient, cd, bootstrapNode, workerNodes, lt) require.NoError(t, err) - cfg, err := ReadConfig() + + config, err := tc.GetConfig("Load", tc.OCR) require.NoError(t, err) - SimulateEAActivity(l, cfg.Load.EAChangeInterval.Duration(), ocrInstances, workerNodes, msClient) + + cfg := config.OCR + cfgl := config.Logging.Loki + SimulateEAActivity(l, cfg.Load.EAChangeInterval.Duration, ocrInstances, workerNodes, msClient) p := wasp.NewProfile() p.Add(wasp.NewGenerator(&wasp.Config{ T: t, GenName: "ocr", LoadType: wasp.RPS, - CallTimeout: cfg.Load.VerificationTimeout.Duration(), - RateLimitUnitDuration: cfg.Load.RateLimitUnitDuration.Duration(), - Schedule: wasp.Plain(cfg.Load.Rate, cfg.Load.TestDuration.Duration()), + CallTimeout: cfg.Load.VerificationTimeout.Duration, + RateLimitUnitDuration: cfg.Load.RateLimitUnitDuration.Duration, + Schedule: wasp.Plain(*cfg.Load.Rate, cfg.Load.TestDuration.Duration), Gun: NewGun(l, cc, ocrInstances), Labels: CommonTestLabels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })) _, err = p.Run(true) require.NoError(t, err) } -func TestOCRCapacity(t *testing.T) { +func TestOCRVolume(t *testing.T) { l := logging.GetTestLogger(t) cc, msClient, cd, bootstrapNode, workerNodes, err := k8s.ConnectRemote(l) require.NoError(t, err) lt, err := SetupCluster(cc, cd, workerNodes) require.NoError(t, err) - cfg, err := ReadConfig() + config, err := tc.GetConfig("Volume", tc.OCR) require.NoError(t, err) + cfg := config.OCR + cfgl := config.Logging.Loki + p := wasp.NewProfile() p.Add(wasp.NewGenerator(&wasp.Config{ T: t, GenName: "ocr", LoadType: wasp.VU, - CallTimeout: cfg.Volume.VerificationTimeout.Duration(), - Schedule: wasp.Plain(cfg.Volume.Rate, cfg.Volume.TestDuration.Duration()), - VU: NewVU(l, cfg.Volume.VURequestsPerUnit, cfg.Volume.RateLimitUnitDuration.Duration(), cc, lt, cd, bootstrapNode, workerNodes, msClient), + CallTimeout: cfg.Volume.VerificationTimeout.Duration, + Schedule: wasp.Plain(*cfg.Volume.Rate, cfg.Volume.TestDuration.Duration), + VU: NewVU(l, *cfg.Volume.VURequestsPerUnit, cfg.Volume.RateLimitUnitDuration.Duration, cc, lt, cd, bootstrapNode, workerNodes, msClient), Labels: CommonTestLabels, - LokiConfig: wasp.NewEnvLokiConfig(), + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), })) _, err = p.Run(true) require.NoError(t, err) diff --git a/integration-tests/load/ocr/vu.go b/integration-tests/load/ocr/vu.go index a905ec011df..d113f7eb3f9 100644 --- a/integration-tests/load/ocr/vu.go +++ b/integration-tests/load/ocr/vu.go @@ -13,6 +13,7 @@ import ( "go.uber.org/ratelimit" client2 "github.com/smartcontractkit/chainlink-testing-framework/client" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" @@ -104,17 +105,17 @@ func (m *VU) Call(l *wasp.Generator) { Msg("starting new round") err := m.ocrInstances[0].RequestNewRound() if err != nil { - l.ResponsesChan <- &wasp.CallResult{Error: err.Error(), Failed: true} + l.ResponsesChan <- &wasp.Response{Error: err.Error(), Failed: true} } for { time.Sleep(5 * time.Second) lr, err := m.ocrInstances[0].GetLatestRound(context.Background()) if err != nil { - l.ResponsesChan <- &wasp.CallResult{Error: err.Error(), Failed: true} + l.ResponsesChan <- &wasp.Response{Error: err.Error(), Failed: true} } m.l.Info().Interface("LatestRound", lr).Msg("latest round") if lr.RoundId.Int64() >= requestedRound { - l.ResponsesChan <- &wasp.CallResult{} + l.ResponsesChan <- &wasp.Response{} } } } diff --git a/integration-tests/load/vrfv2/cmd/dashboard.go b/integration-tests/load/vrfv2/cmd/dashboard.go index 0fb7be2b78b..2536b4caed2 100644 --- a/integration-tests/load/vrfv2/cmd/dashboard.go +++ b/integration-tests/load/vrfv2/cmd/dashboard.go @@ -13,6 +13,7 @@ import ( ) func main() { + //TODO switch to TOML too? lokiDS := os.Getenv("DATA_SOURCE_NAME") d, err := wasp.NewDashboard(nil, []dashboard.Option{ diff --git a/integration-tests/load/vrfv2/config.go b/integration-tests/load/vrfv2/config.go deleted file mode 100644 index d5e94bb75fb..00000000000 --- a/integration-tests/load/vrfv2/config.go +++ /dev/null @@ -1,151 +0,0 @@ -package loadvrfv2 - -import ( - "encoding/base64" - "fmt" - "os" - - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" - - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - "github.com/smartcontractkit/chainlink/v2/core/store/models" -) - -const ( - DefaultConfigFilename = "config.toml" - SoakTestType = "Soak" - LoadTestType = "Load" - StressTestType = "Stress" - SpikeTestType = "Spike" - - ErrReadPerfConfig = "failed to read TOML config for performance tests" - ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" - ErrDeviationShouldBeLessThanOriginal = "`RandomnessRequestCountPerRequestDeviation` should be less than `RandomnessRequestCountPerRequest`" -) - -type PerformanceConfig struct { - Soak *Soak `toml:"Soak"` - Load *Load `toml:"Load"` - Stress *Stress `toml:"Stress"` - Spike *Spike `toml:"Spike"` - - Common *Common `toml:"Common"` - ExistingEnvConfig *ExistingEnvConfig `toml:"ExistingEnvConfig"` - NewEnvConfig *NewEnvConfig `toml:"NewEnvConfig"` -} - -type ExistingEnvConfig struct { - CoordinatorAddress string `toml:"coordinator_address"` - ConsumerAddress string `toml:"consumer_address"` - LinkAddress string `toml:"link_address"` - SubID uint64 `toml:"sub_id"` - KeyHash string `toml:"key_hash"` - Funding - CreateFundSubsAndAddConsumers bool `toml:"create_fund_subs_and_add_consumers"` - NodeSendingKeys []string `toml:"node_sending_keys"` -} - -type NewEnvConfig struct { - Funding -} - -type Common struct { - MinimumConfirmations uint16 `toml:"minimum_confirmations"` - CancelSubsAfterTestRun bool `toml:"cancel_subs_after_test_run"` -} - -type Funding struct { - SubFunding - NodeSendingKeyFunding float64 `toml:"node_sending_key_funding"` - NodeSendingKeyFundingMin float64 `toml:"node_sending_key_funding_min"` -} - -type SubFunding struct { - SubFundsLink float64 `toml:"sub_funds_link"` -} - -type Soak struct { - PerformanceTestConfig -} - -type Load struct { - PerformanceTestConfig -} - -type Stress struct { - PerformanceTestConfig -} - -type Spike struct { - PerformanceTestConfig -} - -type PerformanceTestConfig struct { - NumberOfSubToCreate int `toml:"number_of_sub_to_create"` - - RPS int64 `toml:"rps"` - //Duration *models.Duration `toml:"duration"` - RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` - RandomnessRequestCountPerRequest uint16 `toml:"randomness_request_count_per_request"` - RandomnessRequestCountPerRequestDeviation uint16 `toml:"randomness_request_count_per_request_deviation"` -} - -func ReadConfig() (*PerformanceConfig, error) { - var cfg *PerformanceConfig - rawConfig := os.Getenv("CONFIG") - var d []byte - var err error - if rawConfig == "" { - d, err = os.ReadFile(DefaultConfigFilename) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } else { - d, err = base64.StdEncoding.DecodeString(rawConfig) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) - } - - if cfg.Soak.RandomnessRequestCountPerRequest <= cfg.Soak.RandomnessRequestCountPerRequestDeviation { - return nil, fmt.Errorf("%s, err: %w", ErrDeviationShouldBeLessThanOriginal, err) - } - - log.Debug().Interface("Config", cfg).Msg("Parsed config") - return cfg, nil -} - -func SetPerformanceTestConfig(testType string, vrfv2Config *vrfv2_config.VRFV2Config, cfg *PerformanceConfig) { - switch testType { - case SoakTestType: - vrfv2Config.NumberOfSubToCreate = cfg.Soak.NumberOfSubToCreate - vrfv2Config.RPS = cfg.Soak.RPS - vrfv2Config.RateLimitUnitDuration = cfg.Soak.RateLimitUnitDuration.Duration() - vrfv2Config.RandomnessRequestCountPerRequest = cfg.Soak.RandomnessRequestCountPerRequest - vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Soak.RandomnessRequestCountPerRequestDeviation - case LoadTestType: - vrfv2Config.NumberOfSubToCreate = cfg.Load.NumberOfSubToCreate - vrfv2Config.RPS = cfg.Load.RPS - vrfv2Config.RateLimitUnitDuration = cfg.Load.RateLimitUnitDuration.Duration() - vrfv2Config.RandomnessRequestCountPerRequest = cfg.Load.RandomnessRequestCountPerRequest - vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Load.RandomnessRequestCountPerRequestDeviation - case StressTestType: - vrfv2Config.NumberOfSubToCreate = cfg.Stress.NumberOfSubToCreate - vrfv2Config.RPS = cfg.Stress.RPS - vrfv2Config.RateLimitUnitDuration = cfg.Stress.RateLimitUnitDuration.Duration() - vrfv2Config.RandomnessRequestCountPerRequest = cfg.Stress.RandomnessRequestCountPerRequest - vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Stress.RandomnessRequestCountPerRequestDeviation - case SpikeTestType: - vrfv2Config.NumberOfSubToCreate = cfg.Spike.NumberOfSubToCreate - vrfv2Config.RPS = cfg.Spike.RPS - vrfv2Config.RateLimitUnitDuration = cfg.Spike.RateLimitUnitDuration.Duration() - vrfv2Config.RandomnessRequestCountPerRequest = cfg.Spike.RandomnessRequestCountPerRequest - vrfv2Config.RandomnessRequestCountPerRequestDeviation = cfg.Spike.RandomnessRequestCountPerRequestDeviation - } -} diff --git a/integration-tests/load/vrfv2/config.toml b/integration-tests/load/vrfv2/config.toml deleted file mode 100644 index 6f54d1ec998..00000000000 --- a/integration-tests/load/vrfv2/config.toml +++ /dev/null @@ -1,58 +0,0 @@ - -[Common] -minimum_confirmations = 3 -cancel_subs_after_test_run = true - -[NewEnvConfig] -sub_funds_link = 1000 -node_sending_key_funding = 1000 - -[ExistingEnvConfig] -coordinator_address = "" -consumer_address = "" -sub_id = 1 -key_hash = "" -create_fund_subs_and_add_consumers = true -link_address = "" -sub_funds_link = 10 -node_sending_key_funding_min = 1 -node_sending_keys = [ - "", - "", - "", - "", - "", - "", -] - -# 10 RPM - 1 tx request with 1 rand request in each tx every 6 seconds -[Soak] -rate_limit_unit_duration = "6s" -rps = 1 -randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request -randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 1 - -# approx 60 RPM - 1 tx request with 3 rand requests in each tx every 3 seconds -[Load] -rate_limit_unit_duration = "3s" -rps = 1 -randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request -randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 1 - -# approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx -[Stress] -rate_limit_unit_duration = "1s" -rps = 3 -randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request -randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 1 - -# approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds -[Spike] -rate_limit_unit_duration = "1m" -rps = 1 -randomness_request_count_per_request = 150 # amount of randomness requests to make per one TX request -randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 1 diff --git a/integration-tests/load/vrfv2/gun.go b/integration-tests/load/vrfv2/gun.go index 8a5eb3c66de..4746c73081a 100644 --- a/integration-tests/load/vrfv2/gun.go +++ b/integration-tests/load/vrfv2/gun.go @@ -4,61 +4,64 @@ import ( "math/rand" "github.com/rs/zerolog" - "github.com/smartcontractkit/wasp" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" + "github.com/smartcontractkit/chainlink/integration-tests/types" ) /* SingleHashGun is a gun that constantly requests randomness for one feed */ type SingleHashGun struct { - contracts *vrfv2_actions.VRFV2Contracts - keyHash [32]byte - subIDs []uint64 - vrfv2Config vrfv2_config.VRFV2Config - logger zerolog.Logger + contracts *vrfv2.VRFV2Contracts + keyHash [32]byte + subIDs []uint64 + testConfig types.VRFv2TestConfig + logger zerolog.Logger } func NewSingleHashGun( - contracts *vrfv2_actions.VRFV2Contracts, + contracts *vrfv2.VRFV2Contracts, keyHash [32]byte, subIDs []uint64, - vrfv2Config vrfv2_config.VRFV2Config, + testConfig types.VRFv2TestConfig, logger zerolog.Logger, ) *SingleHashGun { return &SingleHashGun{ - contracts: contracts, - keyHash: keyHash, - subIDs: subIDs, - vrfv2Config: vrfv2Config, - logger: logger, + contracts: contracts, + keyHash: keyHash, + subIDs: subIDs, + testConfig: testConfig, + logger: logger, } } // Call implements example gun call, assertions on response bodies should be done here -func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.CallResult { +func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { //todo - should work with multiple consumers and consumers having different keyhashes and wallets + vrfv2Config := m.testConfig.GetVRFv2Config().General //randomly increase/decrease randomness request count per TX - randomnessRequestCountPerRequest := deviateValue(m.vrfv2Config.RandomnessRequestCountPerRequest, m.vrfv2Config.RandomnessRequestCountPerRequestDeviation) - _, err := vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + randomnessRequestCountPerRequest := deviateValue(*vrfv2Config.RandomnessRequestCountPerRequest, *vrfv2Config.RandomnessRequestCountPerRequestDeviation) + _, err := vrfv2.RequestRandomnessAndWaitForFulfillment( + m.logger, //the same consumer is used for all requests and in all subs m.contracts.LoadTestConsumers[0], m.contracts.Coordinator, - &vrfv2_actions.VRFV2Data{VRFV2KeyData: vrfv2_actions.VRFV2KeyData{KeyHash: m.keyHash}}, //randomly pick a subID from pool of subIDs m.subIDs[randInRange(0, len(m.subIDs)-1)], + &vrfv2.VRFV2Data{VRFV2KeyData: vrfv2.VRFV2KeyData{KeyHash: m.keyHash}}, + *vrfv2Config.MinimumConfirmations, + *vrfv2Config.CallbackGasLimit, + *vrfv2Config.NumberOfWords, randomnessRequestCountPerRequest, - m.vrfv2Config, - m.vrfv2Config.RandomWordsFulfilledEventTimeout, - m.logger, + *vrfv2Config.RandomnessRequestCountPerRequestDeviation, + vrfv2Config.RandomWordsFulfilledEventTimeout.Duration, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } func deviateValue(requestCountPerTX uint16, deviation uint16) uint16 { diff --git a/integration-tests/load/vrfv2/vrfv2_test.go b/integration-tests/load/vrfv2/vrfv2_test.go index ae109f75e28..3a29e729dea 100644 --- a/integration-tests/load/vrfv2/vrfv2_test.go +++ b/integration-tests/load/vrfv2/vrfv2_test.go @@ -3,13 +3,11 @@ package loadvrfv2 import ( "context" "math/big" - "os" "sync" "testing" "time" "github.com/ethereum/go-ethereum/common" - "github.com/kelseyhightower/envconfig" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" @@ -18,20 +16,21 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( env *test_env.CLClusterTestEnv - vrfv2Contracts *vrfv2_actions.VRFV2Contracts - vrfv2Data *vrfv2_actions.VRFV2Data + vrfv2Contracts *vrfv2.VRFV2Contracts + vrfv2Data *vrfv2.VRFV2Data subIDs []uint64 eoaWalletAddress string @@ -39,26 +38,21 @@ var ( "branch": "vrfv2_healthcheck", "commit": "vrfv2_healthcheck", } - - testType = os.Getenv("TEST_TYPE") ) func TestVRFV2Performance(t *testing.T) { - cfg, err := ReadConfig() + l := logging.GetTestLogger(t) + + testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) - var vrfv2Config vrfv2_config.VRFV2Config - err = envconfig.Process("VRFV2", &vrfv2Config) + testConfig, err := tc.GetConfig(testType, tc.VRFv2) require.NoError(t, err) testReporter := &testreporters.VRFV2TestReporter{} + vrfv2Config := testConfig.VRFv2 - SetPerformanceTestConfig(testType, &vrfv2Config, cfg) - - l := logging.GetTestLogger(t) - //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2Config.MinimumConfirmations = cfg.Common.MinimumConfirmations - - lokiConfig := wasp.NewEnvLokiConfig() + 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) @@ -68,35 +62,38 @@ func TestVRFV2Performance(t *testing.T) { updatedLabels := UpdateLabels(labels, t) l.Info(). - Str("Test Type", testType). - Str("Test Duration", vrfv2Config.TestDuration.Truncate(time.Second).String()). - Int64("RPS", vrfv2Config.RPS). - Str("RateLimitUnitDuration", vrfv2Config.RateLimitUnitDuration.String()). - Uint16("RandomnessRequestCountPerRequest", vrfv2Config.RandomnessRequestCountPerRequest). - Uint16("RandomnessRequestCountPerRequestDeviation", vrfv2Config.RandomnessRequestCountPerRequestDeviation). - Bool("UseExistingEnv", vrfv2Config.UseExistingEnv). + Str("Test Type", string(testType)). + Str("Test Duration", vrfv2Config.Performance.TestDuration.Duration.Truncate(time.Second).String()). + Int64("RPS", *vrfv2Config.Performance.RPS). + Str("RateLimitUnitDuration", vrfv2Config.Performance.RateLimitUnitDuration.String()). + Uint16("RandomnessRequestCountPerRequest", *vrfv2Config.General.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", *vrfv2Config.General.RandomnessRequestCountPerRequestDeviation). + Bool("UseExistingEnv", *vrfv2Config.Performance.UseExistingEnv). Msg("Performance Test Configuration") - if vrfv2Config.UseExistingEnv { + if *vrfv2Config.Performance.UseExistingEnv { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2Config.CoordinatorAddress = cfg.ExistingEnvConfig.CoordinatorAddress - vrfv2Config.ConsumerAddress = cfg.ExistingEnvConfig.ConsumerAddress - vrfv2Config.LinkAddress = cfg.ExistingEnvConfig.LinkAddress - vrfv2Config.SubscriptionFundingAmountLink = cfg.ExistingEnvConfig.SubFunding.SubFundsLink - vrfv2Config.SubID = cfg.ExistingEnvConfig.SubID - vrfv2Config.KeyHash = cfg.ExistingEnvConfig.KeyHash + cfg := testConfig.VRFv2 + + vrfv2Config.Performance.CoordinatorAddress = cfg.ExistingEnvConfig.CoordinatorAddress + vrfv2Config.Performance.ConsumerAddress = cfg.ExistingEnvConfig.ConsumerAddress + vrfv2Config.Performance.LinkAddress = cfg.ExistingEnvConfig.LinkAddress + vrfv2Config.General.SubscriptionFundingAmountLink = cfg.ExistingEnvConfig.SubFunding.SubFundsLink + vrfv2Config.Performance.SubID = cfg.ExistingEnvConfig.SubID + vrfv2Config.Performance.KeyHash = cfg.ExistingEnvConfig.KeyHash env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&testConfig). WithCustomCleanup( func() { - teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2Config) + teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - if cfg.Common.CancelSubsAfterTestRun { + if *vrfv2Config.Common.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner cancelSubsAndReturnFunds(subIDs, l) } @@ -106,45 +103,51 @@ func TestVRFV2Performance(t *testing.T) { require.NoError(t, err, "error creating test env") - coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(vrfv2Config.CoordinatorAddress) + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2(*vrfv2Config.Performance.CoordinatorAddress) require.NoError(t, err) var consumers []contracts.VRFv2LoadTestConsumer - if cfg.ExistingEnvConfig.CreateFundSubsAndAddConsumers { - linkToken, err := env.ContractLoader.LoadLINKToken(vrfv2Config.LinkAddress) + if *cfg.ExistingEnvConfig.CreateFundSubsAndAddConsumers { + linkToken, err := env.ContractLoader.LoadLINKToken(*vrfv2Config.Performance.LinkAddress) require.NoError(t, err) - consumers, err = vrfv2_actions.DeployVRFV2Consumers(env.ContractDeployer, coordinator, 1) + consumers, err = vrfv2.DeployVRFV2Consumers(env.ContractDeployer, coordinator.Address(), 1) require.NoError(t, err) - subIDs, err = vrfv2_actions.CreateFundSubsAndAddConsumers( + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2.ErrWaitTXsComplete) + l.Info(). + Str("Coordinator", *cfg.ExistingEnvConfig.CoordinatorAddress). + Int("Number of Subs to create", *vrfv2Config.General.NumberOfSubToCreate). + Msg("Creating and funding subscriptions, deploying and adding consumers to subs") + subIDs, err = vrfv2.CreateFundSubsAndAddConsumers( env, - vrfv2Config, + big.NewFloat(*cfg.General.SubscriptionFundingAmountLink), linkToken, coordinator, consumers, - vrfv2Config.NumberOfSubToCreate, + *vrfv2Config.General.NumberOfSubToCreate, ) require.NoError(t, err) } else { - consumer, err := env.ContractLoader.LoadVRFv2LoadTestConsumer(vrfv2Config.ConsumerAddress) + consumer, err := env.ContractLoader.LoadVRFv2LoadTestConsumer(*vrfv2Config.Performance.ConsumerAddress) require.NoError(t, err) consumers = append(consumers, consumer) - subIDs = append(subIDs, vrfv2Config.SubID) + subIDs = append(subIDs, *vrfv2Config.Performance.SubID) } - err = FundNodesIfNeeded(cfg, env.EVMClient, l) + err = FundNodesIfNeeded(&testConfig, env.EVMClient, l) require.NoError(t, err) - vrfv2Contracts = &vrfv2_actions.VRFV2Contracts{ + vrfv2Contracts = &vrfv2.VRFV2Contracts{ Coordinator: coordinator, LoadTestConsumers: consumers, BHS: nil, } - vrfv2Data = &vrfv2_actions.VRFV2Data{ - VRFV2KeyData: vrfv2_actions.VRFV2KeyData{ + vrfv2Data = &vrfv2.VRFV2Data{ + VRFV2KeyData: vrfv2.VRFV2KeyData{ VRFKey: nil, EncodedProvingKey: [2]*big.Int{}, - KeyHash: common.HexToHash(vrfv2Config.KeyHash), + KeyHash: common.HexToHash(*vrfv2Config.Performance.KeyHash), }, VRFJob: nil, PrimaryEthAddress: "", @@ -153,23 +156,27 @@ func TestVRFV2Performance(t *testing.T) { } else { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2Config.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeSendingKeyFunding - vrfv2Config.SubscriptionFundingAmountLink = cfg.NewEnvConfig.Funding.SubFundsLink + testConfig.Common.ChainlinkNodeFunding = testConfig.VRFv2.NewEnvConfig.NodeSendingKeyFunding + vrfv2Config.General.SubscriptionFundingAmountLink = testConfig.VRFv2.NewEnvConfig.Funding.SubFundsLink + + network, err := actions.EthereumNetworkConfigFromConfig(l, &testConfig) + require.NoError(t, err, "Error building ethereum network config") env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithTestConfig(&testConfig). + WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). WithCustomCleanup( func() { - teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2Config) + teardown(t, vrfv2Contracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - if cfg.Common.CancelSubsAfterTestRun { + if *testConfig.VRFv2.Common.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner cancelSubsAndReturnFunds(subIDs, l) } @@ -178,29 +185,33 @@ func TestVRFV2Performance(t *testing.T) { l.Error().Err(err).Msg("Error cleaning up test environment") } }). - WithLogWatcher(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2Config.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*vrfv2Config.General.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - vrfv2Contracts, subIDs, vrfv2Data, err = vrfv2_actions.SetupVRFV2Environment( + useVRFOwner := true + useTestCoordinator := true + + vrfv2Contracts, subIDs, vrfv2Data, err = vrfv2.SetupVRFV2Environment( env, - vrfv2Config, + &testConfig, + useVRFOwner, + useTestCoordinator, linkToken, mockETHLinkFeed, //register proving key against EOA address in order to return funds to this address env.EVMClient.GetDefaultWallet().Address(), 0, 1, - vrfv2Config.NumberOfSubToCreate, + *vrfv2Config.General.NumberOfSubToCreate, l, ) require.NoError(t, err, "error setting up VRF v2 env") @@ -211,19 +222,19 @@ func TestVRFV2Performance(t *testing.T) { for _, subID := range subIDs { subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information for subscription %d", subID) - vrfv2_actions.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) } singleFeedConfig := &wasp.Config{ T: t, LoadType: wasp.RPS, GenName: "gun", - RateLimitUnitDuration: vrfv2Config.RateLimitUnitDuration, + RateLimitUnitDuration: vrfv2Config.Performance.RateLimitUnitDuration.Duration, Gun: NewSingleHashGun( vrfv2Contracts, vrfv2Data.KeyHash, subIDs, - vrfv2Config, + &testConfig, l, ), Labels: labels, @@ -240,8 +251,8 @@ func TestVRFV2Performance(t *testing.T) { t.Run("vrfv2 performance test", func(t *testing.T) { singleFeedConfig.Schedule = wasp.Plain( - vrfv2Config.RPS, - vrfv2Config.TestDuration, + *vrfv2Config.Performance.RPS, + vrfv2Config.Performance.TestDuration.Duration, ) _, err = wasp.NewProfile(). Add(wasp.NewGenerator(singleFeedConfig)). @@ -251,7 +262,7 @@ func TestVRFV2Performance(t *testing.T) { var wg sync.WaitGroup wg.Add(1) //todo - timeout should be configurable depending on the perf test type - requestCount, fulfilmentCount, err := vrfv2_actions.WaitForRequestCountEqualToFulfilmentCount(consumer, 2*time.Minute, &wg) + requestCount, fulfilmentCount, err := vrfv2.WaitForRequestCountEqualToFulfilmentCount(consumer, 2*time.Minute, &wg) require.NoError(t, err) wg.Wait() @@ -284,15 +295,16 @@ func cancelSubsAndReturnFunds(subIDs []uint64, l zerolog.Logger) { } } -func FundNodesIfNeeded(cfg *PerformanceConfig, client blockchain.EVMClient, l zerolog.Logger) error { - if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { +func FundNodesIfNeeded(vrfv2TestConfig tc.VRFv2TestConfig, client blockchain.EVMClient, l zerolog.Logger) error { + cfg := vrfv2TestConfig.GetVRFv2Config() + if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin != nil && *cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { for _, sendingKey := range cfg.ExistingEnvConfig.NodeSendingKeys { address := common.HexToAddress(sendingKey) sendingKeyBalance, err := client.BalanceAt(context.Background(), address) if err != nil { return err } - fundingAtLeast := conversions.EtherToWei(big.NewFloat(cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) + fundingAtLeast := conversions.EtherToWei(big.NewFloat(*cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) fundingToSendWei := new(big.Int).Sub(fundingAtLeast, sendingKeyBalance) fundingToSendEth := conversions.WeiToEther(fundingToSendWei) if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { @@ -325,7 +337,7 @@ func teardown( updatedLabels map[string]string, testReporter *testreporters.VRFV2TestReporter, testType string, - vrfv2Config vrfv2_config.VRFV2Config, + testConfig *tc.TestConfig, ) { //send final results to Loki metrics := GetLoadTestMetrics(consumer) @@ -338,7 +350,7 @@ func teardown( metrics.AverageFulfillmentInMillions, metrics.SlowestFulfillment, metrics.FastestFulfillment, - vrfv2Config, + testConfig, ) // send Slack notification diff --git a/integration-tests/load/vrfv2plus/cmd/dashboard.go b/integration-tests/load/vrfv2plus/cmd/dashboard.go index 049ee9ff2e9..2be0e265041 100644 --- a/integration-tests/load/vrfv2plus/cmd/dashboard.go +++ b/integration-tests/load/vrfv2plus/cmd/dashboard.go @@ -13,6 +13,7 @@ import ( ) func main() { + //TODO switch to TOML too? lokiDS := os.Getenv("DATA_SOURCE_NAME") d, err := wasp.NewDashboard(nil, []dashboard.Option{ diff --git a/integration-tests/load/vrfv2plus/config.go b/integration-tests/load/vrfv2plus/config.go deleted file mode 100644 index 43bcf44d044..00000000000 --- a/integration-tests/load/vrfv2plus/config.go +++ /dev/null @@ -1,151 +0,0 @@ -package loadvrfv2plus - -import ( - "encoding/base64" - "fmt" - "os" - - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" - "github.com/smartcontractkit/chainlink/v2/core/store/models" -) - -const ( - DefaultConfigFilename = "config.toml" - SoakTestType = "Soak" - LoadTestType = "Load" - StressTestType = "Stress" - SpikeTestType = "Spike" - - ErrReadPerfConfig = "failed to read TOML config for performance tests" - ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" - ErrDeviationShouldBeLessThanOriginal = "`RandomnessRequestCountPerRequestDeviation` should be less than `RandomnessRequestCountPerRequest`" -) - -type PerformanceConfig struct { - Soak *Soak `toml:"Soak"` - Load *Load `toml:"Load"` - Stress *Stress `toml:"Stress"` - Spike *Spike `toml:"Spike"` - - Common *Common `toml:"Common"` - ExistingEnvConfig *ExistingEnvConfig `toml:"ExistingEnvConfig"` - NewEnvConfig *NewEnvConfig `toml:"NewEnvConfig"` -} - -type ExistingEnvConfig struct { - CoordinatorAddress string `toml:"coordinator_address"` - ConsumerAddress string `toml:"consumer_address"` - LinkAddress string `toml:"link_address"` - SubID string `toml:"sub_id"` - KeyHash string `toml:"key_hash"` - Funding - CreateFundSubsAndAddConsumers bool `toml:"create_fund_subs_and_add_consumers"` - NodeSendingKeys []string `toml:"node_sending_keys"` -} - -type NewEnvConfig struct { - Funding -} - -type Common struct { - MinimumConfirmations uint16 `toml:"minimum_confirmations"` - CancelSubsAfterTestRun bool `toml:"cancel_subs_after_test_run"` -} - -type Funding struct { - SubFunding - NodeSendingKeyFunding float64 `toml:"node_sending_key_funding"` - NodeSendingKeyFundingMin float64 `toml:"node_sending_key_funding_min"` -} - -type SubFunding struct { - SubFundsLink float64 `toml:"sub_funds_link"` - SubFundsNative float64 `toml:"sub_funds_native"` -} - -type Soak struct { - PerformanceTestConfig -} - -type Load struct { - PerformanceTestConfig -} - -type Stress struct { - PerformanceTestConfig -} - -type Spike struct { - PerformanceTestConfig -} - -type PerformanceTestConfig struct { - NumberOfSubToCreate int `toml:"number_of_sub_to_create"` - - RPS int64 `toml:"rps"` - //Duration *models.Duration `toml:"duration"` - RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` - RandomnessRequestCountPerRequest uint16 `toml:"randomness_request_count_per_request"` - RandomnessRequestCountPerRequestDeviation uint16 `toml:"randomness_request_count_per_request_deviation"` -} - -func ReadConfig() (*PerformanceConfig, error) { - var cfg *PerformanceConfig - rawConfig := os.Getenv("CONFIG") - var d []byte - var err error - if rawConfig == "" { - d, err = os.ReadFile(DefaultConfigFilename) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } else { - d, err = base64.StdEncoding.DecodeString(rawConfig) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrReadPerfConfig, err) - } - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, fmt.Errorf("%s, err: %w", ErrUnmarshalPerfConfig, err) - } - - if cfg.Soak.RandomnessRequestCountPerRequest <= cfg.Soak.RandomnessRequestCountPerRequestDeviation { - return nil, fmt.Errorf("%s, err: %w", ErrDeviationShouldBeLessThanOriginal, err) - } - - log.Debug().Interface("Config", cfg).Msg("Parsed config") - return cfg, nil -} - -func SetPerformanceTestConfig(testType string, vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig, cfg *PerformanceConfig) { - switch testType { - case SoakTestType: - vrfv2PlusConfig.NumberOfSubToCreate = cfg.Soak.NumberOfSubToCreate - vrfv2PlusConfig.RPS = cfg.Soak.RPS - vrfv2PlusConfig.RateLimitUnitDuration = cfg.Soak.RateLimitUnitDuration.Duration() - vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Soak.RandomnessRequestCountPerRequest - vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Soak.RandomnessRequestCountPerRequestDeviation - case LoadTestType: - vrfv2PlusConfig.NumberOfSubToCreate = cfg.Load.NumberOfSubToCreate - vrfv2PlusConfig.RPS = cfg.Load.RPS - vrfv2PlusConfig.RateLimitUnitDuration = cfg.Load.RateLimitUnitDuration.Duration() - vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Load.RandomnessRequestCountPerRequest - vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Load.RandomnessRequestCountPerRequestDeviation - case StressTestType: - vrfv2PlusConfig.NumberOfSubToCreate = cfg.Stress.NumberOfSubToCreate - vrfv2PlusConfig.RPS = cfg.Stress.RPS - vrfv2PlusConfig.RateLimitUnitDuration = cfg.Stress.RateLimitUnitDuration.Duration() - vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Stress.RandomnessRequestCountPerRequest - vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Stress.RandomnessRequestCountPerRequestDeviation - case SpikeTestType: - vrfv2PlusConfig.NumberOfSubToCreate = cfg.Spike.NumberOfSubToCreate - vrfv2PlusConfig.RPS = cfg.Spike.RPS - vrfv2PlusConfig.RateLimitUnitDuration = cfg.Spike.RateLimitUnitDuration.Duration() - vrfv2PlusConfig.RandomnessRequestCountPerRequest = cfg.Spike.RandomnessRequestCountPerRequest - vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation = cfg.Spike.RandomnessRequestCountPerRequestDeviation - } -} diff --git a/integration-tests/load/vrfv2plus/config.toml b/integration-tests/load/vrfv2plus/config.toml deleted file mode 100644 index 8ccf60c6d80..00000000000 --- a/integration-tests/load/vrfv2plus/config.toml +++ /dev/null @@ -1,60 +0,0 @@ - -[Common] -minimum_confirmations = 3 -cancel_subs_after_test_run = true - -[NewEnvConfig] -sub_funds_link = 1 -sub_funds_native = 1 -node_funds = 10 -node_sending_key_funding = 1000 - -[ExistingEnvConfig] -coordinator_address = "" -consumer_address = "" -sub_id = 1 -key_hash = "" -create_fund_subs_and_add_consumers = true -link_address = "" -sub_funds_link = 10 -node_sending_key_funding_min = 1 -node_sending_keys = [ - "", - "", - "", - "", - "", - "", -] - -# 10 RPM - 1 tx request with 1 rand request in each tx every 6 seconds -[Soak] -rate_limit_unit_duration = "6s" -rps = 1 -randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request -randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 1 - -# approx 60 RPM - 1 tx request with 3 rand requests in each tx every 3 seconds -[Load] -rate_limit_unit_duration = "3s" -rps = 1 -randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request -randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 1 - -# approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx -[Stress] -rate_limit_unit_duration = "1s" -rps = 3 -randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request -randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 1 - -# approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds -[Spike] -rate_limit_unit_duration = "1m" -rps = 1 -randomness_request_count_per_request = 150 # amount of randomness requests to make per one TX request -randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting -number_of_sub_to_create = 1 diff --git a/integration-tests/load/vrfv2plus/gun.go b/integration-tests/load/vrfv2plus/gun.go index 8ab278b73e9..faf5e6ef211 100644 --- a/integration-tests/load/vrfv2plus/gun.go +++ b/integration-tests/load/vrfv2plus/gun.go @@ -1,49 +1,56 @@ package loadvrfv2plus import ( + "fmt" "math/big" "math/rand" "github.com/rs/zerolog" "github.com/smartcontractkit/wasp" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2plus" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" + "github.com/smartcontractkit/chainlink/integration-tests/types" ) /* SingleHashGun is a gun that constantly requests randomness for one feed */ type SingleHashGun struct { - contracts *vrfv2plus.VRFV2_5Contracts - keyHash [32]byte - subIDs []*big.Int - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - logger zerolog.Logger + contracts *vrfv2plus.VRFV2_5Contracts + keyHash [32]byte + subIDs []*big.Int + testConfig types.VRFv2PlusTestConfig + logger zerolog.Logger } func NewSingleHashGun( contracts *vrfv2plus.VRFV2_5Contracts, keyHash [32]byte, subIDs []*big.Int, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + testConfig types.VRFv2PlusTestConfig, logger zerolog.Logger, ) *SingleHashGun { return &SingleHashGun{ - contracts: contracts, - keyHash: keyHash, - subIDs: subIDs, - vrfv2PlusConfig: vrfv2PlusConfig, - logger: logger, + contracts: contracts, + keyHash: keyHash, + subIDs: subIDs, + testConfig: testConfig, + logger: logger, } } // Call implements example gun call, assertions on response bodies should be done here -func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.CallResult { +func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.Response { //todo - should work with multiple consumers and consumers having different keyhashes and wallets + billingType, err := selectBillingType(*m.testConfig.GetVRFv2PlusConfig().General.SubscriptionBillingType) + if err != nil { + return &wasp.Response{Error: err.Error(), Failed: true} + } + //randomly increase/decrease randomness request count per TX - randomnessRequestCountPerRequest := deviateValue(m.vrfv2PlusConfig.RandomnessRequestCountPerRequest, m.vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation) - _, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( + randomnessRequestCountPerRequest := deviateValue(*m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequest, *m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequestDeviation) + _, err = vrfv2plus.RequestRandomnessAndWaitForFulfillment( //the same consumer is used for all requests and in all subs m.contracts.LoadTestConsumers[0], m.contracts.Coordinator, @@ -51,16 +58,19 @@ func (m *SingleHashGun) Call(_ *wasp.Generator) *wasp.CallResult { //randomly pick a subID from pool of subIDs m.subIDs[randInRange(0, len(m.subIDs)-1)], //randomly pick payment type - randBool(), + billingType, + *m.testConfig.GetVRFv2PlusConfig().General.MinimumConfirmations, + *m.testConfig.GetVRFv2PlusConfig().General.CallbackGasLimit, + *m.testConfig.GetVRFv2PlusConfig().General.NumberOfWords, randomnessRequestCountPerRequest, - m.vrfv2PlusConfig, - m.vrfv2PlusConfig.RandomWordsFulfilledEventTimeout, + *m.testConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequestDeviation, + m.testConfig.GetVRFv2PlusConfig().General.RandomWordsFulfilledEventTimeout.Duration, m.logger, ) if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } - return &wasp.CallResult{} + return &wasp.Response{} } func deviateValue(requestCountPerTX uint16, deviation uint16) uint16 { @@ -78,3 +88,16 @@ func randBool() bool { func randInRange(min int, max int) int { return rand.Intn(max-min+1) + min } + +func selectBillingType(billingType string) (bool, error) { + switch vrfv2plus_config.BillingType(billingType) { + case vrfv2plus_config.BillingType_Link: + return false, nil + case vrfv2plus_config.BillingType_Native: + return true, nil + case vrfv2plus_config.BillingType_Link_and_Native: + return randBool(), nil + default: + return false, fmt.Errorf("invalid billing type: %s", billingType) + } +} diff --git a/integration-tests/load/vrfv2plus/vrfv2plus_test.go b/integration-tests/load/vrfv2plus/vrfv2plus_test.go index 4b6728440b3..51a3116dca2 100644 --- a/integration-tests/load/vrfv2plus/vrfv2plus_test.go +++ b/integration-tests/load/vrfv2plus/vrfv2plus_test.go @@ -3,14 +3,11 @@ package loadvrfv2plus import ( "context" "math/big" - "os" "sync" "testing" "time" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" - "github.com/kelseyhightower/envconfig" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/smartcontractkit/wasp" @@ -20,13 +17,15 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2plus" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" ) var ( @@ -40,27 +39,21 @@ var ( "branch": "vrfv2Plus_healthcheck", "commit": "vrfv2Plus_healthcheck", } - - testType = os.Getenv("TEST_TYPE") ) func TestVRFV2PlusPerformance(t *testing.T) { - cfg, err := ReadConfig() + l := logging.GetTestLogger(t) + + testType, err := tc.GetConfigurationNameFromEnv() require.NoError(t, err) - var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - err = envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) + testConfig, err := tc.GetConfig(testType, tc.VRFv2Plus) require.NoError(t, err) + cfgl := testConfig.Logging.Loki + vrfv2PlusConfig := testConfig.VRFv2Plus testReporter := &testreporters.VRFV2PlusTestReporter{} - SetPerformanceTestConfig(testType, &vrfv2PlusConfig, cfg) - - l := logging.GetTestLogger(t) - //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2PlusConfig.MinimumConfirmations = cfg.Common.MinimumConfirmations - - lokiConfig := wasp.NewEnvLokiConfig() - lc, err := wasp.NewLokiClient(lokiConfig) + lc, err := wasp.NewLokiClient(wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken)) if err != nil { l.Error().Err(err).Msg(ErrLokiClient) return @@ -69,36 +62,37 @@ func TestVRFV2PlusPerformance(t *testing.T) { updatedLabels := UpdateLabels(labels, t) l.Info(). - Str("Test Type", testType). - Str("Test Duration", vrfv2PlusConfig.TestDuration.Truncate(time.Second).String()). - Int64("RPS", vrfv2PlusConfig.RPS). - Str("RateLimitUnitDuration", vrfv2PlusConfig.RateLimitUnitDuration.String()). - Uint16("RandomnessRequestCountPerRequest", vrfv2PlusConfig.RandomnessRequestCountPerRequest). - Uint16("RandomnessRequestCountPerRequestDeviation", vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation). - Bool("UseExistingEnv", vrfv2PlusConfig.UseExistingEnv). + Str("Test Type", string(testType)). + Str("Test Duration", vrfv2PlusConfig.Performance.TestDuration.Duration.Truncate(time.Second).String()). + Int64("RPS", *vrfv2PlusConfig.Performance.RPS). + Str("RateLimitUnitDuration", vrfv2PlusConfig.Performance.RateLimitUnitDuration.String()). + Uint16("RandomnessRequestCountPerRequest", *vrfv2PlusConfig.General.RandomnessRequestCountPerRequest). + Uint16("RandomnessRequestCountPerRequestDeviation", *vrfv2PlusConfig.General.RandomnessRequestCountPerRequestDeviation). + Bool("UseExistingEnv", *vrfv2PlusConfig.Performance.UseExistingEnv). Msg("Performance Test Configuration") - if vrfv2PlusConfig.UseExistingEnv { + if *vrfv2PlusConfig.Performance.UseExistingEnv { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2PlusConfig.CoordinatorAddress = cfg.ExistingEnvConfig.CoordinatorAddress - vrfv2PlusConfig.ConsumerAddress = cfg.ExistingEnvConfig.ConsumerAddress - vrfv2PlusConfig.LinkAddress = cfg.ExistingEnvConfig.LinkAddress - vrfv2PlusConfig.SubscriptionFundingAmountLink = cfg.ExistingEnvConfig.SubFunding.SubFundsLink - vrfv2PlusConfig.SubscriptionFundingAmountNative = cfg.ExistingEnvConfig.SubFunding.SubFundsNative - vrfv2PlusConfig.SubID = cfg.ExistingEnvConfig.SubID - vrfv2PlusConfig.KeyHash = cfg.ExistingEnvConfig.KeyHash + vrfv2PlusConfig.Performance.CoordinatorAddress = testConfig.VRFv2Plus.ExistingEnvConfig.CoordinatorAddress + vrfv2PlusConfig.Performance.ConsumerAddress = testConfig.VRFv2Plus.ExistingEnvConfig.ConsumerAddress + vrfv2PlusConfig.Performance.LinkAddress = testConfig.VRFv2Plus.ExistingEnvConfig.LinkAddress + vrfv2PlusConfig.General.SubscriptionFundingAmountLink = testConfig.VRFv2Plus.ExistingEnvConfig.SubFunding.SubFundsLink + vrfv2PlusConfig.General.SubscriptionFundingAmountNative = testConfig.VRFv2Plus.ExistingEnvConfig.SubFunding.SubFundsNative + vrfv2PlusConfig.Performance.SubID = testConfig.VRFv2Plus.ExistingEnvConfig.SubID + vrfv2PlusConfig.Performance.KeyHash = testConfig.VRFv2Plus.ExistingEnvConfig.KeyHash env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&testConfig). WithCustomCleanup( func() { - teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) + teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - if cfg.Common.CancelSubsAfterTestRun { + if *testConfig.VRFv2Plus.Common.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner cancelSubsAndReturnFunds(subIDs, l) } @@ -108,35 +102,43 @@ func TestVRFV2PlusPerformance(t *testing.T) { require.NoError(t, err, "error creating test env") - coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2_5(vrfv2PlusConfig.CoordinatorAddress) + coordinator, err := env.ContractLoader.LoadVRFCoordinatorV2_5(*vrfv2PlusConfig.Performance.CoordinatorAddress) require.NoError(t, err) var consumers []contracts.VRFv2PlusLoadTestConsumer - if cfg.ExistingEnvConfig.CreateFundSubsAndAddConsumers { - linkToken, err := env.ContractLoader.LoadLINKToken(vrfv2PlusConfig.LinkAddress) + if *testConfig.VRFv2Plus.ExistingEnvConfig.CreateFundSubsAndAddConsumers { + linkToken, err := env.ContractLoader.LoadLINKToken(*vrfv2PlusConfig.Performance.LinkAddress) require.NoError(t, err) consumers, err = vrfv2plus.DeployVRFV2PlusConsumers(env.ContractDeployer, coordinator, 1) require.NoError(t, err) + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + l.Info(). + Str("Coordinator", *vrfv2PlusConfig.Performance.CoordinatorAddress). + Int("Number of Subs to create", *vrfv2PlusConfig.General.NumberOfSubToCreate). + Msg("Creating and funding subscriptions, deploying and adding consumers to subs") subIDs, err = vrfv2plus.CreateFundSubsAndAddConsumers( env, - vrfv2PlusConfig, + big.NewFloat(*testConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), + big.NewFloat(*testConfig.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, coordinator, consumers, - vrfv2PlusConfig.NumberOfSubToCreate, + *vrfv2PlusConfig.General.NumberOfSubToCreate, + vrfv2plus_config.BillingType(*vrfv2PlusConfig.General.SubscriptionBillingType), ) require.NoError(t, err) } else { - consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(vrfv2PlusConfig.ConsumerAddress) + consumer, err := env.ContractLoader.LoadVRFv2PlusLoadTestConsumer(*vrfv2PlusConfig.Performance.ConsumerAddress) require.NoError(t, err) consumers = append(consumers, consumer) var ok bool - subID, ok := new(big.Int).SetString(vrfv2PlusConfig.SubID, 10) + subID := big.NewInt(int64(*vrfv2PlusConfig.Performance.SubID)) require.True(t, ok) subIDs = append(subIDs, subID) } - err = FundNodesIfNeeded(cfg, env.EVMClient, l) + err = FundNodesIfNeeded(&testConfig, env.EVMClient, l) require.NoError(t, err) vrfv2PlusContracts = &vrfv2plus.VRFV2_5Contracts{ @@ -149,7 +151,7 @@ func TestVRFV2PlusPerformance(t *testing.T) { VRFV2PlusKeyData: vrfv2plus.VRFV2PlusKeyData{ VRFKey: nil, EncodedProvingKey: [2]*big.Int{}, - KeyHash: common.HexToHash(vrfv2PlusConfig.KeyHash), + KeyHash: common.HexToHash(*vrfv2PlusConfig.Performance.KeyHash), }, VRFJob: nil, PrimaryEthAddress: "", @@ -158,24 +160,28 @@ func TestVRFV2PlusPerformance(t *testing.T) { } else { //todo: temporary solution with envconfig and toml config until VRF-662 is implemented - vrfv2PlusConfig.ChainlinkNodeFunding = cfg.NewEnvConfig.NodeSendingKeyFunding - vrfv2PlusConfig.SubscriptionFundingAmountLink = cfg.NewEnvConfig.Funding.SubFundsLink - vrfv2PlusConfig.SubscriptionFundingAmountNative = cfg.NewEnvConfig.Funding.SubFundsNative + testConfig.Common.ChainlinkNodeFunding = testConfig.VRFv2.NewEnvConfig.NodeSendingKeyFunding + vrfv2PlusConfig.General.SubscriptionFundingAmountLink = testConfig.VRFv2Plus.NewEnvConfig.Funding.SubFundsLink + vrfv2PlusConfig.General.SubscriptionFundingAmountNative = testConfig.VRFv2Plus.NewEnvConfig.Funding.SubFundsNative + + network, err := actions.EthereumNetworkConfigFromConfig(l, &testConfig) + require.NoError(t, err, "Error building ethereum network config") env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithTestConfig(&testConfig). + WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*testConfig.Common.ChainlinkNodeFunding)). WithCustomCleanup( func() { - teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, testType, vrfv2PlusConfig) + teardown(t, vrfv2PlusContracts.LoadTestConsumers[0], lc, updatedLabels, testReporter, string(testType), &testConfig) if env.EVMClient.NetworkSimulated() { l.Info(). Str("Network Name", env.EVMClient.GetNetworkName()). Msg("Network is a simulated network. Skipping fund return for Coordinator Subscriptions.") } else { - if cfg.Common.CancelSubsAfterTestRun { + if *testConfig.VRFv2Plus.Common.CancelSubsAfterTestRun { //cancel subs and return funds to sub owner cancelSubsAndReturnFunds(subIDs, l) } @@ -184,14 +190,13 @@ func TestVRFV2PlusPerformance(t *testing.T) { l.Error().Err(err).Msg("Error cleaning up test environment") } }). - WithLogWatcher(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*vrfv2PlusConfig.General.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkToken, err := actions.DeployLINKToken(env.ContractDeployer) @@ -199,14 +204,12 @@ func TestVRFV2PlusPerformance(t *testing.T) { vrfv2PlusContracts, subIDs, vrfv2PlusData, err = vrfv2plus.SetupVRFV2_5Environment( env, - vrfv2PlusConfig, + &testConfig, linkToken, mockETHLinkFeed, - //register proving key against EOA address in order to return funds to this address - env.EVMClient.GetDefaultWallet().Address(), 0, 1, - vrfv2PlusConfig.NumberOfSubToCreate, + *vrfv2PlusConfig.General.NumberOfSubToCreate, l, ) require.NoError(t, err, "error setting up VRF v2_5 env") @@ -224,16 +227,16 @@ func TestVRFV2PlusPerformance(t *testing.T) { T: t, LoadType: wasp.RPS, GenName: "gun", - RateLimitUnitDuration: vrfv2PlusConfig.RateLimitUnitDuration, + RateLimitUnitDuration: vrfv2PlusConfig.Performance.RateLimitUnitDuration.Duration, Gun: NewSingleHashGun( vrfv2PlusContracts, vrfv2PlusData.KeyHash, subIDs, - vrfv2PlusConfig, + &testConfig, l, ), Labels: labels, - LokiConfig: lokiConfig, + LokiConfig: wasp.NewLokiConfig(cfgl.Endpoint, cfgl.TenantId, cfgl.BasicAuth, cfgl.BearerToken), CallTimeout: 2 * time.Minute, } require.Len(t, vrfv2PlusContracts.LoadTestConsumers, 1, "only one consumer should be created for Load Test") @@ -244,10 +247,9 @@ func TestVRFV2PlusPerformance(t *testing.T) { // is our "job" stable at all, no memory leaks, no flaking performance under some RPS? t.Run("vrfv2plus performance test", func(t *testing.T) { - singleFeedConfig.Schedule = wasp.Plain( - vrfv2PlusConfig.RPS, - vrfv2PlusConfig.TestDuration, + *vrfv2PlusConfig.Performance.RPS, + vrfv2PlusConfig.Performance.TestDuration.Duration, ) _, err = wasp.NewProfile(). Add(wasp.NewGenerator(singleFeedConfig)). @@ -290,15 +292,16 @@ func cancelSubsAndReturnFunds(subIDs []*big.Int, l zerolog.Logger) { } } -func FundNodesIfNeeded(cfg *PerformanceConfig, client blockchain.EVMClient, l zerolog.Logger) error { - if cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { +func FundNodesIfNeeded(vrfv2plusTestConfig tc.VRFv2PlusTestConfig, client blockchain.EVMClient, l zerolog.Logger) error { + cfg := vrfv2plusTestConfig.GetVRFv2PlusConfig() + if *cfg.ExistingEnvConfig.NodeSendingKeyFundingMin > 0 { for _, sendingKey := range cfg.ExistingEnvConfig.NodeSendingKeys { address := common.HexToAddress(sendingKey) sendingKeyBalance, err := client.BalanceAt(context.Background(), address) if err != nil { return err } - fundingAtLeast := conversions.EtherToWei(big.NewFloat(cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) + fundingAtLeast := conversions.EtherToWei(big.NewFloat(*cfg.ExistingEnvConfig.NodeSendingKeyFundingMin)) fundingToSendWei := new(big.Int).Sub(fundingAtLeast, sendingKeyBalance) fundingToSendEth := conversions.WeiToEther(fundingToSendWei) if fundingToSendWei.Cmp(big.NewInt(0)) == 1 { @@ -308,13 +311,7 @@ func FundNodesIfNeeded(cfg *PerformanceConfig, client blockchain.EVMClient, l ze Str("Should have at least", fundingAtLeast.String()). Str("Funding Amount in ETH", fundingToSendEth.String()). Msg("Funding Node's Sending Key") - gasEstimates, err := client.EstimateGas(ethereum.CallMsg{ - To: &address, - }) - if err != nil { - return err - } - err = client.Fund(sendingKey, fundingToSendEth, gasEstimates) + err := actions.FundAddress(client, sendingKey, fundingToSendEth) if err != nil { return err } @@ -337,7 +334,7 @@ func teardown( updatedLabels map[string]string, testReporter *testreporters.VRFV2PlusTestReporter, testType string, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + testConfig *tc.TestConfig, ) { //send final results to Loki metrics := GetLoadTestMetrics(consumer) @@ -350,11 +347,11 @@ func teardown( metrics.AverageFulfillmentInMillions, metrics.SlowestFulfillment, metrics.FastestFulfillment, - vrfv2PlusConfig, + testConfig, ) // send Slack notification - err := testReporter.SendSlackNotification(t, nil) + err := testReporter.SendSlackNotification(t, nil, testConfig) if err != nil { log.Warn().Err(err).Msg("Error sending Slack notification") } diff --git a/integration-tests/migration/upgrade_version_test.go b/integration-tests/migration/upgrade_version_test.go index d1f07a52b74..584a9fbc75e 100644 --- a/integration-tests/migration/upgrade_version_test.go +++ b/integration-tests/migration/upgrade_version_test.go @@ -1,38 +1,41 @@ package migration import ( - "os" "testing" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestVersionUpgrade(t *testing.T) { t.Parallel() + + config, err := tc.GetConfig("Migration", tc.Node) + require.NoError(t, err, "Error getting config") + + err = config.ChainlinkUpgradeImage.Validate() + require.NoError(t, err, "Error validating upgrade image") + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestConfig(&config). + WithTestInstance(t). + WithStandardCleanup(). WithGeth(). WithCLNodes(1). + WithStandardCleanup(). Build() require.NoError(t, err) - upgradeImage, err := osutil.GetEnv("UPGRADE_IMAGE") - require.NoError(t, err, "Error getting upgrade image") - upgradeVersion, err := osutil.GetEnv("UPGRADE_VERSION") - require.NoError(t, err, "Error getting upgrade version") - - _ = os.Setenv("CHAINLINK_IMAGE", upgradeImage) - _ = os.Setenv("CHAINLINK_VERSION", upgradeVersion) - // just restarting CL container with the same name, DB is still the same // // [Database] // MigrateOnStartup = true // // by default - err = env.ClCluster.Nodes[0].Restart(env.ClCluster.Nodes[0].NodeConfig) + err = env.ClCluster.Nodes[0].UpgradeVersion(*config.ChainlinkUpgradeImage.Image, *config.ChainlinkUpgradeImage.Version) require.NoError(t, err) + } diff --git a/integration-tests/performance/cron_test.go b/integration-tests/performance/cron_test.go deleted file mode 100644 index 38d861cee07..00000000000 --- a/integration-tests/performance/cron_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package performance - -import ( - "fmt" - "os" - "strings" - "testing" - "time" - - "github.com/google/uuid" - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - - "github.com/smartcontractkit/chainlink-testing-framework/networks" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/testreporters" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" -) - -func TestMain(m *testing.M) { - os.Exit(m.Run()) -} - -func CleanupPerformanceTest( - t *testing.T, - testEnvironment *environment.Environment, - chainlinkNodes []*client.ChainlinkK8sClient, - testReporter testreporters.ChainlinkProfileTestReporter, - chainClient blockchain.EVMClient, -) { - if chainClient != nil { - chainClient.GasStats().PrintStats() - } - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, &testReporter, zapcore.PanicLevel, chainClient) - require.NoError(t, err, "Error tearing down environment") -} - -func TestCronPerformance(t *testing.T) { - testEnvironment := setupCronTest(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - mockServer, err := ctfClient.ConnectMockServer(testEnvironment) - require.NoError(t, err, "Creating mockserver client shouldn't fail") - chainlinkNode := chainlinkNodes[0] - err = mockServer.SetValuePath("/variable", 5) - require.NoError(t, err, "Setting value path in mockserver shouldn't fail") - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - if chainlinkNode != chainlinkNodes[len(chainlinkNodes)-1].ChainlinkClient { - // Not the last node, hence not all nodes started profiling yet. - return - } - bta := &client.BridgeTypeAttributes{ - Name: fmt.Sprintf("variable-%s", uuid.New().String()), - URL: fmt.Sprintf("%s/variable", mockServer.Config.ClusterURL), - RequestData: "{}", - } - err = chainlinkNode.MustCreateBridge(bta) - require.NoError(t, err, "Creating bridge in chainlink node shouldn't fail") - - job, err := chainlinkNode.MustCreateJob(&client.CronJobSpec{ - Schedule: "CRON_TZ=UTC * * * * * *", - ObservationSource: client.ObservationSourceSpecBridge(bta), - }) - require.NoError(t, err, "Creating Cron Job in chainlink node shouldn't fail") - - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - jobRuns, err := chainlinkNode.MustReadRunsByJob(job.Data.ID) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Reading Job run data shouldn't fail") - - g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 5), "Expected number of job runs to be greater than 5, but got %d", len(jobRuns.Data)) - - for _, jr := range jobRuns.Data { - g.Expect(jr.Attributes.Errors).Should(gomega.Equal([]interface{}{nil}), "Job run %s shouldn't have errors", jr.ID) - } - }, "2m", "1s").Should(gomega.Succeed()) - } - - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: 30 * time.Second, - ChainlinkNodes: []*client.ChainlinkK8sClient{chainlinkNode}, - }) - // Register cleanup for any test - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, nil) - }) - profileTest.Setup(testEnvironment) - profileTest.Run() -} - -func setupCronTest(t *testing.T) (testEnvironment *environment.Environment) { - logging.Init() - network := networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := ethereum.New(nil) - if !network.Simulated { - evmConfig = ethereum.New(ðereum.Props{ - NetworkName: network.Name, - Simulated: network.Simulated, - WsURLs: network.URLs, - }) - } - baseTOML := `[WebServer] -HTTPWriteTimout = '300s'` - cd := chainlink.New(0, map[string]interface{}{ - "replicas": 1, - "toml": networks.AddNetworksConfig(baseTOML, network), - }) - - testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-cron-%s", strings.ReplaceAll(strings.ToLower(network.Name), " ", "-")), - Test: t, - PreventPodEviction: true, - }). - AddHelm(mockservercfg.New(nil)). - AddHelm(mockserver.New(nil)). - AddHelm(evmConfig). - AddHelm(cd) - err := testEnvironment.Run() - require.NoError(t, err, "Error launching test environment") - return testEnvironment -} diff --git a/integration-tests/performance/directrequest_test.go b/integration-tests/performance/directrequest_test.go deleted file mode 100644 index 0fe1ca37e15..00000000000 --- a/integration-tests/performance/directrequest_test.go +++ /dev/null @@ -1,160 +0,0 @@ -package performance - -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" - - "github.com/google/uuid" -) - -func TestDirectRequestPerformance(t *testing.T) { - l := logging.GetTestLogger(t) - testEnvironment := setupDirectRequestTest(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - - chainClient, err := blockchain.NewEVMClient(blockchain.SimulatedEVMNetwork, testEnvironment, l) - require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Deploying contracts shouldn't fail") - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - mockServerClient, err := ctfClient.ConnectMockServer(testEnvironment) - require.NoError(t, err, "Error connecting to mock server") - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.01)) - require.NoError(t, err, "Funding chainlink nodes with ETH shouldn't fail") - - lt, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - oracle, err := contractDeployer.DeployOracle(lt.Address()) - require.NoError(t, err, "Deploying Oracle Contract shouldn't fail") - consumer, err := contractDeployer.DeployAPIConsumer(lt.Address()) - require.NoError(t, err, "Deploying Consumer Contract shouldn't fail") - err = chainClient.SetDefaultWallet(0) - require.NoError(t, err, "Setting default wallet shouldn't fail") - err = lt.Transfer(consumer.Address(), big.NewInt(2e18)) - require.NoError(t, err, "Transferring %d to consumer contract shouldn't fail", big.NewInt(2e18)) - - err = mockServerClient.SetValuePath("/variable", 5) - require.NoError(t, err, "Setting mockserver value path shouldn't fail") - - jobUUID := uuid.New() - - bta := client.BridgeTypeAttributes{ - Name: fmt.Sprintf("five-%s", jobUUID.String()), - URL: fmt.Sprintf("%s/variable", mockServerClient.Config.ClusterURL), - } - err = chainlinkNodes[0].MustCreateBridge(&bta) - require.NoError(t, err, "Creating bridge shouldn't fail") - - os := &client.DirectRequestTxPipelineSpec{ - BridgeTypeAttributes: bta, - DataPath: "data,result", - } - ost, err := os.String() - require.NoError(t, err, "Building observation source spec shouldn't fail") - - _, err = chainlinkNodes[0].MustCreateJob(&client.DirectRequestJobSpec{ - Name: "direct_request", - MinIncomingConfirmations: "1", - ContractAddress: oracle.Address(), - EVMChainID: chainClient.GetChainID().String(), - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - }) - require.NoError(t, err, "Creating direct_request job shouldn't fail") - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - if chainlinkNode != chainlinkNodes[len(chainlinkNodes)-1].ChainlinkClient { - // Not the last node, hence not all nodes started profiling yet. - return - } - jobUUIDReplaces := strings.Replace(jobUUID.String(), "-", "", 4) - var jobID [32]byte - copy(jobID[:], jobUUIDReplaces) - err = consumer.CreateRequestTo( - oracle.Address(), - jobID, - big.NewInt(1e18), - fmt.Sprintf("%s/variable", mockServerClient.Config.ClusterURL), - "data,result", - big.NewInt(100), - ) - require.NoError(t, err, "Calling oracle contract shouldn't fail") - - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - d, err := consumer.Data(testcontext.Get(t)) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting data from consumer contract shouldn't fail") - g.Expect(d).ShouldNot(gomega.BeNil(), "Expected the initial on chain data to be nil") - l.Debug().Int64("Data", d.Int64()).Msg("Found on chain") - g.Expect(d.Int64()).Should(gomega.BeNumerically("==", 5), "Expected the on-chain data to be 5, but found %d", d.Int64()) - }, "2m", "1s").Should(gomega.Succeed()) - } - - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: 30 * time.Second, - ChainlinkNodes: chainlinkNodes, - }) - profileTest.Setup(testEnvironment) - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, chainClient) - }) - profileTest.Run() -} - -func setupDirectRequestTest(t *testing.T) (testEnvironment *environment.Environment) { - network := networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := ethereum.New(nil) - if !network.Simulated { - evmConfig = ethereum.New(ðereum.Props{ - NetworkName: network.Name, - Simulated: network.Simulated, - WsURLs: network.URLs, - }) - } - baseTOML := `[WebServer] -HTTPWriteTimout = '300s'` - cd := chainlink.New(0, map[string]interface{}{ - "replicas": 1, - "toml": networks.AddNetworksConfig(baseTOML, network), - }) - - testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-cron-%s", strings.ReplaceAll(strings.ToLower(network.Name), " ", "-")), - Test: t, - PreventPodEviction: true, - }). - AddHelm(mockservercfg.New(nil)). - AddHelm(mockserver.New(nil)). - AddHelm(evmConfig). - AddHelm(cd) - err := testEnvironment.Run() - require.NoError(t, err, "Error launching test environment") - return testEnvironment -} diff --git a/integration-tests/performance/flux_test.go b/integration-tests/performance/flux_test.go deleted file mode 100644 index 5fa31b626ae..00000000000 --- a/integration-tests/performance/flux_test.go +++ /dev/null @@ -1,207 +0,0 @@ -package performance - -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/ethereum/go-ethereum/common" - "github.com/google/uuid" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" -) - -func TestFluxPerformance(t *testing.T) { - l := logging.GetTestLogger(t) - testEnvironment, testNetwork := setupFluxTest(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) - require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Deploying contracts shouldn't fail") - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - nodeAddresses, err := actions.ChainlinkNodeAddresses(chainlinkNodes) - require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") - mockServer, err := ctfClient.ConnectMockServer(testEnvironment) - require.NoError(t, err, "Creating mock server client shouldn't fail") - - chainClient.ParallelTransactions(true) - - adapterUUID := uuid.New().String() - adapterPath := fmt.Sprintf("/variable-%s", adapterUUID) - err = mockServer.SetValuePath(adapterPath, 1e5) - require.NoError(t, err, "Setting mockserver value path shouldn't fail") - - linkToken, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - fluxInstance, err := contractDeployer.DeployFluxAggregatorContract(linkToken.Address(), contracts.DefaultFluxAggregatorOptions()) - require.NoError(t, err, "Deploying Flux Aggregator Contract shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for deployment of flux aggregator contract") - - err = linkToken.Transfer(fluxInstance.Address(), big.NewInt(1e18)) - require.NoError(t, err, "Funding Flux Aggregator Contract shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Failed waiting for funding of flux aggregator contract") - - err = fluxInstance.UpdateAvailableFunds() - require.NoError(t, err, "Updating the available funds on the Flux Aggregator Contract shouldn't fail") - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.02)) - require.NoError(t, err, "Funding chainlink nodes with ETH shouldn't fail") - - err = fluxInstance.SetOracles( - contracts.FluxAggregatorSetOraclesOptions{ - AddList: nodeAddresses, - RemoveList: []common.Address{}, - AdminList: nodeAddresses, - MinSubmissions: 3, - MaxSubmissions: 3, - RestartDelayRounds: 0, - }) - require.NoError(t, err, "Setting oracle options in the Flux Aggregator contract shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - oracles, err := fluxInstance.GetOracles(testcontext.Get(t)) - require.NoError(t, err, "Getting oracle details from the Flux aggregator contract shouldn't fail") - l.Info().Str("Oracles", strings.Join(oracles, ",")).Msg("Oracles set") - - adapterFullURL := fmt.Sprintf("%s%s", mockServer.Config.ClusterURL, adapterPath) - bta := &client.BridgeTypeAttributes{ - Name: fmt.Sprintf("variable-%s", adapterUUID), - URL: adapterFullURL, - } - for i, n := range chainlinkNodes { - err = n.MustCreateBridge(bta) - require.NoError(t, err, "Creating bridge shouldn't fail for node %d", i+1) - - fluxSpec := &client.FluxMonitorJobSpec{ - Name: fmt.Sprintf("flux-monitor-%s", adapterUUID), - ContractAddress: fluxInstance.Address(), - EVMChainID: chainClient.GetChainID().String(), - Threshold: 0, - AbsoluteThreshold: 0, - PollTimerPeriod: 15 * time.Second, // min 15s - IdleTimerDisabled: true, - ObservationSource: client.ObservationSourceSpecBridge(bta), - } - _, err = n.MustCreateJob(fluxSpec) - require.NoError(t, err, "Creating flux job shouldn't fail for node %d", i+1) - } - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - if chainlinkNode != chainlinkNodes[len(chainlinkNodes)-1].ChainlinkClient { - // Not the last node, hence not all nodes started profiling yet. - return - } - fluxRoundTimeout := 2 * time.Minute - fluxRound := contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(1), fluxRoundTimeout, l) - chainClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) - err = chainClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err := fluxInstance.GetContractData(testcontext.Get(t)) - require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") - l.Info().Interface("Data", data).Msg("Round data") - require.Equal(t, int64(1e5), data.LatestRoundData.Answer.Int64(), - "Expected latest round answer to be %d, but found %d", int64(1e5), data.LatestRoundData.Answer.Int64()) - require.Equal(t, int64(1), data.LatestRoundData.RoundId.Int64(), - "Expected latest round id to be %d, but found %d", int64(1), data.LatestRoundData.RoundId.Int64()) - require.Equal(t, int64(1), data.LatestRoundData.AnsweredInRound.Int64(), - "Expected latest round's answered in round to be %d, but found %d", int64(1), data.LatestRoundData.AnsweredInRound.Int64()) - require.Equal(t, int64(999999999999999997), data.AvailableFunds.Int64(), - "Expected available funds to be %d, but found %d", int64(999999999999999997), data.AvailableFunds.Int64()) - require.Equal(t, int64(3), data.AllocatedFunds.Int64(), - "Expected allocated funds to be %d, but found %d", int64(3), data.AllocatedFunds.Int64()) - - fluxRound = contracts.NewFluxAggregatorRoundConfirmer(fluxInstance, big.NewInt(2), fluxRoundTimeout, l) - chainClient.AddHeaderEventSubscription(fluxInstance.Address(), fluxRound) - err = mockServer.SetValuePath(adapterPath, 1e10) - require.NoError(t, err, "Setting value path in mock server shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - data, err = fluxInstance.GetContractData(testcontext.Get(t)) - require.NoError(t, err, "Getting contract data from flux aggregator contract shouldn't fail") - require.Equal(t, int64(1e10), data.LatestRoundData.Answer.Int64(), - "Expected latest round answer to be %d, but found %d", int64(1e10), data.LatestRoundData.Answer.Int64()) - require.Equal(t, int64(2), data.LatestRoundData.RoundId.Int64(), - "Expected latest round id to be %d, but found %d", int64(2), data.LatestRoundData.RoundId.Int64()) - require.Equal(t, int64(999999999999999994), data.AvailableFunds.Int64(), - "Expected available funds to be %d, but found %d", int64(999999999999999994), data.AvailableFunds.Int64()) - require.Equal(t, int64(6), data.AllocatedFunds.Int64(), - "Expected allocated funds to be %d, but found %d", int64(6), data.AllocatedFunds.Int64()) - l.Info().Interface("data", data).Msg("Round data") - - for _, oracleAddr := range nodeAddresses { - payment, _ := fluxInstance.WithdrawablePayment(testcontext.Get(t), oracleAddr) - require.Equal(t, int64(2), payment.Int64(), - "Expected flux aggregator contract's withdrawable payment to be %d, but found %d", int64(2), payment.Int64()) - } - } - - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: 30 * time.Second, - ChainlinkNodes: chainlinkNodes, - }) - // Register cleanup - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, chainClient) - }) - profileTest.Setup(testEnvironment) - profileTest.Run() -} - -func setupFluxTest(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] - evmConf := ethereum.New(nil) - if !testNetwork.Simulated { - evmConf = ethereum.New(ðereum.Props{ - NetworkName: testNetwork.Name, - Simulated: testNetwork.Simulated, - WsURLs: testNetwork.URLs, - }) - } - baseTOML := `[WebServer] -HTTPWriteTimout = '300s' - -[OCR] -Enabled = true` - cd := chainlink.New(0, map[string]interface{}{ - "replicas": 3, - "toml": networks.AddNetworksConfig(baseTOML, testNetwork), - }) - - testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-flux-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), - Test: t, - PreventPodEviction: true, - }). - AddHelm(mockservercfg.New(nil)). - AddHelm(mockserver.New(nil)). - AddHelm(evmConf). - AddHelm(cd) - err := testEnvironment.Run() - require.NoError(t, err, "Error running test environment") - return testEnvironment, testNetwork -} diff --git a/integration-tests/performance/keeper_test.go b/integration-tests/performance/keeper_test.go deleted file mode 100644 index ac6e9e6a579..00000000000 --- a/integration-tests/performance/keeper_test.go +++ /dev/null @@ -1,194 +0,0 @@ -package performance - -//revive:disable:dot-imports -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - eth "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" -) - -var keeperDefaultRegistryConfig = contracts.KeeperRegistrySettings{ - PaymentPremiumPPB: uint32(200000000), - FlatFeeMicroLINK: uint32(0), - BlockCountPerTurn: big.NewInt(10), - CheckGasLimit: uint32(2500000), - StalenessSeconds: big.NewInt(90000), - GasCeilingMultiplier: uint16(1), - MinUpkeepSpend: big.NewInt(0), - MaxPerformGas: uint32(5000000), - FallbackGasPrice: big.NewInt(2e11), - FallbackLinkPrice: big.NewInt(2e18), - MaxCheckDataSize: uint32(5000), - MaxPerformDataSize: uint32(5000), -} - -func TestKeeperPerformance(t *testing.T) { - l := logging.GetTestLogger(t) - testEnvironment, chainClient, chainlinkNodes, contractDeployer, linkToken := setupKeeperTest(t, "basic-smoke") - if testEnvironment.WillUseRemoteRunner() { - return - } - registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( - t, - ethereum.RegistryVersion_1_1, - keeperDefaultRegistryConfig, - 1, - uint32(2500000), - linkToken, - contractDeployer, - chainClient, - big.NewInt(9e18), - ) - gom := gomega.NewGomegaWithT(t) - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - if chainlinkNode != chainlinkNodes[len(chainlinkNodes)-1].ChainlinkClient { - // Not the last node, hence not all nodes started profiling yet. - return - } - actions.CreateKeeperJobs(t, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) - err := chainClient.WaitForEvents() - require.NoError(t, err, "Error creating keeper jobs") - - gom.Eventually(func(g gomega.Gomega) { - // Check if the upkeeps are performing multiple times by analysing their counters and checking they are greater than 10 - for i := 0; i < len(upkeepIDs); i++ { - counter, err := consumers[i].Counter(testcontext.Get(t)) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Failed to retrieve consumer counter for upkeep at index %d", i) - g.Expect(counter.Int64()).Should(gomega.BeNumerically(">", int64(10)), - "Expected consumer counter to be greater than 10, but got %d", counter.Int64()) - l.Info().Int64("Upkeep counter", counter.Int64()).Msg("Number of upkeeps performed") - } - }, "5m", "1s").Should(gomega.Succeed()) - - // Cancel all the registered upkeeps via the registry - for i := 0; i < len(upkeepIDs); i++ { - err = registry.CancelUpkeep(upkeepIDs[i]) - require.NoError(t, err, "Could not cancel upkeep at index %d", i) - } - - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for upkeeps to be cancelled") - - var countersAfterCancellation = make([]*big.Int, len(upkeepIDs)) - - for i := 0; i < len(upkeepIDs); i++ { - // Obtain the amount of times the upkeep has been executed so far - countersAfterCancellation[i], err = consumers[i].Counter(testcontext.Get(t)) - require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) - l.Info().Int("Index", i).Int64("Upkeeps Performed", countersAfterCancellation[i].Int64()).Msg("Cancelled Upkeep") - } - - gom.Consistently(func(g gomega.Gomega) { - for i := 0; i < len(upkeepIDs); i++ { - // Expect the counter to remain constant because the upkeep was cancelled, so it shouldn't increase anymore - latestCounter, err := consumers[i].Counter(testcontext.Get(t)) - require.NoError(t, err, "Failed to retrieve consumer counter for upkeep at index %d", i) - g.Expect(latestCounter.Int64()).Should(gomega.Equal(countersAfterCancellation[i].Int64()), - "Expected consumer counter to remain constant at %d, but got %d", - countersAfterCancellation[i].Int64(), latestCounter.Int64()) - } - }, "1m", "1s").Should(gomega.Succeed()) - } - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: 10 * time.Second, - ChainlinkNodes: chainlinkNodes, - }) - // Register cleanup - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, chainClient) - }) - profileTest.Setup(testEnvironment) - profileTest.Run() -} - -func setupKeeperTest( - t *testing.T, - testName string, -) ( - *environment.Environment, - blockchain.EVMClient, - []*client.ChainlinkK8sClient, - contracts.ContractDeployer, - contracts.LinkToken, -) { - network := networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := eth.New(nil) - if !network.Simulated { - evmConfig = eth.New(ð.Props{ - NetworkName: network.Name, - Simulated: network.Simulated, - WsURLs: network.URLs, - }) - } - baseTOML := `[WebServer] -HTTPWriteTimout = '300s' - -[Keeper] -TurnLookBack = 0 - -[Keeper.Registry] -SyncInterval = '5s' -PerformGasOverhead = 150_000` - networkName := strings.ReplaceAll(strings.ToLower(network.Name), " ", "-") - cd := chainlink.New(0, map[string]interface{}{ - "replicas": 5, - "toml": networks.AddNetworksConfig(baseTOML, network), - }) - - testEnvironment := environment.New( - &environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-keeper-%s-%s", testName, networkName), - Test: t, - PreventPodEviction: true, - }, - ). - AddHelm(mockservercfg.New(nil)). - AddHelm(mockserver.New(nil)). - AddHelm(evmConfig). - AddHelm(cd) - err := testEnvironment.Run() - require.NoError(t, err, "Error deploying test environment") - if testEnvironment.WillUseRemoteRunner() { - return testEnvironment, nil, nil, nil, nil - } - - l := logging.GetTestLogger(t) - chainClient, err := blockchain.NewEVMClient(network, testEnvironment, l) - require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Deploying contracts shouldn't fail") - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - chainClient.ParallelTransactions(true) - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.5)) - require.NoError(t, err, "Funding Chainlink nodes shouldn't fail") - - linkToken, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - - return testEnvironment, chainClient, chainlinkNodes, contractDeployer, linkToken -} diff --git a/integration-tests/performance/ocr_test.go b/integration-tests/performance/ocr_test.go deleted file mode 100644 index 2c339c04ddf..00000000000 --- a/integration-tests/performance/ocr_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package performance - -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" -) - -func TestOCRBasic(t *testing.T) { - t.Parallel() - testEnvironment, testNetwork := setupOCRTest(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - l := logging.GetTestLogger(t) - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) - require.NoError(t, err, "Connecting to blockchain nodes shouldn't fail") - contractDeployer, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Deploying contracts shouldn't fail") - - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - bootstrapNode, workerNodes := chainlinkNodes[0], chainlinkNodes[1:] - mockServer, err := ctfClient.ConnectMockServer(testEnvironment) - require.NoError(t, err, "Creating mockserver clients shouldn't fail") - - chainClient.ParallelTransactions(true) - - linkTokenContract, err := contractDeployer.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.05)) - require.NoError(t, err, "Error funding Chainlink nodes") - - ocrInstances, err := actions.DeployOCRContracts(1, linkTokenContract, contractDeployer, workerNodes, chainClient) - require.NoError(t, err) - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error waiting for events") - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, mockServer, chainClient.GetChainID().String()) - require.NoError(t, err) - err = actions.StartNewRound(1, ocrInstances, chainClient, l) - require.NoError(t, err) - - answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) - require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") - require.Equal(t, int64(5), answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) - - err = mockServer.SetValuePath("ocr", 10) - require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, chainClient, l) - require.NoError(t, err) - - answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest OCR answer") - require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) - } - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: time.Minute, - ChainlinkNodes: chainlinkNodes, - }) - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, chainClient) - }) - profileTest.Setup(testEnvironment) - profileTest.Run() -} - -func setupOCRTest(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := ethereum.New(nil) - if !testNetwork.Simulated { - evmConfig = ethereum.New(ðereum.Props{ - NetworkName: testNetwork.Name, - Simulated: testNetwork.Simulated, - WsURLs: testNetwork.URLs, - }) - } - baseTOML := `[OCR] -Enabled = true - -[P2P] -[P2P.V2] -Enabled = false - -[P2P] -[P2P.V2] -AnnounceAddresses = ["0.0.0.0:6690"] -ListenAddresses = ["0.0.0.0:6690"]` - - cd := chainlink.New(0, map[string]interface{}{ - "replicas": 6, - "toml": networks.AddNetworksConfig(baseTOML, testNetwork), - }) - - testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("performance-ocr-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), - Test: t, - PreventPodEviction: true, - }). - AddHelm(mockservercfg.New(nil)). - AddHelm(mockserver.New(nil)). - AddHelm(evmConfig). - AddHelm(cd) - err := testEnvironment.Run() - require.NoError(t, err, "Error running test environment") - return testEnvironment, testNetwork -} diff --git a/integration-tests/performance/vrf_test.go b/integration-tests/performance/vrf_test.go deleted file mode 100644 index cad4ea5eebd..00000000000 --- a/integration-tests/performance/vrf_test.go +++ /dev/null @@ -1,163 +0,0 @@ -package performance - -import ( - "fmt" - "math/big" - "strings" - "testing" - "time" - - "github.com/google/uuid" - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" -) - -func TestVRFBasic(t *testing.T) { - t.Parallel() - l := logging.GetTestLogger(t) - testEnvironment, testNetwork := setupVRFTest(t) - if testEnvironment.WillUseRemoteRunner() { - return - } - - chainClient, err := blockchain.NewEVMClient(testNetwork, testEnvironment, l) - require.NoError(t, err, "Connecting client shouldn't fail") - cd, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Deploying contracts shouldn't fail") - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Connecting to chainlink nodes shouldn't fail") - chainClient.ParallelTransactions(true) - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(.01)) - require.NoError(t, err, "Funding chainlink nodes with ETH shouldn't fail") - - lt, err := cd.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - bhs, err := cd.DeployBlockhashStore() - require.NoError(t, err, "Deploying Blockhash store shouldn't fail") - coordinator, err := cd.DeployVRFCoordinator(lt.Address(), bhs.Address()) - require.NoError(t, err, "Deploying VRF coordinator shouldn't fail") - consumer, err := cd.DeployVRFConsumer(lt.Address(), coordinator.Address()) - require.NoError(t, err, "Deploying VRF consumer contract shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Failed to wait for VRF setup contracts to deploy") - - err = lt.Transfer(consumer.Address(), big.NewInt(2e18)) - require.NoError(t, err, "Funding consumer contract shouldn't fail") - _, err = cd.DeployVRFContract() - require.NoError(t, err, "Deploying VRF contract shouldn't fail") - err = chainClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") - - profileFunction := func(chainlinkNode *client.ChainlinkClient) { - nodeKey, err := chainlinkNode.MustCreateVRFKey() - require.NoError(t, err, "Creating VRF key shouldn't fail") - l.Debug().Interface("Key JSON", nodeKey).Msg("Created proving key") - pubKeyCompressed := nodeKey.Data.ID - jobUUID := uuid.New() - os := &client.VRFTxPipelineSpec{ - Address: coordinator.Address(), - } - ost, err := os.String() - require.NoError(t, err, "Building observation source spec shouldn't fail") - job, err := chainlinkNode.MustCreateJob(&client.VRFJobSpec{ - Name: fmt.Sprintf("vrf-%s", jobUUID), - CoordinatorAddress: coordinator.Address(), - MinIncomingConfirmations: 1, - PublicKey: pubKeyCompressed, - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - }) - require.NoError(t, err, "Creating VRF Job shouldn't fail") - - oracleAddr, err := chainlinkNode.PrimaryEthAddress() - require.NoError(t, err, "Getting primary ETH address of chainlink node shouldn't fail") - provingKey, err := actions.EncodeOnChainVRFProvingKey(*nodeKey) - require.NoError(t, err, "Encoding on-chain VRF Proving key shouldn't fail") - err = coordinator.RegisterProvingKey( - big.NewInt(1), - oracleAddr, - provingKey, - actions.EncodeOnChainExternalJobID(jobUUID), - ) - require.NoError(t, err, "Registering the on-chain VRF Proving key shouldn't fail") - encodedProvingKeys := make([][2]*big.Int, 0) - encodedProvingKeys = append(encodedProvingKeys, provingKey) - - requestHash, err := coordinator.HashOfKey(testcontext.Get(t), encodedProvingKeys[0]) - require.NoError(t, err, "Getting Hash of encoded proving keys shouldn't fail") - err = consumer.RequestRandomness(requestHash, big.NewInt(1)) - require.NoError(t, err, "Requesting randomness shouldn't fail") - - gom := gomega.NewGomegaWithT(t) - timeout := time.Minute * 2 - gom.Eventually(func(g gomega.Gomega) { - jobRuns, err := chainlinkNodes[0].MustReadRunsByJob(job.Data.ID) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Job execution shouldn't fail") - - out, err := consumer.RandomnessOutput(testcontext.Get(t)) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting the randomness output of the consumer shouldn't fail") - // Checks that the job has actually run - g.Expect(len(jobRuns.Data)).Should(gomega.BeNumerically(">=", 1), - fmt.Sprintf("Expected the VRF job to run once or more after %s", timeout)) - - // TODO: This is an imperfect check, given it's a random number, it CAN be 0, but chances are unlikely. - // So we're just checking that the answer has changed to something other than the default (0) - // There's a better formula to ensure that VRF response is as expected, detailed under Technical Walkthrough. - // https://blog.chain.link/chainlink-vrf-on-chain-verifiable-randomness/ - g.Expect(out.Uint64()).ShouldNot(gomega.BeNumerically("==", 0), "Expected the VRF job give an answer other than 0") - l.Debug().Uint64("Output", out.Uint64()).Msg("Randomness fulfilled") - }, timeout, "1s").Should(gomega.Succeed()) - } - profileTest := testsetups.NewChainlinkProfileTest(testsetups.ChainlinkProfileTestInputs{ - ProfileFunction: profileFunction, - ProfileDuration: 30 * time.Second, - ChainlinkNodes: chainlinkNodes, - }) - t.Cleanup(func() { - CleanupPerformanceTest(t, testEnvironment, chainlinkNodes, profileTest.TestReporter, chainClient) - }) - profileTest.Setup(testEnvironment) - profileTest.Run() -} - -func setupVRFTest(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] - evmConfig := ethereum.New(nil) - if !testNetwork.Simulated { - evmConfig = ethereum.New(ðereum.Props{ - NetworkName: testNetwork.Name, - Simulated: testNetwork.Simulated, - WsURLs: testNetwork.URLs, - }) - } - baseTOML := `[WebServer] -HTTPWriteTimout = '300s'` - cd := chainlink.New(0, map[string]interface{}{ - "toml": networks.AddNetworksConfig(baseTOML, testNetwork), - }) - - testEnvironment = environment.New(&environment.Config{ - NamespacePrefix: fmt.Sprintf("smoke-vrf-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), - Test: t, - PreventPodEviction: true, - }). - AddHelm(evmConfig). - AddHelm(cd) - err := testEnvironment.Run() - require.NoError(t, err, "Error running test environment") - return testEnvironment, testNetwork -} diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index dae977d3eea..36b5d3eb985 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -12,6 +12,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" @@ -24,6 +25,8 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) var ( @@ -47,9 +50,9 @@ HistoryDepth = 400 [EVM.GasEstimator] Mode = 'FixedPrice' LimitDefault = 5_000_000` - activeEVMNetwork = networks.MustGetSelectedNetworksFromEnv()[0] + defaultAutomationSettings = map[string]interface{}{ - "toml": networks.AddNetworkDetailedConfig(baseTOML, networkTOML, activeEVMNetwork), + "toml": "", "db": map[string]interface{}{ "stateful": false, "capacity": "1Gi", @@ -67,7 +70,7 @@ LimitDefault = 5_000_000` } defaultReorgEthereumSettings = &reorg.Props{ - NetworkName: activeEVMNetwork.Name, + NetworkName: "", NetworkType: "geth-reorg", Values: map[string]interface{}{ "geth": map[string]interface{}{ @@ -126,9 +129,9 @@ func TestAutomationReorg(t *testing.T) { l := logging.GetTestLogger(t) registryVersions := map[string]ethereum.KeeperRegistryVersion{ - "registry_2_0": ethereum.RegistryVersion_2_0, - "registry_2_1_conditional": ethereum.RegistryVersion_2_1, - "registry_2_1_logtrigger": ethereum.RegistryVersion_2_1, + "registry_2_0": ethereum.RegistryVersion_2_0, + // "registry_2_1_conditional": ethereum.RegistryVersion_2_1, + // "registry_2_1_logtrigger": ethereum.RegistryVersion_2_1, } for name, registryVersion := range registryVersions { @@ -136,22 +139,38 @@ func TestAutomationReorg(t *testing.T) { registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() - network := networks.MustGetSelectedNetworksFromEnv()[0] + config, err := tc.GetConfig("Reorg", tc.Automation) + if err != nil { + t.Fatal(err) + } + + network := networks.MustGetSelectedNetworkConfig(config.Network)[0] defaultAutomationSettings["replicas"] = numberOfNodes - cd := chainlink.New(0, defaultAutomationSettings) + defaultAutomationSettings["toml"] = networks.AddNetworkDetailedConfig(baseTOML, config.Pyroscope, networkTOML, network) + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(config.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(config.Pyroscope, target) + } + + cd := chainlink.NewWithOverride(0, defaultAutomationSettings, config.ChainlinkImage, overrideFn) + + ethSetting := defaultReorgEthereumSettings + ethSetting.NetworkName = network.Name + testEnvironment := environment. New(&environment.Config{ NamespacePrefix: fmt.Sprintf("automation-reorg-%d", automationReorgBlocks), TTL: time.Hour * 1, Test: t}). - AddHelm(reorg.New(defaultReorgEthereumSettings)). + AddHelm(reorg.New(ethSetting)). AddChart(blockscout.New(&blockscout.Props{ Name: "geth-blockscout", - WsURL: activeEVMNetwork.URL, - HttpURL: activeEVMNetwork.HTTPURLs[0]})). + WsURL: network.URL, + HttpURL: network.HTTPURLs[0]})). AddHelm(cd) - err := testEnvironment.Run() + err = testEnvironment.Run() require.NoError(t, err, "Error setting up test environment") if testEnvironment.WillUseRemoteRunner() { @@ -168,7 +187,7 @@ func TestAutomationReorg(t *testing.T) { // Register cleanup for any test t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, &config, chainClient) require.NoError(t, err, "Error tearing down environment") }) diff --git a/integration-tests/reorg/log_poller_maybe_reorg_test.go b/integration-tests/reorg/log_poller_maybe_reorg_test.go deleted file mode 100644 index d319e39aa20..00000000000 --- a/integration-tests/reorg/log_poller_maybe_reorg_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package reorg - -import ( - "testing" - - "github.com/ethereum/go-ethereum/accounts/abi" - - logpoller "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" -) - -func TestLogPollerFromEnv(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 100, - UseFinalityTag: true, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 400, - MaxEmitWaitTimeMs: 600, - }, - }, - } - - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } - - cfg.General.EventsToEmit = eventsToEmit - err := cfg.OverrideFromEnv() - if err != nil { - t.Errorf("failed to override config from env: %v", err) - t.FailNow() - } - - logpoller.ExecuteCILogPollerTest(t, &cfg) -} diff --git a/integration-tests/reorg/reorg_test.go b/integration-tests/reorg/reorg_test.go deleted file mode 100644 index fc35047d0e4..00000000000 --- a/integration-tests/reorg/reorg_test.go +++ /dev/null @@ -1,228 +0,0 @@ -package reorg - -import ( - "fmt" - "math/big" - "os" - "strings" - "testing" - "time" - - "github.com/google/uuid" - "github.com/onsi/gomega" - "github.com/rs/zerolog/log" - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/cdk8s/blockscout" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver" - mockservercfg "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/mockserver-cfg" - "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/reorg" - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/networks" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" -) - -const ( - baseDRTOML = ` -[Feature] -LogPoller = true -` - networkDRTOML = ` -Enabled = true -FinalityDepth = %s -LogPollInterval = '1s' - -[EVM.HeadTracker] -HistoryDepth = %s -` -) - -const ( - EVMFinalityDepth = "200" - EVMTrackerHistoryDepth = "400" - reorgBlocks = 10 - minIncomingConfirmations = "200" - timeout = "15m" - interval = "2s" -) - -var ( - networkSettings = blockchain.EVMNetwork{ - Name: "geth", - Simulated: true, - ChainID: 1337, - PrivateKeys: []string{ - "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", - }, - ChainlinkTransactionLimit: 500000, - Timeout: blockchain.JSONStrDuration{Duration: 2 * time.Minute}, - MinimumConfirmations: 1, - GasEstimationBuffer: 10000, - } -) - -func TestMain(m *testing.M) { - os.Exit(m.Run()) -} - -func CleanupReorgTest( - t *testing.T, - testEnvironment *environment.Environment, - chainlinkNodes []*client.ChainlinkK8sClient, - chainClient blockchain.EVMClient, -) { - if chainClient != nil { - chainClient.GasStats().PrintStats() - } - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.PanicLevel, chainClient) - require.NoError(t, err, "Error tearing down environment") -} - -func TestDirectRequestReorg(t *testing.T) { - logging.Init() - l := logging.GetTestLogger(t) - testEnvironment := environment.New(&environment.Config{ - TTL: 1 * time.Hour, - Test: t, - }) - err := testEnvironment. - AddHelm(mockservercfg.New(nil)). - AddHelm(mockserver.New(nil)). - AddChart(blockscout.New(&blockscout.Props{ - WsURL: "ws://geth-ethereum-geth:8546", - HttpURL: "http://geth-ethereum-geth:8544", - })). - AddHelm(reorg.New(&reorg.Props{ - NetworkName: "geth", - NetworkType: "geth-reorg", - Values: map[string]interface{}{ - "geth": map[string]interface{}{ - "genesis": map[string]interface{}{ - "networkId": "1337", - }, - }, - }, - })). - Run() - require.NoError(t, err, "Error deploying test environment") - if testEnvironment.WillUseRemoteRunner() { - return - } - - // related https://app.shortcut.com/chainlinklabs/story/38295/creating-an-evm-chain-via-cli-or-api-immediately-polling-the-nodes-and-returning-an-error - // node must work and reconnect even if network is not working - time.Sleep(90 * time.Second) - activeEVMNetwork = networks.SimulatedEVMNonDev - netCfg := fmt.Sprintf(networkDRTOML, EVMFinalityDepth, EVMTrackerHistoryDepth) - chainlinkDeployment := chainlink.New(0, map[string]interface{}{ - "replicas": 1, - "toml": networks.AddNetworkDetailedConfig(baseDRTOML, netCfg, activeEVMNetwork), - }) - - err = testEnvironment.AddHelm(chainlinkDeployment).Run() - require.NoError(t, err, "Error adding to test environment") - - chainClient, err := blockchain.NewEVMClient(networkSettings, testEnvironment, l) - require.NoError(t, err, "Error connecting to blockchain") - cd, err := contracts.NewContractDeployer(chainClient, l) - require.NoError(t, err, "Error building contract deployer") - chainlinkNodes, err := client.ConnectChainlinkNodes(testEnvironment) - require.NoError(t, err, "Error connecting to Chainlink nodes") - ms, err := ctfClient.ConnectMockServer(testEnvironment) - require.NoError(t, err, "Error connecting to Mockserver") - - t.Cleanup(func() { - CleanupReorgTest(t, testEnvironment, chainlinkNodes, chainClient) - }) - - err = actions.FundChainlinkNodes(chainlinkNodes, chainClient, big.NewFloat(10)) - require.NoError(t, err, "Error funding Chainlink nodes") - - lt, err := cd.DeployLinkTokenContract() - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - oracle, err := cd.DeployOracle(lt.Address()) - require.NoError(t, err, "Deploying Oracle Contract shouldn't fail") - consumer, err := cd.DeployAPIConsumer(lt.Address()) - require.NoError(t, err, "Deploying Consumer Contract shouldn't fail") - err = chainClient.SetDefaultWallet(0) - require.NoError(t, err, "Setting default wallet shouldn't fail") - err = lt.Transfer(consumer.Address(), big.NewInt(2e18)) - require.NoError(t, err, "Transferring %d to consumer contract shouldn't fail", big.NewInt(2e18)) - - err = ms.SetValuePath("/variable", 5) - require.NoError(t, err, "Setting mockserver value path shouldn't fail") - - jobUUID := uuid.New() - - bta := client.BridgeTypeAttributes{ - Name: fmt.Sprintf("five-%s", jobUUID.String()), - URL: fmt.Sprintf("%s/variable", ms.Config.ClusterURL), - } - err = chainlinkNodes[0].MustCreateBridge(&bta) - require.NoError(t, err, "Creating bridge shouldn't fail") - - drps := &client.DirectRequestTxPipelineSpec{ - BridgeTypeAttributes: bta, - DataPath: "data,result", - } - ost, err := drps.String() - require.NoError(t, err, "Building observation source spec shouldn't fail") - - _, err = chainlinkNodes[0].MustCreateJob(&client.DirectRequestJobSpec{ - Name: "direct_request", - MinIncomingConfirmations: minIncomingConfirmations, - ContractAddress: oracle.Address(), - EVMChainID: chainClient.GetChainID().String(), - ExternalJobID: jobUUID.String(), - ObservationSource: ost, - }) - require.NoError(t, err, "Creating direct_request job shouldn't fail") - - rc, err := NewReorgController( - &ReorgConfig{ - FromPodLabel: reorg.TXNodesAppLabel, - ToPodLabel: reorg.MinerNodesAppLabel, - Network: chainClient, - Env: testEnvironment, - BlockConsensusThreshold: 3, - Timeout: 1800 * time.Second, - }, - ) - require.NoError(t, err, "Error getting reorg controller") - rc.ReOrg(reorgBlocks) - rc.WaitReorgStarted() - - jobUUIDReplaces := strings.Replace(jobUUID.String(), "-", "", 4) - var jobID [32]byte - copy(jobID[:], jobUUIDReplaces) - err = consumer.CreateRequestTo( - oracle.Address(), - jobID, - big.NewInt(1e18), - fmt.Sprintf("%s/variable", ms.Config.ClusterURL), - "data,result", - big.NewInt(100), - ) - require.NoError(t, err, "Calling oracle contract shouldn't fail") - - err = rc.WaitDepthReached() - require.NoError(t, err, "Error waiting for depth to be reached") - - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - d, err := consumer.Data(testcontext.Get(t)) - g.Expect(err).ShouldNot(gomega.HaveOccurred(), "Getting data from consumer contract shouldn't fail") - g.Expect(d).ShouldNot(gomega.BeNil(), "Expected the initial on chain data to be nil") - log.Debug().Int64("Data", d.Int64()).Msg("Found on chain") - g.Expect(d.Int64()).Should(gomega.BeNumerically("==", 5), "Expected the on-chain data to be 5, but found %d", d.Int64()) - }, timeout, interval).Should(gomega.Succeed()) -} diff --git a/integration-tests/scripts/buildTestMatrixList.sh b/integration-tests/scripts/buildTestMatrixList.sh index 7f058b5b659..f02362aa47a 100755 --- a/integration-tests/scripts/buildTestMatrixList.sh +++ b/integration-tests/scripts/buildTestMatrixList.sh @@ -40,24 +40,26 @@ jq -c '.tests[]' ${JSONFILE} | while read -r test; do effective_node_count=${node_count:-$NODE_COUNT} subTests=$(echo ${test} | jq -r '.run[]?.name // empty') output="" + + if [ $COUNTER -ne 1 ]; then + echo -n "," + fi # Loop through subtests, if any, and print in the desired format if [ -n "$subTests" ]; then + subTestString="" + subTestCounter=1 for subTest in $subTests; do - if [ $COUNTER -ne 1 ]; then - echo -n "," + if [ $subTestCounter -ne 1 ]; then + subTestString+="|" fi - matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}/${subTest}" ${effective_node_label} ${effective_node_count} - ((COUNTER++)) + subTestString+="${testName}\/${subTest}" + ((subTestCounter++)) done - else - if [ $COUNTER -ne 1 ]; then - echo -n "," - fi - matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}" ${effective_node_label} ${effective_node_count} - ((COUNTER++)) + testName="${subTestString}" fi - + matrix_output $COUNTER $MATRIX_JOB_NAME "${testName}" ${effective_node_label} ${effective_node_count} + ((COUNTER++)) done > "./tmpout.json" OUTPUT=$(cat ./tmpout.json) echo "[${OUTPUT}]" diff --git a/integration-tests/scripts/buildTests b/integration-tests/scripts/buildTests index edf4043ce1c..749bb545110 100755 --- a/integration-tests/scripts/buildTests +++ b/integration-tests/scripts/buildTests @@ -21,6 +21,6 @@ OIFS=$IFS IFS=' ' for x in $tosplit do - go test -c ./"${x}" + go test -c -tags embed ./"${x}" done IFS=$OIFS diff --git a/integration-tests/scripts/entrypoint b/integration-tests/scripts/entrypoint index cb5c98fde6a..8797765ab2c 100755 --- a/integration-tests/scripts/entrypoint +++ b/integration-tests/scripts/entrypoint @@ -24,7 +24,11 @@ echo "Test exit code: ${exit_code}" # 3 is the code for an interrupted test, we only want to restart the test when the test is interrupted and in a state # that it can recover from. Otherwise we mark the test as "passed" as far as K8s is concerned so it doesn't restart it. if [ $exit_code -eq 3 ]; then +echo "Test was interrupted, exiting with 1 exit code to trigger K8s to restart" exit 1 # Exiting with non-zero status to trigger pod restart +else + echo "Test either panicked or had some sort of failure. We're exiting with a non-zero exit code so that K8s doesn't restart the pod." + echo "TEST_FAILED" fi # Sleep for the amount of time provided by the POST_RUN_SLEEP env var @@ -38,3 +42,6 @@ fi if [ -n "${UPLOAD_MEM_PROFILE}" ]; then upload_to_slack memprofile.out "MEM Profile for ${TEST_NAME}" fi + +echo "Exiting with 0 exit code as test is either completed, or failed and cannot be restarted" +exit 0 \ No newline at end of file diff --git a/integration-tests/scripts/search_and_delete.sh b/integration-tests/scripts/search_and_delete.sh new file mode 100755 index 00000000000..ae1f8a6e70a --- /dev/null +++ b/integration-tests/scripts/search_and_delete.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +if [ $# -eq 0 ]; then + read -p "Enter the comma-separated list of filenames to search for: " filenames +else + filenames=$@ +fi + +IFS=',' read -ra filenames_arr <<< "$filenames" + +# Start search from the current working directory +current_dir=$(pwd) + +echo "Searching for files in $current_dir..." +found_files=() +for filename in "${filenames_arr[@]}"; do + while IFS= read -r file; do + found_files+=("$file") + done < <(find "$current_dir" -type f -name "$filename" 2>/dev/null) +done + +if [[ ${#found_files[@]} -eq 0 ]]; then + echo "No files found." + exit 0 +fi + +echo "Found files:" +for file in "${found_files[@]}"; do + echo "$file" +done + +read -p "Do you want to remove all these files? (y/n): " confirm + +if [[ $confirm == "yes" ]] || [[ $confirm == "y" ]]; then + for file in "${found_files[@]}"; do + rm "$file" + done + echo "Files removed." +else + echo "Files not removed." +fi \ No newline at end of file diff --git a/integration-tests/smoke/README.md b/integration-tests/smoke/README.md index 1dedc4e3840..266720c7bc6 100644 --- a/integration-tests/smoke/README.md +++ b/integration-tests/smoke/README.md @@ -52,18 +52,32 @@ Here is an example for 3 nodes cluster ``` ### Running against Live Testnets +1. Prepare your `overrides.toml` file with selected network and CL image name and version and save anywhere inside `integration-tests` folder. +```toml +[ChainlinkImage] +image="your-image" +version="your-version" +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai=["https://http.endpoint.com"] + +[Network.RpcWsUrls] +polygon_mumbai=["wss://ws.endpoint.com"] + +[Network.WalletKeys] +polygon_mumbai=["my_so_private_key"] ``` -SELECTED_NETWORKS= \ -_KEYS= \ -_URLS= \ -_HTTP_URLS= \ +Then execute: +```bash go test -v -run ${TestName} ``` ### Debugging CL client API calls -``` +```bash export CL_CLIENT_DEBUG=true ``` \ No newline at end of file diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index f72843e77e8..3f69e7f829c 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -17,8 +17,8 @@ import ( ocr2keepers30config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config" "github.com/smartcontractkit/chainlink/integration-tests/actions/automationv2" - - "github.com/kelseyhightower/envconfig" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/smartcontractkit/chainlink/integration-tests/types" "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" @@ -29,16 +29,15 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/automation_utils_2_1" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" ) var utilsABI = cltypes.MustGetABI(automation_utils_2_1.AutomationUtilsABI) @@ -69,18 +68,27 @@ var ( func TestMain(m *testing.M) { logging.Init() - fmt.Printf("Running Smoke Test on %s\n", networks.MustGetSelectedNetworksFromEnv()[0].Name) // Print to get around disabled logging - fmt.Printf("Chainlink Image %s\n", os.Getenv("CHAINLINK_IMAGE")) // Print to get around disabled logging - fmt.Printf("Chainlink Version %s\n", os.Getenv("CHAINLINK_VERSION")) // Print to get around disabled logging + // config, err := tc.GetConfig(tc.NoTest, tc.Smoke, tc.Automation) + // if err != nil { + // panic(err) + // } + // fmt.Printf("Running Smoke Test on %s\n", networks.MustGetSelectedNetworkConfig(config.Network)[0].Name) // Print to get around disabled logging + // fmt.Printf("Chainlink Image %v\n", config.ChainlinkImage.Image) // Print to get around disabled logging + // fmt.Printf("Chainlink Version %v\n", config.ChainlinkImage.Version) // Print to get around disabled logging os.Exit(m.Run()) } func TestAutomationBasic(t *testing.T) { - SetupAutomationBasic(t, false) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } + SetupAutomationBasic(t, false, &config) } -func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { +func SetupAutomationBasic(t *testing.T, nodeUpgrade bool, automationTestConfig types.AutomationTestConfig) { t.Parallel() + registryVersions := map[string]ethereum.KeeperRegistryVersion{ "registry_2_0": ethereum.RegistryVersion_2_0, "registry_2_1_conditional": ethereum.RegistryVersion_2_1, @@ -90,23 +98,18 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { "registry_2_1_with_logtrigger_and_mercury_v02": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { + cfg := tc.MustCopy(automationTestConfig) t.Parallel() l := logging.GetTestLogger(t) - var ( - upgradeImage string - upgradeVersion string - err error - ) + var err error if nodeUpgrade { - upgradeImage = os.Getenv("UPGRADE_IMAGE") - upgradeVersion = os.Getenv("UPGRADE_VERSION") - if len(upgradeImage) == 0 || len(upgradeVersion) == 0 { - t.Fatal("UPGRADE_IMAGE and UPGRADE_VERSION must be set to upgrade nodes") + if cfg.GetChainlinkUpgradeImageConfig() == nil { + t.Fatal("[ChainlinkUpgradeImage] must be set in TOML config to upgrade nodes") } } @@ -117,7 +120,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { isMercury := isMercuryV02 || isMercuryV03 a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, isMercuryV02, isMercuryV03, + t, registryVersion, automationDefaultRegistryConfig, isMercuryV02, isMercuryV03, automationTestConfig, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -168,15 +171,16 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { g.Expect(counter.Int64()).Should(gomega.BeNumerically(">=", int64(expect)), "Expected consumer counter to be greater than %d, but got %d", expect, counter.Int64()) } - }, "5m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer + }, "10m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~2m for performing each upkeep 5 times, ~2m buffer l.Info().Msgf("Total time taken to get 5 performs for each upkeep: %s", time.Since(startTime)) if nodeUpgrade { + require.NotNil(t, cfg.GetChainlinkImageConfig(), "unable to upgrade node version, [ChainlinkUpgradeImage] was not set, must both a new image or a new version") expect := 5 // Upgrade the nodes one at a time and check that the upkeeps are still being performed for i := 0; i < 5; i++ { - err = actions.UpgradeChainlinkNodeVersionsLocal(upgradeImage, upgradeVersion, a.DockerEnv.ClCluster.Nodes[i]) + err = actions.UpgradeChainlinkNodeVersionsLocal(*cfg.GetChainlinkImageConfig().Image, *cfg.GetChainlinkImageConfig().Version, a.DockerEnv.ClCluster.Nodes[i]) require.NoError(t, err, "Error when upgrading node %d", i) time.Sleep(time.Second * 10) expect = expect + 5 @@ -230,8 +234,13 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } + a := setupAutomationTestDocker( - t, ethereum.RegistryVersion_2_1, automationDefaultRegistryConfig, false, false, + t, ethereum.RegistryVersion_2_1, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -309,7 +318,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { require.NoError(t, err, "Could not set upkeep trigger config at index %d", i) } - err := a.ChainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") var countersAfterSetNoMatch = make([]*big.Int, len(upkeepIDs)) @@ -400,13 +409,17 @@ func TestAutomationAddFunds(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -433,7 +446,7 @@ func TestAutomationAddFunds(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion // Grant permission to the registry to fund the upkeep - err := a.LinkToken.Approve(a.Registry.Address(), big.NewInt(9e18)) + err = a.LinkToken.Approve(a.Registry.Address(), big.NewInt(9e18)) require.NoError(t, err, "Could not approve permissions for the registry on the link token contract") err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") @@ -468,8 +481,12 @@ func TestAutomationPauseUnPause(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -504,7 +521,7 @@ func TestAutomationPauseUnPause(t *testing.T) { require.NoError(t, err, "Could not pause upkeep at index %d", i) } - err := a.ChainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for upkeeps to be paused") var countersAfterPause = make([]*big.Int, len(upkeepIDs)) @@ -557,14 +574,18 @@ func TestAutomationRegisterUpkeep(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -641,13 +662,17 @@ func TestAutomationPauseRegistry(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -676,7 +701,7 @@ func TestAutomationPauseRegistry(t *testing.T) { }, "4m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~1m for performing each upkeep once, ~2m buffer // Pause the registry - err := a.Registry.Pause() + err = a.Registry.Pause() require.NoError(t, err, "Error pausing registry") err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for registry to pause") @@ -710,14 +735,18 @@ func TestAutomationKeeperNodesDown(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumers, upkeepIDs := actions.DeployConsumers( @@ -751,7 +780,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { }, "4m", "1s").Should(gomega.Succeed()) // ~1m for cluster setup, ~1m for performing each upkeep once, ~2m buffer // Take down 1 node. Currently, using 4 nodes so f=1 and is the max nodes that can go down. - err := nodesWithoutBootstrap[0].MustDeleteJob("1") + err = nodesWithoutBootstrap[0].MustDeleteJob("1") require.NoError(t, err, "Error deleting job from Chainlink node") err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for blockchain events") @@ -810,13 +839,17 @@ func TestAutomationPerformSimulation(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumersPerformance, _ := actions.DeployPerformanceConsumers( @@ -849,7 +882,7 @@ func TestAutomationPerformSimulation(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion // Set performGas on consumer to be low, so that performUpkeep starts becoming successful - err := consumerPerformance.SetPerformGasToBurn(testcontext.Get(t), big.NewInt(100000)) + err = consumerPerformance.SetPerformGasToBurn(testcontext.Get(t), big.NewInt(100000)) require.NoError(t, err, "Perform gas should be set successfully on consumer") err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for set perform gas tx") @@ -873,14 +906,18 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) consumersPerformance, upkeepIDs := actions.DeployPerformanceConsumers( @@ -915,7 +952,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { }, "2m", "1s").Should(gomega.Succeed()) // ~1m for setup, 1m assertion // Increase gas limit for the upkeep, higher than the performGasBurn - err := a.Registry.SetUpkeepGasLimit(upkeepID, uint32(4500000)) + err = a.Registry.SetUpkeepGasLimit(upkeepID, uint32(4500000)) require.NoError(t, err, "Error setting upkeep gas limit") err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error waiting for SetUpkeepGasLimit tx") @@ -987,14 +1024,19 @@ func TestUpdateCheckData(t *testing.T) { "registry_2_1": ethereum.RegistryVersion_2_1, } - for n, rv := range registryVersions { - name := n - registryVersion := rv + for name, registryVersion := range registryVersions { + name := name + registryVersion := registryVersion t.Run(name, func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Automation) + if err != nil { + t.Fatal(err) + } + a := setupAutomationTestDocker( - t, registryVersion, automationDefaultRegistryConfig, false, false, + t, registryVersion, automationDefaultRegistryConfig, false, false, &config, ) performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerConsumers( @@ -1028,7 +1070,7 @@ func TestUpdateCheckData(t *testing.T) { require.NoError(t, err, "Could not update check data for upkeep at index %d", i) } - err := a.ChainClient.WaitForEvents() + err = a.ChainClient.WaitForEvents() require.NoError(t, err, "Error while waiting for check data update") // retrieve new check data for all upkeeps @@ -1053,27 +1095,24 @@ func TestUpdateCheckData(t *testing.T) { } } -type TestConfig struct { - ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:"1"` -} - func setupAutomationTestDocker( t *testing.T, registryVersion ethereum.KeeperRegistryVersion, registryConfig contracts.KeeperRegistrySettings, isMercuryV02 bool, isMercuryV03 bool, + automationTestConfig types.AutomationTestConfig, ) automationv2.AutomationTest { require.False(t, isMercuryV02 && isMercuryV03, "Cannot run test with both Mercury V02 and V03 on") l := logging.GetTestLogger(t) // Add registry version to config registryConfig.RegistryVersion = registryVersion - network := networks.MustGetSelectedNetworksFromEnv()[0] + network := networks.MustGetSelectedNetworkConfig(automationTestConfig.GetNetworkConfig())[0] // build the node config clNodeConfig := node.NewConfig(node.NewBaseConfig()) - syncInterval := models.MustMakeDuration(5 * time.Minute) + syncInterval := *commonconfig.MustNewDuration(5 * time.Minute) clNodeConfig.Feature.LogPoller = ptr.Ptr[bool](true) clNodeConfig.OCR2.Enabled = ptr.Ptr[bool](true) clNodeConfig.Keeper.TurnLookBack = ptr.Ptr[int64](int64(0)) @@ -1085,17 +1124,16 @@ func setupAutomationTestDocker( //launch the environment var env *test_env.CLClusterTestEnv var err error - var testConfig TestConfig - err = envconfig.Process("AUTOMATION", &testConfig) require.NoError(t, err) - l.Debug().Msgf("Funding amount: %f", testConfig.ChainlinkNodeFunding) + l.Debug().Msgf("Funding amount: %f", *automationTestConfig.GetCommonConfig().ChainlinkNodeFunding) clNodesCount := 5 if isMercuryV02 || isMercuryV03 { env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(automationTestConfig). WithGeth(). WithMockAdapter(). - WithFunding(big.NewFloat(testConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*automationTestConfig.GetCommonConfig().ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "Error deploying test environment for Mercury") @@ -1121,19 +1159,20 @@ func setupAutomationTestDocker( node.SetChainConfig(clNodeConfig, wsUrls, httpUrls, network, false) - err = env.StartClCluster(clNodeConfig, clNodesCount, secretsConfig) + err = env.StartClCluster(clNodeConfig, clNodesCount, secretsConfig, automationTestConfig) require.NoError(t, err, "Error starting CL nodes test environment for Mercury") - err = env.FundChainlinkNodes(big.NewFloat(testConfig.ChainlinkNodeFunding)) + err = env.FundChainlinkNodes(big.NewFloat(*automationTestConfig.GetCommonConfig().ChainlinkNodeFunding)) require.NoError(t, err, "Error funding CL nodes") } else { env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(automationTestConfig). WithGeth(). WithMockAdapter(). WithCLNodes(clNodesCount). WithCLNodeConfig(clNodeConfig). - WithFunding(big.NewFloat(testConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*automationTestConfig.GetCommonConfig().ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "Error deploying test environment") diff --git a/integration-tests/smoke/automation_test.go_test_list.json b/integration-tests/smoke/automation_test.go_test_list.json index ad6de592ede..b88684599c7 100644 --- a/integration-tests/smoke/automation_test.go_test_list.json +++ b/integration-tests/smoke/automation_test.go_test_list.json @@ -2,51 +2,73 @@ "tests": [ { "name": "TestAutomationBasic", - "label": "ubuntu20.04-32cores-128GB", - "nodes": 6 + "label": "ubuntu-latest", + "nodes": 2, + "run":[ + {"name":"registry_2_0"}, + {"name":"registry_2_1_conditional"} + ] + }, + { + "name": "TestAutomationBasic", + "label": "ubuntu-latest", + "nodes": 2, + "run":[ + {"name":"registry_2_1_logtrigger"}, + {"name":"registry_2_1_with_mercury_v02"} + ] + }, + { + "name": "TestAutomationBasic", + "label": "ubuntu-latest", + "nodes": 2, + "run":[ + {"name":"registry_2_1_with_mercury_v03"}, + {"name":"registry_2_1_with_logtrigger_and_mercury_v02"} + ] }, { "name": "TestSetUpkeepTriggerConfig" }, { "name": "TestAutomationAddFunds", - "label": "ubuntu20.04-32cores-128GB", + "label": "ubuntu-latest", "nodes": 2 }, { "name": "TestAutomationPauseUnPause", - "label": "ubuntu20.04-16cores-64GB", + "label": "ubuntu-latest", "nodes": 2 }, { "name": "TestAutomationRegisterUpkeep", - "label": "ubuntu20.04-16cores-64GB", + "label": "ubuntu-latest", "nodes": 2 }, { "name": "TestAutomationPauseRegistry", - "label": "ubuntu20.04-16cores-64GB", + "label": "ubuntu-latest", "nodes": 2 }, { "name": "TestAutomationKeeperNodesDown", - "label": "ubuntu20.04-16cores-64GB", + "label": "ubuntu-latest", "nodes": 2 }, { "name": "TestAutomationPerformSimulation", - "label": "ubuntu20.04-16cores-64GB", + "label": "ubuntu-latest", "nodes": 2 }, { "name": "TestAutomationCheckPerformGasLimit", - "label": "ubuntu20.04-32cores-128GB", + "label": "ubuntu-latest", "nodes": 2 }, { "name": "TestUpdateCheckData", - "label": "ubuntu20.04-32cores-128GB", + "label": "ubuntu-latest", "nodes": 2 } ] -} +} \ No newline at end of file diff --git a/integration-tests/smoke/automation_upgrade_test.go b/integration-tests/smoke/automation_upgrade_test.go index 28285543621..6601457de8b 100644 --- a/integration-tests/smoke/automation_upgrade_test.go +++ b/integration-tests/smoke/automation_upgrade_test.go @@ -2,8 +2,14 @@ package smoke import ( "testing" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestAutomationNodeUpgrade(t *testing.T) { - SetupAutomationBasic(t, true) + config, err := tc.GetConfig(t.Name(), tc.Automation) + if err != nil { + t.Fatal(err, "Error getting config") + } + SetupAutomationBasic(t, true, &config) } diff --git a/integration-tests/smoke/cron_test.go b/integration-tests/smoke/cron_test.go index 013e4c631c7..b6e04612aca 100644 --- a/integration-tests/smoke/cron_test.go +++ b/integration-tests/smoke/cron_test.go @@ -13,14 +13,21 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestCronBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Cron) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodes(1). @@ -65,8 +72,14 @@ func TestCronJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Cron) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodes(1). diff --git a/integration-tests/smoke/flux_test.go b/integration-tests/smoke/flux_test.go index 72dc15e7b11..c8cec4e385b 100644 --- a/integration-tests/smoke/flux_test.go +++ b/integration-tests/smoke/flux_test.go @@ -19,14 +19,21 @@ import ( "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" ) func TestFluxBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.Flux) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodes(3). diff --git a/integration-tests/smoke/forwarder_ocr_test.go b/integration-tests/smoke/forwarder_ocr_test.go index d4f9b5884a2..5c603c5b08f 100644 --- a/integration-tests/smoke/forwarder_ocr_test.go +++ b/integration-tests/smoke/forwarder_ocr_test.go @@ -12,14 +12,21 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestForwarderOCRBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.ForwarderOcr) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithForwarders(). @@ -67,7 +74,7 @@ func TestForwarderOCRBasic(t *testing.T) { err = actions.CreateOCRJobsWithForwarderLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID().String()) require.NoError(t, err, "failed to setup forwarder jobs") - err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") @@ -78,7 +85,7 @@ func TestForwarderOCRBasic(t *testing.T) { err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") diff --git a/integration-tests/smoke/forwarders_ocr2_test.go b/integration-tests/smoke/forwarders_ocr2_test.go index 7b775cf437f..9385fb4f9a5 100644 --- a/integration-tests/smoke/forwarders_ocr2_test.go +++ b/integration-tests/smoke/forwarders_ocr2_test.go @@ -17,14 +17,22 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestForwarderOCR2Basic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.ForwarderOcr2) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), @@ -77,7 +85,7 @@ func TestForwarderOCR2Basic(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") - err = actions.CreateOCRv2JobsLocal(ocrInstances, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), true) + err = actions.CreateOCRv2JobsLocal(ocrInstances, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), true, false) require.NoError(t, err, "Error creating OCRv2 jobs with forwarders") err = env.EVMClient.WaitForEvents() require.NoError(t, err, "Error waiting for events") diff --git a/integration-tests/smoke/keeper_test.go b/integration-tests/smoke/keeper_test.go index bcf64a5febd..0ebbc1e083d 100644 --- a/integration-tests/smoke/keeper_test.go +++ b/integration-tests/smoke/keeper_test.go @@ -11,18 +11,19 @@ import ( "github.com/onsi/gomega" "github.com/stretchr/testify/require" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) const ( @@ -87,7 +88,12 @@ func TestKeeperBasicSmoke(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -101,7 +107,7 @@ func TestKeeperBasicSmoke(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -163,7 +169,12 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -177,7 +188,7 @@ func TestKeeperBlockCountPerTurn(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -267,7 +278,12 @@ func TestKeeperSimulation(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumersPerformance, upkeepIDs := actions.DeployPerformanceKeeperContracts( t, registryVersion, @@ -285,7 +301,7 @@ func TestKeeperSimulation(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -340,7 +356,11 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumersPerformance, upkeepIDs := actions.DeployPerformanceKeeperContracts( t, registryVersion, @@ -358,7 +378,7 @@ func TestKeeperCheckPerformGasLimit(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -453,7 +473,11 @@ func TestKeeperRegisterUpkeep(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, registrar, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -467,7 +491,7 @@ func TestKeeperRegisterUpkeep(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -542,7 +566,11 @@ func TestKeeperAddFunds(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -556,7 +584,7 @@ func TestKeeperAddFunds(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -605,7 +633,11 @@ func TestKeeperRemove(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -619,7 +651,7 @@ func TestKeeperRemove(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -683,7 +715,11 @@ func TestKeeperPauseRegistry(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -697,7 +733,7 @@ func TestKeeperPauseRegistry(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -744,7 +780,11 @@ func TestKeeperPauseRegistry(t *testing.T) { func TestKeeperMigrateRegistry(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, ethereum.RegistryVersion_1_2, @@ -758,7 +798,7 @@ func TestKeeperMigrateRegistry(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -836,7 +876,11 @@ func TestKeeperNodeDown(t *testing.T) { t.Run(fmt.Sprintf("registry_1_%d", registryVersion), func(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -942,7 +986,11 @@ type nodeAndJob struct { func TestKeeperPauseUnPauseUpkeep(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, ethereum.RegistryVersion_1_3, @@ -956,7 +1004,7 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -1032,7 +1080,11 @@ func TestKeeperPauseUnPauseUpkeep(t *testing.T) { func TestKeeperUpdateCheckData(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, performDataChecker, upkeepIDs := actions.DeployPerformDataCheckerContracts( t, ethereum.RegistryVersion_1_3, @@ -1047,7 +1099,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") @@ -1091,7 +1143,7 @@ func TestKeeperUpdateCheckData(t *testing.T) { }, "3m", "1s").Should(gomega.Succeed()) } -func setupKeeperTest(t *testing.T) ( +func setupKeeperTest(t *testing.T, config *tc.TestConfig) ( blockchain.EVMClient, []*client.ChainlinkClient, contracts.ContractDeployer, @@ -1100,14 +1152,15 @@ func setupKeeperTest(t *testing.T) ( ) { clNodeConfig := node.NewConfig(node.NewBaseConfig(), node.WithP2Pv2()) turnLookBack := int64(0) - syncInterval := models.MustMakeDuration(5 * time.Second) + syncInterval := *commonconfig.MustNewDuration(5 * time.Second) performGasOverhead := uint32(150000) clNodeConfig.Keeper.TurnLookBack = &turnLookBack clNodeConfig.Keeper.Registry.SyncInterval = &syncInterval clNodeConfig.Keeper.Registry.PerformGasOverhead = &performGasOverhead env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(config). WithGeth(). WithCLNodes(5). WithCLNodeConfig(clNodeConfig). @@ -1129,10 +1182,14 @@ func setupKeeperTest(t *testing.T) ( func TestKeeperJobReplacement(t *testing.T) { t.Parallel() + l := logging.GetTestLogger(t) registryVersion := ethereum.RegistryVersion_1_3 + config, err := tc.GetConfig("Smoke", tc.Keeper) + if err != nil { + t.Fatal(err) + } - l := logging.GetTestLogger(t) - chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t) + chainClient, chainlinkNodes, contractDeployer, linkToken, _ := setupKeeperTest(t, &config) registry, _, consumers, upkeepIDs := actions.DeployKeeperContracts( t, registryVersion, @@ -1146,7 +1203,7 @@ func TestKeeperJobReplacement(t *testing.T) { ) gom := gomega.NewGomegaWithT(t) - _, err := actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) + _, err = actions.CreateKeeperJobsLocal(l, chainlinkNodes, registry, contracts.OCRv2Config{}, chainClient.GetChainID().String()) require.NoError(t, err, "Error creating keeper jobs") err = chainClient.WaitForEvents() require.NoError(t, err, "Error creating keeper jobs") diff --git a/integration-tests/smoke/keeper_test.go_test_list.json b/integration-tests/smoke/keeper_test.go_test_list.json index b874bc65ee0..b2f4aa00659 100644 --- a/integration-tests/smoke/keeper_test.go_test_list.json +++ b/integration-tests/smoke/keeper_test.go_test_list.json @@ -2,42 +2,42 @@ "tests": [ { "name": "TestKeeperBasicSmoke", - "label": "ubuntu20.04-32cores-128GB", + "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperBlockCountPerTurn", - "label": "ubuntu20.04-32cores-128GB", + "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperSimulation", - "label": "ubuntu20.04-16cores-64GB", + "label": "ubuntu-latest", "nodes": 2 }, { "name": "TestKeeperCheckPerformGasLimit", - "label": "ubuntu20.04-16cores-64GB", + "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperRegisterUpkeep", - "label": "ubuntu20.04-16cores-64GB", + "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperAddFunds", - "label": "ubuntu20.04-16cores-64GB", + "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperRemove", - "label": "ubuntu20.04-32cores-128GB", + "label": "ubuntu-latest", "nodes": 3 }, { "name": "TestKeeperPauseRegistry", - "label": "ubuntu20.04-16cores-64GB", + "label": "ubuntu-latest", "nodes": 2 }, { @@ -45,7 +45,7 @@ }, { "name": "TestKeeperNodeDown", - "label": "ubuntu20.04-32cores-128GB", + "label": "ubuntu-latest", "nodes": 3 }, { @@ -58,4 +58,4 @@ "name": "TestKeeperJobReplacement" } ] -} +} \ No newline at end of file diff --git a/integration-tests/smoke/log_poller_test.go b/integration-tests/smoke/log_poller_test.go index 03a287ee6b7..593b4eb879a 100644 --- a/integration-tests/smoke/log_poller_test.go +++ b/integration-tests/smoke/log_poller_test.go @@ -1,261 +1,395 @@ package smoke import ( + "fmt" + "math/big" "testing" + "time" "github.com/ethereum/go-ethereum/accounts/abi" - + "github.com/onsi/gomega" + "github.com/rs/zerolog" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + lp_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/log_poller" logpoller "github.com/smartcontractkit/chainlink/integration-tests/universal/log_poller" + + core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" ) // consistency test with no network disruptions with approximate emission of 1500-1600 logs per second for ~110-120 seconds // 6 filters are registered func TestLogPollerFewFiltersFixedDepth(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 4, - UseFinalityTag: false, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - } + executeBasicLogPollerTest(t) +} - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } +func TestLogPollerFewFiltersFinalityTag(t *testing.T) { + executeBasicLogPollerTest(t) +} - cfg.General.EventsToEmit = eventsToEmit +// consistency test with no network disruptions with approximate emission of 1000-1100 logs per second for ~110-120 seconds +// 900 filters are registered +func TestLogPollerManyFiltersFixedDepth(t *testing.T) { + t.Skip("Execute manually, when needed as it runs for a long time") + executeBasicLogPollerTest(t) +} - logpoller.ExecuteBasicLogPollerTest(t, &cfg) +func TestLogPollerManyFiltersFinalityTag(t *testing.T) { + t.Skip("Execute manually, when needed as it runs for a long time") + executeBasicLogPollerTest(t) } -func TestLogPollerFewFiltersFinalityTag(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 4, - UseFinalityTag: true, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - } +// consistency test that introduces random distruptions by pausing either Chainlink or Postgres containers for random interval of 5-20 seconds +// with approximate emission of 520-550 logs per second for ~110 seconds +// 6 filters are registered +func TestLogPollerWithChaosFixedDepth(t *testing.T) { + executeBasicLogPollerTest(t) +} - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } +func TestLogPollerWithChaosFinalityTag(t *testing.T) { + executeBasicLogPollerTest(t) +} - cfg.General.EventsToEmit = eventsToEmit +func TestLogPollerWithChaosPostgresFixedDepth(t *testing.T) { + executeBasicLogPollerTest(t) +} - logpoller.ExecuteBasicLogPollerTest(t, &cfg) +func TestLogPollerWithChaosPostgresFinalityTag(t *testing.T) { + executeBasicLogPollerTest(t) } -// consistency test with no network disruptions with approximate emission of 1000-1100 logs per second for ~110-120 seconds -// 900 filters are registered -func TestLogManyFiltersPollerFixedDepth(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 300, - EventsPerTx: 3, - UseFinalityTag: false, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 30, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - } +// consistency test that registers filters after events were emitted and then triggers replay via API +// unfortunately there is no way to make sure that logs that are indexed are only picked up by replay +// and not by backup poller +// with approximate emission of 24 logs per second for ~110 seconds +// 6 filters are registered +func TestLogPollerReplayFixedDepth(t *testing.T) { + executeLogPollerReplay(t, "5m") +} + +func TestLogPollerReplayFinalityTag(t *testing.T) { + executeLogPollerReplay(t, "5m") +} + +// HELPER FUNCTIONS +func executeBasicLogPollerTest(t *testing.T) { + testConfig, err := tc.GetConfig(t.Name(), tc.LogPoller) + require.NoError(t, err, "Error getting config") eventsToEmit := []abi.Event{} for _, event := range logpoller.EmitterABI.Events { eventsToEmit = append(eventsToEmit, event) } + cfg := testConfig.LogPoller cfg.General.EventsToEmit = eventsToEmit - logpoller.ExecuteBasicLogPollerTest(t, &cfg) -} + l := logging.GetTestLogger(t) + coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ -func TestLogManyFiltersPollerFinalityTag(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 300, - EventsPerTx: 3, - UseFinalityTag: true, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 30, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - } + lpTestEnv := prepareEnvironment(l, t, &testConfig) + testEnv := lpTestEnv.testEnv - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } + // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) + // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) + err = logpoller.RegisterFiltersAndAssertUniquness(l, lpTestEnv.registry, lpTestEnv.upkeepIDs, lpTestEnv.logEmitters, cfg, lpTestEnv.upKeepsNeeded) + require.NoError(t, err, "Error registering filters") - cfg.General.EventsToEmit = eventsToEmit + l.Info().Msg("No duplicate filters found. OK!") - logpoller.ExecuteBasicLogPollerTest(t, &cfg) -} + err = testEnv.EVMClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") -// consistency test that introduces random distruptions by pausing either Chainlink or Postgres containers for random interval of 5-20 seconds -// with approximate emission of 520-550 logs per second for ~110 seconds -// 6 filters are registered -func TestLogPollerWithChaosFixedDepth(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 100, - UseFinalityTag: false, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - ChaosConfig: &logpoller.ChaosConfig{ - ExperimentCount: 10, - }, - } + expectedFilters := logpoller.GetExpectedFilters(lpTestEnv.logEmitters, cfg) + waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(l, coreLogger, t, testEnv, expectedFilters) - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } + // Save block number before starting to emit events, so that we can later use it when querying logs + sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "Error getting latest block number") + startBlock := int64(sb) - cfg.General.EventsToEmit = eventsToEmit + l.Info().Int64("Starting Block", startBlock).Msg("STARTING EVENT EMISSION") + startTime := time.Now() - logpoller.ExecuteBasicLogPollerTest(t, &cfg) -} + // Start chaos experimnents by randomly pausing random containers (Chainlink nodes or their DBs) + chaosDoneCh := make(chan error, 1) + go func() { + logpoller.ExecuteChaosExperiment(l, testEnv, cfg, chaosDoneCh) + }() -func TestLogPollerWithChaosFinalityTag(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 100, - UseFinalityTag: true, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - ChaosConfig: &logpoller.ChaosConfig{ - ExperimentCount: 10, - }, - } + totalLogsEmitted, err := logpoller.ExecuteGenerator(t, cfg, lpTestEnv.logEmitters) + endTime := time.Now() + require.NoError(t, err, "Error executing event generator") - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) - } + expectedLogsEmitted := logpoller.GetExpectedLogCount(cfg) + duration := int(endTime.Sub(startTime).Seconds()) - cfg.General.EventsToEmit = eventsToEmit + eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "Error getting latest block number") + + l.Info(). + Int("Total logs emitted", totalLogsEmitted). + Uint64("Probable last block with logs", eb). + Int64("Expected total logs emitted", expectedLogsEmitted). + Str("Duration", fmt.Sprintf("%d sec", duration)). + Str("LPS", fmt.Sprintf("~%d/sec", totalLogsEmitted/duration)). + Msg("FINISHED EVENT EMISSION") + + l.Info().Msg("Waiting before proceeding with test until all chaos experiments finish") + chaosError := <-chaosDoneCh + require.NoError(t, chaosError, "Error encountered during chaos experiment") + + // use ridciuously high end block so that we don't have to find out the block number of the last block in which logs were emitted + // as that's not trivial to do (i.e. just because chain was at block X when log emission ended it doesn't mean all events made it to that block) + endBlock := int64(eb) + 10000 - logpoller.ExecuteBasicLogPollerTest(t, &cfg) + // logCountWaitDuration, err := time.ParseDuration("5m") + // require.NoError(t, err, "Error parsing log count wait duration") + allNodesLogCountMatches, err := logpoller.FluentlyCheckIfAllNodesHaveLogCount("5m", startBlock, endBlock, totalLogsEmitted, expectedFilters, l, coreLogger, testEnv) + require.NoError(t, err, "Error checking if CL nodes have expected log count") + + conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l, coreLogger, t, allNodesLogCountMatches, lpTestEnv, cfg, startBlock, endBlock, "5m") } -// consistency test that registers filters after events were emitted and then triggers replay via API -// unfortunately there is no way to make sure that logs that are indexed are only picked up by replay -// and not by backup poller -// with approximate emission of 24 logs per second for ~110 seconds -// 6 filters are registered -func TestLogPollerReplayFixedDepth(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 4, - UseFinalityTag: false, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, - } +func executeLogPollerReplay(t *testing.T, consistencyTimeout string) { + testConfig, err := tc.GetConfig(t.Name(), tc.LogPoller) + require.NoError(t, err, "Error getting config") eventsToEmit := []abi.Event{} for _, event := range logpoller.EmitterABI.Events { eventsToEmit = append(eventsToEmit, event) } + cfg := testConfig.LogPoller cfg.General.EventsToEmit = eventsToEmit - consistencyTimeout := "5m" - logpoller.ExecuteLogPollerReplay(t, &cfg, consistencyTimeout) + l := logging.GetTestLogger(t) + coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ + + lpTestEnv := prepareEnvironment(l, t, &testConfig) + testEnv := lpTestEnv.testEnv + + // Save block number before starting to emit events, so that we can later use it when querying logs + sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "Error getting latest block number") + startBlock := int64(sb) + + l.Info().Int64("Starting Block", startBlock).Msg("STARTING EVENT EMISSION") + startTime := time.Now() + totalLogsEmitted, err := logpoller.ExecuteGenerator(t, cfg, lpTestEnv.logEmitters) + endTime := time.Now() + require.NoError(t, err, "Error executing event generator") + expectedLogsEmitted := logpoller.GetExpectedLogCount(cfg) + duration := int(endTime.Sub(startTime).Seconds()) + + // Save block number after finishing to emit events, so that we can later use it when querying logs + eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "Error getting latest block number") + + endBlock, err := logpoller.GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) + require.NoError(t, err, "Error getting end block to wait for") + + l.Info().Int64("Ending Block", endBlock).Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") + + // Lets make sure no logs are in DB yet + expectedFilters := logpoller.GetExpectedFilters(lpTestEnv.logEmitters, cfg) + logCountMatches, err := logpoller.ClNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), 0, expectedFilters, l, coreLogger, testEnv.ClCluster) + require.NoError(t, err, "Error checking if CL nodes have expected log count") + require.True(t, logCountMatches, "Some CL nodes already had logs in DB") + l.Info().Msg("No logs were saved by CL nodes yet, as expected. Proceeding.") + + // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) + // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) + err = logpoller.RegisterFiltersAndAssertUniquness(l, lpTestEnv.registry, lpTestEnv.upkeepIDs, lpTestEnv.logEmitters, cfg, lpTestEnv.upKeepsNeeded) + require.NoError(t, err, "Error registering filters") + + err = testEnv.EVMClient.WaitForEvents() + require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") + + waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(l, coreLogger, t, testEnv, expectedFilters) + + blockFinalisationWaitDuration := "5m" + l.Warn().Str("Duration", blockFinalisationWaitDuration).Msg("Waiting for all CL nodes to have end block finalised") + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + hasFinalised, err := logpoller.LogPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) + if err != nil { + l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") + } + g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") + }, blockFinalisationWaitDuration, "10s").Should(gomega.Succeed()) + + // Trigger replay + l.Info().Msg("Triggering log poller's replay") + for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { + nodeName := testEnv.ClCluster.Nodes[i].ContainerName + response, _, err := testEnv.ClCluster.Nodes[i].API.ReplayLogPollerFromBlock(startBlock, testEnv.EVMClient.GetChainID().Int64()) + require.NoError(t, err, "Error triggering log poller's replay on node %s", nodeName) + require.Equal(t, "Replay started", response.Data.Attributes.Message, "Unexpected response message from log poller's replay") + } + + // so that we don't have to look for block number of the last block in which logs were emitted as that's not trivial to do + endBlock = endBlock + 10000 + l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for replay logs to be processed by all nodes") + + // logCountWaitDuration, err := time.ParseDuration("5m") + allNodesLogCountMatches, err := logpoller.FluentlyCheckIfAllNodesHaveLogCount("5m", startBlock, endBlock, totalLogsEmitted, expectedFilters, l, coreLogger, testEnv) + require.NoError(t, err, "Error checking if CL nodes have expected log count") + + conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l, coreLogger, t, allNodesLogCountMatches, lpTestEnv, cfg, startBlock, endBlock, "5m") } -func TestLogPollerReplayFinalityTag(t *testing.T) { - cfg := logpoller.Config{ - General: &logpoller.General{ - Generator: logpoller.GeneratorType_Looped, - Contracts: 2, - EventsPerTx: 4, - UseFinalityTag: false, - }, - LoopedConfig: &logpoller.LoopedConfig{ - ContractConfig: logpoller.ContractConfig{ - ExecutionCount: 100, - }, - FuzzConfig: logpoller.FuzzConfig{ - MinEmitWaitTimeMs: 200, - MaxEmitWaitTimeMs: 500, - }, - }, +type logPollerEnvironment struct { + logEmitters []*contracts.LogEmitter + testEnv *test_env.CLClusterTestEnv + registry contracts.KeeperRegistry + upkeepIDs []*big.Int + upKeepsNeeded int +} + +// prepareEnvironment prepares environment for log poller tests by starting DON, private Ethereum network, +// deploying registry and log emitter contracts and registering log triggered upkeeps +func prepareEnvironment(l zerolog.Logger, t *testing.T, testConfig *tc.TestConfig) logPollerEnvironment { + cfg := testConfig.LogPoller + if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { + l.Warn().Msg("No events to emit specified, using all events from log emitter contract") + for _, event := range logpoller.EmitterABI.Events { + cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) + } } - eventsToEmit := []abi.Event{} - for _, event := range logpoller.EmitterABI.Events { - eventsToEmit = append(eventsToEmit, event) + l.Info().Msg("Starting basic log poller test") + + var ( + err error + upKeepsNeeded = *cfg.General.Contracts * len(cfg.General.EventsToEmit) + ) + + chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := logpoller.SetupLogPollerTestDocker( + t, + ethereum.RegistryVersion_2_1, + logpoller.DefaultOCRRegistryConfig, + upKeepsNeeded, + time.Duration(500*time.Millisecond), + *cfg.General.UseFinalityTag, + testConfig, + ) + + _, upkeepIDs := actions.DeployConsumers( + t, + registry, + registrar, + linkToken, + contractDeployer, + chainClient, + upKeepsNeeded, + big.NewInt(int64(9e18)), + uint32(2500000), + true, + false, + ) + + err = logpoller.AssertUpkeepIdsUniqueness(upkeepIDs) + require.NoError(t, err, "Error asserting upkeep ids uniqueness") + l.Info().Msg("No duplicate upkeep IDs found. OK!") + + // Deploy Log Emitter contracts + logEmitters := logpoller.UploadLogEmitterContractsAndWaitForFinalisation(l, t, testEnv, cfg) + err = logpoller.AssertContractAddressUniquneness(logEmitters) + require.NoError(t, err, "Error asserting contract addresses uniqueness") + l.Info().Msg("No duplicate contract addresses found. OK!") + + return logPollerEnvironment{ + logEmitters: logEmitters, + registry: registry, + upkeepIDs: upkeepIDs, + upKeepsNeeded: upKeepsNeeded, + testEnv: testEnv, } +} - cfg.General.EventsToEmit = eventsToEmit - consistencyTimeout := "5m" +// waitForAllNodesToHaveExpectedFiltersRegisteredOrFail waits until all nodes have expected filters registered until timeout +func waitForAllNodesToHaveExpectedFiltersRegisteredOrFail(l zerolog.Logger, coreLogger core_logger.SugaredLogger, t *testing.T, testEnv *test_env.CLClusterTestEnv, expectedFilters []logpoller.ExpectedFilter) { + // Make sure that all nodes have expected filters registered before starting to emit events + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + hasFilters := false + for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { + nodeName := testEnv.ClCluster.Nodes[i].ContainerName + l.Info(). + Str("Node name", nodeName). + Msg("Fetching filters from log poller's DB") + var message string + var err error + + hasFilters, message, err = logpoller.NodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) + if !hasFilters || err != nil { + l.Warn(). + Str("Details", message). + Msg("Some filters were missing, but we will retry") + break + } + } + g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") + }, "5m", "10s").Should(gomega.Succeed()) + + l.Info(). + Msg("All nodes have expected filters registered") + l.Info(). + Int("Count", len(expectedFilters)). + Msg("Expected filters count") +} - logpoller.ExecuteLogPollerReplay(t, &cfg, consistencyTimeout) +// conditionallyWaitUntilNodesHaveTheSameLogsAsEvm checks whether all CL nodes have the same number of logs as EVM node +// if not, then it prints missing logs and wait for some time and checks again +func conditionallyWaitUntilNodesHaveTheSameLogsAsEvm(l zerolog.Logger, coreLogger core_logger.SugaredLogger, t *testing.T, allNodesLogCountMatches bool, lpTestEnv logPollerEnvironment, cfg *lp_config.Config, startBlock, endBlock int64, waitDuration string) { + logCountWaitDuration, err := time.ParseDuration(waitDuration) + require.NoError(t, err, "Error parsing log count wait duration") + + allNodesHaveAllExpectedLogs := false + if !allNodesLogCountMatches { + missingLogs, err := logpoller.GetMissingLogs(startBlock, endBlock, lpTestEnv.logEmitters, lpTestEnv.testEnv.EVMClient, lpTestEnv.testEnv.ClCluster, l, coreLogger, cfg) + if err == nil { + if !missingLogs.IsEmpty() { + logpoller.PrintMissingLogsInfo(missingLogs, l, cfg) + } else { + allNodesHaveAllExpectedLogs = true + l.Info().Msg("All CL nodes have all the logs that EVM node has") + } + } + } + + require.True(t, allNodesLogCountMatches, "Not all CL nodes had expected log count afer %s", logCountWaitDuration) + + // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has + // but only in the rare case that first attempt to do it failed (basically here want to know not only + // if log count matches, but whether details of every single log match) + if !allNodesHaveAllExpectedLogs { + logConsistencyWaitDuration := "5m" + l.Info(). + Str("Duration", logConsistencyWaitDuration). + Msg("Waiting for CL nodes to have all the logs that EVM node has") + + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + missingLogs, err := logpoller.GetMissingLogs(startBlock, endBlock, lpTestEnv.logEmitters, lpTestEnv.testEnv.EVMClient, lpTestEnv.testEnv.ClCluster, l, coreLogger, cfg) + if err != nil { + l.Warn(). + Err(err). + Msg("Error getting missing logs. Retrying...") + } + + if !missingLogs.IsEmpty() { + logpoller.PrintMissingLogsInfo(missingLogs, l, cfg) + } + g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") + }, logConsistencyWaitDuration, "10s").Should(gomega.Succeed()) + } } diff --git a/integration-tests/smoke/log_poller_test.go_test_list.json b/integration-tests/smoke/log_poller_test.go_test_list.json new file mode 100644 index 00000000000..2159654e283 --- /dev/null +++ b/integration-tests/smoke/log_poller_test.go_test_list.json @@ -0,0 +1,44 @@ +{ + "tests": [ + { + "name": "TestLogPollerFewFiltersFixedDepth", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerFewFiltersFinalityTag", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerWithChaosFixedDepth", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerWithChaosFinalityTag", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerWithChaosPostgresFinalityTag", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerWithChaosPostgresFixedDepth", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerReplayFixedDepth", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerReplayFinalityTag", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerManyFiltersFixedDepth", + "label": "ubuntu-latest" + }, + { + "name": "TestLogPollerManyFiltersFinalityTag", + "label": "ubuntu-latest" + } + ] +} \ No newline at end of file diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index 9b30ab497b0..959ea412e11 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -11,20 +11,137 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/integration-tests/actions" "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/integration-tests/types/config/node" ) // Tests a basic OCRv2 median feed func TestOCRv2Basic(t *testing.T) { + t.Parallel() + + noMedianPlugin := map[string]string{string(env.MedianPlugin.Cmd): ""} + medianPlugin := map[string]string{string(env.MedianPlugin.Cmd): "chainlink-feeds"} + for _, test := range []struct { + name string + env map[string]string + chainReaderAndCodec bool + }{ + {"legacy", noMedianPlugin, false}, + {"legacy-chain-reader", noMedianPlugin, true}, + {"plugins", medianPlugin, false}, + {"plugins-chain-reader", medianPlugin, true}, + } { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + l := logging.GetTestLogger(t) + + config, err := tc.GetConfig("Smoke", tc.OCR2) + if err != nil { + t.Fatal(err) + } + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). + WithMockAdapter(). + WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), + node.WithOCR2(), + node.WithP2Pv2(), + node.WithTracing(), + )). + WithCLNodeOptions(test_env.WithNodeEnvVars(test.env)). + WithCLNodes(6). + WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). + Build() + require.NoError(t, err) + + env.ParallelTransactions(true) + + nodeClients := env.ClCluster.NodeAPIs() + bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] + + linkToken, err := env.ContractDeployer.DeployLinkTokenContract() + require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") + + err = actions.FundChainlinkNodesLocal(workerNodes, env.EVMClient, big.NewFloat(.05)) + require.NoError(t, err, "Error funding Chainlink nodes") + + // Gather transmitters + var transmitters []string + for _, node := range workerNodes { + addr, err := node.PrimaryEthAddress() + if err != nil { + require.NoError(t, fmt.Errorf("error getting node's primary ETH address: %w", err)) + } + transmitters = append(transmitters, addr) + } + + ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() + aggregatorContracts, err := actions.DeployOCRv2Contracts(1, linkToken, env.ContractDeployer, transmitters, env.EVMClient, ocrOffchainOptions) + require.NoError(t, err, "Error deploying OCRv2 aggregator contracts") + + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false, test.chainReaderAndCodec) + require.NoError(t, err, "Error creating OCRv2 jobs") + + ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) + require.NoError(t, err, "Error building OCRv2 config") + + err = actions.ConfigureOCRv2AggregatorContracts(env.EVMClient, ocrv2Config, aggregatorContracts) + require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") + + err = actions.WatchNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) + require.NoError(t, err, "Error watching for new OCR2 round") + roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(1)) + require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") + require.Equal(t, int64(5), roundData.Answer.Int64(), + "Expected latest answer from OCR contract to be 5 but got %d", + roundData.Answer.Int64(), + ) + + err = env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, 10) + require.NoError(t, err) + err = actions.WatchNewOCR2Round(2, aggregatorContracts, env.EVMClient, time.Minute*5, l) + require.NoError(t, err) + + roundData, err = aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(2)) + require.NoError(t, err, "Error getting latest OCR answer") + require.Equal(t, int64(10), roundData.Answer.Int64(), + "Expected latest answer from OCR contract to be 10 but got %d", + roundData.Answer.Int64(), + ) + }) + } +} + +// Tests that just calling requestNewRound() will properly induce more rounds +func TestOCRv2Request(t *testing.T) { + t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.ForwarderOcr) + if err != nil { + t.Fatal(err) + } + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), node.WithOCR2(), @@ -62,7 +179,7 @@ func TestOCRv2Basic(t *testing.T) { aggregatorContracts, err := actions.DeployOCRv2Contracts(1, linkToken, env.ContractDeployer, transmitters, env.EVMClient, ocrOffchainOptions) require.NoError(t, err, "Error deploying OCRv2 aggregator contracts") - err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) @@ -72,7 +189,7 @@ func TestOCRv2Basic(t *testing.T) { require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") err = actions.WatchNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) - require.NoError(t, err, "Error starting new OCR2 round") + require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), roundData.Answer.Int64(), @@ -80,17 +197,18 @@ func TestOCRv2Basic(t *testing.T) { roundData.Answer.Int64(), ) - err = env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, 10) - require.NoError(t, err) - err = actions.WatchNewOCR2Round(2, aggregatorContracts, env.EVMClient, time.Minute*5, l) - require.NoError(t, err) - - roundData, err = aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(2)) - require.NoError(t, err, "Error getting latest OCR answer") - require.Equal(t, int64(10), roundData.Answer.Int64(), - "Expected latest answer from OCR contract to be 10 but got %d", - roundData.Answer.Int64(), - ) + // Keep the mockserver value the same and continually request new rounds + for round := 2; round <= 4; round++ { + err = actions.StartNewOCR2Round(int64(round), aggregatorContracts, env.EVMClient, time.Minute*5, l) + require.NoError(t, err, "Error starting new OCR2 round") + roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(int64(round))) + require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") + require.Equal(t, int64(5), roundData.Answer.Int64(), + "Expected round %d answer from OCR contract to be 5 but got %d", + round, + roundData.Answer.Int64(), + ) + } } // Tests that just calling requestNewRound() will properly induce more rounds @@ -171,10 +289,17 @@ func TestOCRv2Request(t *testing.T) { } func TestOCRv2JobReplacement(t *testing.T) { + t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.OCR2) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodeConfig(node.NewConfig(node.NewBaseConfig(), @@ -213,7 +338,7 @@ func TestOCRv2JobReplacement(t *testing.T) { aggregatorContracts, err := actions.DeployOCRv2Contracts(1, linkToken, env.ContractDeployer, transmitters, env.EVMClient, ocrOffchainOptions) require.NoError(t, err, "Error deploying OCRv2 aggregator contracts") - err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, env.EVMClient.GetChainID().Uint64(), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) @@ -223,7 +348,7 @@ func TestOCRv2JobReplacement(t *testing.T) { require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") err = actions.WatchNewOCR2Round(1, aggregatorContracts, env.EVMClient, time.Minute*5, l) - require.NoError(t, err, "Error starting new OCR2 round") + require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(5), roundData.Answer.Int64(), @@ -249,11 +374,11 @@ func TestOCRv2JobReplacement(t *testing.T) { err = actions.DeleteBridges(nodeClients) require.NoError(t, err) - err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 15, env.EVMClient.GetChainID().Uint64(), false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 15, env.EVMClient.GetChainID().Uint64(), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") err = actions.WatchNewOCR2Round(3, aggregatorContracts, env.EVMClient, time.Minute*3, l) - require.NoError(t, err, "Error starting new OCR2 round") + require.NoError(t, err, "Error watching for new OCR2 round") roundData, err = aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(3)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, int64(15), roundData.Answer.Int64(), diff --git a/integration-tests/smoke/ocr2vrf_test.go b/integration-tests/smoke/ocr2vrf_test.go index 773476826c7..c01ac46fbbc 100644 --- a/integration-tests/smoke/ocr2vrf_test.go +++ b/integration-tests/smoke/ocr2vrf_test.go @@ -10,6 +10,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" eth "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" @@ -23,12 +24,21 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) +var ocr2vrfSmokeConfig *testconfig.TestConfig + func TestOCR2VRFRedeemModel(t *testing.T) { t.Parallel() t.Skip("VRFv3 is on pause, skipping") l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.OCR2) + if err != nil { + t.Fatal(err) + } + testEnvironment, testNetwork := setupOCR2VRFEnvironment(t) if testEnvironment.WillUseRemoteRunner() { return @@ -44,7 +54,7 @@ func TestOCR2VRFRedeemModel(t *testing.T) { require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, &config, chainClient) require.NoError(t, err, "Error tearing down environment") }) @@ -91,6 +101,11 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { t.Parallel() t.Skip("VRFv3 is on pause, skipping") l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.OCR2) + if err != nil { + t.Fatal(err) + } + testEnvironment, testNetwork := setupOCR2VRFEnvironment(t) if testEnvironment.WillUseRemoteRunner() { return @@ -106,7 +121,7 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { require.NoError(t, err, "Retreiving on-chain wallet addresses for chainlink nodes shouldn't fail") t.Cleanup(func() { - err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, chainClient) + err := actions.TeardownSuite(t, testEnvironment, chainlinkNodes, nil, zapcore.ErrorLevel, &config, chainClient) require.NoError(t, err, "Error tearing down environment") }) @@ -149,7 +164,15 @@ func TestOCR2VRFFulfillmentModel(t *testing.T) { } func setupOCR2VRFEnvironment(t *testing.T) (testEnvironment *environment.Environment, testNetwork blockchain.EVMNetwork) { - testNetwork = networks.MustGetSelectedNetworksFromEnv()[0] + if ocr2vrfSmokeConfig == nil { + c, err := testconfig.GetConfig("Smoke", tc.OCR2VRF) + if err != nil { + t.Fatal(err) + } + ocr2vrfSmokeConfig = &c + } + + testNetwork = networks.MustGetSelectedNetworkConfig(ocr2vrfSmokeConfig.Network)[0] evmConfig := eth.New(nil) if !testNetwork.Simulated { evmConfig = eth.New(ð.Props{ @@ -159,14 +182,20 @@ func setupOCR2VRFEnvironment(t *testing.T) (testEnvironment *environment.Environ }) } - cd := chainlink.New(0, map[string]interface{}{ + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(ocr2vrfSmokeConfig.ChainlinkImage, target) + ctf_config.MightConfigOverridePyroscopeKey(ocr2vrfSmokeConfig.Pyroscope, target) + } + + cd := chainlink.NewWithOverride(0, map[string]interface{}{ "replicas": 6, "toml": networks.AddNetworkDetailedConfig( config.BaseOCR2Config, + ocr2vrfSmokeConfig.Pyroscope, config.DefaultOCR2VRFNetworkDetailTomlConfig, testNetwork, ), - }) + }, ocr2vrfSmokeConfig.ChainlinkImage, overrideFn) testEnvironment = environment.New(&environment.Config{ NamespacePrefix: fmt.Sprintf("smoke-ocr2vrf-%s", strings.ReplaceAll(strings.ToLower(testNetwork.Name), " ", "-")), diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 9ed692700ad..549d6b0a63b 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -8,20 +8,32 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestOCRBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.OCR) + if err != nil { + t.Fatal(err) + } + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). WithMockAdapter(). WithCLNodes(6). - WithFunding(big.NewFloat(.01)). + WithFunding(big.NewFloat(.5)). WithStandardCleanup(). Build() require.NoError(t, err) @@ -42,7 +54,7 @@ func TestOCRBasic(t *testing.T) { err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID()) require.NoError(t, err) - err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -51,7 +63,7 @@ func TestOCRBasic(t *testing.T) { err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -63,8 +75,14 @@ func TestOCRJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.OCR) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodes(6). @@ -89,7 +107,7 @@ func TestOCRJobReplacement(t *testing.T) { err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID()) require.NoError(t, err) - err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -98,7 +116,7 @@ func TestOCRJobReplacement(t *testing.T) { err = actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err) - err = actions.StartNewRound(2, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(2, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -115,7 +133,7 @@ func TestOCRJobReplacement(t *testing.T) { err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, env.EVMClient.GetChainID()) require.NoError(t, err) - err = actions.StartNewRound(1, ocrInstances, env.EVMClient, l) + err = actions.WatchNewRound(1, ocrInstances, env.EVMClient, l) require.NoError(t, err) answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) diff --git a/integration-tests/smoke/runlog_test.go b/integration-tests/smoke/runlog_test.go index e2cd28b3320..f7f5c54069e 100644 --- a/integration-tests/smoke/runlog_test.go +++ b/integration-tests/smoke/runlog_test.go @@ -16,14 +16,22 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestRunLogBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.RunLog) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithMockAdapter(). WithCLNodes(1). diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index 9c24d97b13b..f5aeb86173b 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -12,19 +12,26 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv1" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv1" "github.com/smartcontractkit/chainlink/integration-tests/client" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestVRFBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.VRF) + if err != nil { + t.Fatal(err) + } + env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(.1)). @@ -111,9 +118,14 @@ func TestVRFBasic(t *testing.T) { func TestVRFJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) + config, err := tc.GetConfig("Smoke", tc.VRF) + if err != nil { + t.Fatal(err) + } env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestInstance(t). + WithTestConfig(&config). WithGeth(). WithCLNodes(1). WithFunding(big.NewFloat(.1)). diff --git a/integration-tests/smoke/vrfv2_test.go b/integration-tests/smoke/vrfv2_test.go index 4edb92e5df6..e4ff1600649 100644 --- a/integration-tests/smoke/vrfv2_test.go +++ b/integration-tests/smoke/vrfv2_test.go @@ -4,42 +4,52 @@ import ( "context" "math/big" "testing" + "time" + "github.com/ethereum/go-ethereum/common" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" + commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/conversions" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) func TestVRFv2Basic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - var vrfv2Config vrfv2_config.VRFV2Config - err := envconfig.Process("VRFV2", &vrfv2Config) - require.NoError(t, err) + config, err := tc.GetConfig("Smoke", tc.VRFv2) + require.NoError(t, err, "Error getting config") + + useVRFOwner := false + useTestCoordinator := false + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2Config.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) require.NoError(t, err) linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err) @@ -48,9 +58,11 @@ func TestVRFv2Basic(t *testing.T) { defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() numberOfTxKeysToCreate := 1 - vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2_actions.SetupVRFV2Environment( + vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2.SetupVRFV2Environment( env, - vrfv2Config, + &config, + useVRFOwner, + useTestCoordinator, linkToken, mockETHLinkFeed, defaultWalletAddress, @@ -66,25 +78,28 @@ func TestVRFv2Basic(t *testing.T) { subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information") - vrfv2_actions.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) t.Run("Request Randomness", func(t *testing.T) { - testConfig := vrfv2Config + configCopy := config.MustCopy().(tc.TestConfig) subBalanceBeforeRequest := subscription.Balance jobRunsBeforeTest, err := env.ClCluster.Nodes[0].API.MustReadRunsByJob(vrfv2Data.VRFJob.Data.ID) require.NoError(t, err, "error reading job runs") // test and assert - randomWordsFulfilledEvent, err := vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + randomWordsFulfilledEvent, err := vrfv2.RequestRandomnessAndWaitForFulfillment( + l, vrfv2Contracts.LoadTestConsumers[0], vrfv2Contracts.Coordinator, - vrfv2Data, subID, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, - l, + vrfv2Data, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -103,34 +118,361 @@ func TestVRFv2Basic(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, *config.VRFv2.General.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) + + t.Run("Direct Funding (VRFV2Wrapper)", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + wrapperContracts, wrapperSubID, err := vrfv2.SetupVRFV2WrapperEnvironment( + env, + &configCopy, + linkToken, + mockETHLinkFeed, + vrfv2Contracts.Coordinator, + vrfv2Data.KeyHash, + 1, + ) + require.NoError(t, err) + wrapperConsumer := wrapperContracts.LoadTestConsumers[0] + + wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperConsumer.Address()) + require.NoError(t, err, "Error getting wrapper consumer balance") + + wrapperSubscription, err := vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), *wrapperSubID) + require.NoError(t, err, "Error getting subscription information") + subBalanceBeforeRequest := wrapperSubscription.Balance + + // Request Randomness and wait for fulfillment event + randomWordsFulfilledEvent, err := vrfv2.DirectFundingRequestRandomnessAndWaitForFulfillment( + l, + wrapperConsumer, + vrfv2Contracts.Coordinator, + *wrapperSubID, + vrfv2Data, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + ) + require.NoError(t, err, "Error requesting randomness and waiting for fulfilment") + + // Check wrapper subscription balance + expectedSubBalanceJuels := new(big.Int).Sub(subBalanceBeforeRequest, randomWordsFulfilledEvent.Payment) + wrapperSubscription, err = vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), *wrapperSubID) + require.NoError(t, err, "Error getting subscription information") + subBalanceAfterRequest := wrapperSubscription.Balance + require.Equal(t, expectedSubBalanceJuels, subBalanceAfterRequest) + + // Check status of randomness request within the wrapper consumer contract + consumerStatus, err := wrapperConsumer.GetRequestStatus(testcontext.Get(t), randomWordsFulfilledEvent.RequestId) + require.NoError(t, err, "Error getting randomness request status") + require.True(t, consumerStatus.Fulfilled) + + // Check wrapper consumer LINK balance + expectedWrapperConsumerJuelsBalance := new(big.Int).Sub(wrapperConsumerJuelsBalanceBeforeRequest, consumerStatus.Paid) + wrapperConsumerJuelsBalanceAfterRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperConsumer.Address()) + require.NoError(t, err, "Error getting wrapper consumer balance") + require.Equal(t, expectedWrapperConsumerJuelsBalance, wrapperConsumerJuelsBalanceAfterRequest) + + // Check random word count + require.Equal(t, *configCopy.VRFv2.General.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + for _, w := range consumerStatus.RandomWords { + l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") + require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") + } + + 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") + }) + + t.Run("Oracle Withdraw", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + subIDsForOracleWithDraw, err := vrfv2.CreateFundSubsAndAddConsumers( + env, + big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), + linkToken, + vrfv2Contracts.Coordinator, + vrfv2Contracts.LoadTestConsumers, + 1, + ) + require.NoError(t, err) + + subIDForOracleWithdraw := subIDsForOracleWithDraw[0] + + fulfilledEventLink, err := vrfv2.RequestRandomnessAndWaitForFulfillment( + l, + vrfv2Contracts.LoadTestConsumers[0], + vrfv2Contracts.Coordinator, + subIDForOracleWithdraw, + vrfv2Data, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, + ) + require.NoError(t, err) + + amountToWithdrawLink := fulfilledEventLink.Payment + + defaultWalletBalanceLinkBeforeOracleWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + require.NoError(t, err) + + l.Info(). + Str("Returning to", defaultWalletAddress). + Str("Amount", amountToWithdrawLink.String()). + Msg("Invoking Oracle Withdraw for LINK") + + err = vrfv2Contracts.Coordinator.OracleWithdraw(common.HexToAddress(defaultWalletAddress), amountToWithdrawLink) + require.NoError(t, err, "Error withdrawing LINK from coordinator to default wallet") + + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2.ErrWaitTXsComplete) + + defaultWalletBalanceLinkAfterOracleWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + require.NoError(t, err) + + require.Equal( + t, + 1, + defaultWalletBalanceLinkAfterOracleWithdraw.Cmp(defaultWalletBalanceLinkBeforeOracleWithdraw), + "LINK funds were not returned after oracle withdraw", + ) + }) + + t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + subIDsForCancelling, err := vrfv2.CreateFundSubsAndAddConsumers( + env, + big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), + linkToken, + vrfv2Contracts.Coordinator, + vrfv2Contracts.LoadTestConsumers, + 1, + ) + require.NoError(t, err) + subIDForCancelling := subIDsForCancelling[0] + + testWalletAddress, err := actions.GenerateWallet() + require.NoError(t, err) + + testWalletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) + require.NoError(t, err) + + subscriptionForCancelling, err := vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + require.NoError(t, err, "error getting subscription information") + + subBalanceLink := subscriptionForCancelling.Balance + + l.Info(). + Str("Subscription Amount Link", subBalanceLink.String()). + Uint64("Returning funds from SubID", subIDForCancelling). + Str("Returning funds to", testWalletAddress.String()). + Msg("Canceling subscription and returning funds to subscription owner") + + tx, err := vrfv2Contracts.Coordinator.CancelSubscription(subIDForCancelling, testWalletAddress) + require.NoError(t, err, "Error canceling subscription") + + subscriptionCanceledEvent, err := vrfv2Contracts.Coordinator.WaitForSubscriptionCanceledEvent([]uint64{subIDForCancelling}, time.Second*30) + require.NoError(t, err, "error waiting for subscription canceled event") + + cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + require.NoError(t, err, "error getting tx cancellation Tx Receipt") + + txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) + + l.Info(). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Effective Gas Price", cancellationTxReceipt.EffectiveGasPrice.String()). + Uint64("Gas Used", cancellationTxReceipt.GasUsed). + Msg("Cancellation TX Receipt") + + l.Info(). + Str("Returned Subscription Amount Link", subscriptionCanceledEvent.Amount.String()). + Uint64("SubID", subscriptionCanceledEvent.SubId). + Str("Returned to", subscriptionCanceledEvent.To.String()). + Msg("Subscription Canceled Event") + + require.Equal(t, subBalanceLink, subscriptionCanceledEvent.Amount, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") + + testWalletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), testWalletAddress.String()) + require.NoError(t, err) + + //Verify that sub was deleted from Coordinator + _, err = vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + require.Error(t, err, "error not occurred when trying to get deleted subscription from old Coordinator after sub migration") + + subFundsReturnedLinkActual := new(big.Int).Sub(testWalletBalanceLinkAfterSubCancelling, testWalletBalanceLinkBeforeSubCancelling) + + l.Info(). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Sub Funds Returned Actual - Link", subFundsReturnedLinkActual.String()). + Str("Sub Balance - Link", subBalanceLink.String()). + Msg("Sub funds returned") + + require.Equal(t, 0, subBalanceLink.Cmp(subFundsReturnedLinkActual), "Returned LINK funds are not equal to sub balance that was cancelled") + }) + + t.Run("Owner Canceling Sub And Returning Funds While Having Pending Requests", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + // Underfund subscription to force fulfillments to fail + configCopy.VRFv2.General.SubscriptionFundingAmountLink = ptr.Ptr(float64(0.000000000000000001)) // 1 Juel + + subIDsForCancelling, err := vrfv2.CreateFundSubsAndAddConsumers( + env, + big.NewFloat(*configCopy.VRFv2.General.SubscriptionFundingAmountLink), + linkToken, + vrfv2Contracts.Coordinator, + vrfv2Contracts.LoadTestConsumers, + 1, + ) + require.NoError(t, err) + + subIDForCancelling := subIDsForCancelling[0] + + subscriptionForCancelling, err := vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + require.NoError(t, err, "Error getting subscription information") + + vrfv2.LogSubDetails(l, subscriptionForCancelling, subIDForCancelling, vrfv2Contracts.Coordinator) + + // No GetActiveSubscriptionIds function available - skipping check + + pendingRequestsExist, err := vrfv2Contracts.Coordinator.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) + require.NoError(t, err) + require.False(t, pendingRequestsExist, "Pending requests should not exist") + + // Request randomness - should fail due to underfunded subscription + randomWordsFulfilledEventTimeout := 5 * time.Second + _, err = vrfv2.RequestRandomnessAndWaitForFulfillment( + l, + vrfv2Contracts.LoadTestConsumers[0], + vrfv2Contracts.Coordinator, + subIDForCancelling, + vrfv2Data, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + randomWordsFulfilledEventTimeout, + ) + require.Error(t, err, "Error should occur while waiting for fulfilment due to low sub balance") + + pendingRequestsExist, err = vrfv2Contracts.Coordinator.PendingRequestsExist(testcontext.Get(t), subIDForCancelling) + require.NoError(t, err) + require.True(t, pendingRequestsExist, "Pending requests should exist after unfilfulled requests due to low sub balance") + + walletBalanceLinkBeforeSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + require.NoError(t, err) + + subscriptionForCancelling, err = vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + require.NoError(t, err, "Error getting subscription information") + subBalanceLink := subscriptionForCancelling.Balance + + l.Info(). + Str("Subscription Amount Link", subBalanceLink.String()). + Uint64("Returning funds from SubID", subIDForCancelling). + Str("Returning funds to", defaultWalletAddress). + Msg("Canceling subscription and returning funds to subscription owner") + + // Call OwnerCancelSubscription + tx, err := vrfv2Contracts.Coordinator.OwnerCancelSubscription(subIDForCancelling) + require.NoError(t, err, "Error canceling subscription") + + subscriptionCanceledEvent, err := vrfv2Contracts.Coordinator.WaitForSubscriptionCanceledEvent([]uint64{subIDForCancelling}, time.Second*30) + require.NoError(t, err, "error waiting for subscription canceled event") + + cancellationTxReceipt, err := env.EVMClient.GetTxReceipt(tx.Hash()) + require.NoError(t, err, "error getting tx cancellation Tx Receipt") + + txGasUsed := new(big.Int).SetUint64(cancellationTxReceipt.GasUsed) + cancellationTxFeeWei := new(big.Int).Mul(txGasUsed, cancellationTxReceipt.EffectiveGasPrice) + + l.Info(). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Effective Gas Price", cancellationTxReceipt.EffectiveGasPrice.String()). + Uint64("Gas Used", cancellationTxReceipt.GasUsed). + Msg("Cancellation TX Receipt") + + l.Info(). + Str("Returned Subscription Amount Link", subscriptionCanceledEvent.Amount.String()). + Uint64("SubID", subscriptionCanceledEvent.SubId). + Str("Returned to", subscriptionCanceledEvent.To.String()). + Msg("Subscription Canceled Event") + + require.Equal(t, subBalanceLink, subscriptionCanceledEvent.Amount, "SubscriptionCanceled event LINK amount is not equal to sub amount while canceling subscription") + + walletBalanceLinkAfterSubCancelling, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + require.NoError(t, err) + + // Verify that subscription was deleted from Coordinator contract + _, err = vrfv2Contracts.Coordinator.GetSubscription(testcontext.Get(t), subIDForCancelling) + l.Info(). + Str("Expected error message", err.Error()) + require.Error(t, err, "Error did not occur when fetching deleted subscription from the Coordinator after owner cancelation") + + subFundsReturnedLinkActual := new(big.Int).Sub(walletBalanceLinkAfterSubCancelling, walletBalanceLinkBeforeSubCancelling) + l.Info(). + Str("Wallet Balance Before Owner Cancelation", walletBalanceLinkBeforeSubCancelling.String()). + Str("Cancellation Tx Fee Wei", cancellationTxFeeWei.String()). + Str("Sub Funds Returned Actual - Link", subFundsReturnedLinkActual.String()). + Str("Sub Balance - Link", subBalanceLink.String()). + Str("Wallet Balance After Owner Cancelation", walletBalanceLinkAfterSubCancelling.String()). + Msg("Sub funds returned") + + require.Equal(t, 0, subBalanceLink.Cmp(subFundsReturnedLinkActual), "Returned LINK funds are not equal to sub balance that was cancelled") + + // Again, there is no GetActiveSubscriptionIds method on the v2 Coordinator contract, so we can't double check that the cancelled + // subID is no longer in the list of active subs + }) } func TestVRFv2MultipleSendingKeys(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - var vrfv2Config vrfv2_config.VRFV2Config - err := envconfig.Process("VRFV2", &vrfv2Config) - require.NoError(t, err) + config, err := tc.GetConfig("Smoke", tc.VRFv2) + if err != nil { + t.Fatal(err) + } + + useVRFOwner := false + useTestCoordinator := false + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestConfig(&config). + WithTestInstance(t). + WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2Config.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2Config.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) require.NoError(t, err) linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err) @@ -139,9 +481,11 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() numberOfTxKeysToCreate := 2 - vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2_actions.SetupVRFV2Environment( + vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2.SetupVRFV2Environment( env, - vrfv2Config, + &config, + useVRFOwner, + useTestCoordinator, linkToken, mockETHLinkFeed, defaultWalletAddress, @@ -157,10 +501,9 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) require.NoError(t, err, "error getting subscription information") - vrfv2_actions.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { - testConfig := vrfv2Config txKeys, _, err := env.ClCluster.Nodes[0].API.ReadTxKeys("evm") require.NoError(t, err, "error reading tx keys") @@ -168,15 +511,18 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { var fulfillmentTxFromAddresses []string for i := 0; i < numberOfTxKeysToCreate+1; i++ { - randomWordsFulfilledEvent, err := vrfv2_actions.RequestRandomnessAndWaitForFulfillment( + randomWordsFulfilledEvent, err := vrfv2.RequestRandomnessAndWaitForFulfillment( + l, vrfv2Contracts.LoadTestConsumers[0], vrfv2Contracts.Coordinator, - vrfv2Data, subID, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, - l, + vrfv2Data, + *config.VRFv2.General.MinimumConfirmations, + *config.VRFv2.General.CallbackGasLimit, + *config.VRFv2.General.NumberOfWords, + *config.VRFv2.General.RandomnessRequestCountPerRequest, + *config.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + config.VRFv2.General.RandomWordsFulfilledEventTimeout.Duration, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -198,3 +544,135 @@ func TestVRFv2MultipleSendingKeys(t *testing.T) { require.True(t, equalIgnoreOrder) }) } + +func TestVRFOwner(t *testing.T) { + t.Parallel() + l := logging.GetTestLogger(t) + + config, err := tc.GetConfig("Smoke", tc.VRFv2) + require.NoError(t, err, "Error getting config") + + useVRFOwner := true + useTestCoordinator := true + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). + WithCLNodes(1). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). + WithStandardCleanup(). + Build() + require.NoError(t, err, "error creating test env") + + env.ParallelTransactions(true) + + mockETHLinkFeed, err := env.ContractDeployer.DeployVRFMockETHLINKFeed(big.NewInt(*config.VRFv2.General.LinkNativeFeedResponse)) + + require.NoError(t, err) + linkToken, err := actions.DeployLINKToken(env.ContractDeployer) + require.NoError(t, err) + + // register proving key against oracle address (sending key) in order to test oracleWithdraw + defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() + + numberOfTxKeysToCreate := 1 + vrfv2Contracts, subIDs, vrfv2Data, err := vrfv2.SetupVRFV2Environment( + env, + &config, + useVRFOwner, + useTestCoordinator, + linkToken, + mockETHLinkFeed, + defaultWalletAddress, + numberOfTxKeysToCreate, + 1, + 1, + l, + ) + require.NoError(t, err, "error setting up VRF v2 env") + + subID := subIDs[0] + + subscription, err := vrfv2Contracts.Coordinator.GetSubscription(context.Background(), subID) + require.NoError(t, err, "error getting subscription information") + + vrfv2.LogSubDetails(l, subscription, subID, vrfv2Contracts.Coordinator) + + t.Run("Request Randomness With Force-Fulfill", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + + vrfCoordinatorOwner, err := vrfv2Contracts.Coordinator.GetOwner(testcontext.Get(t)) + require.NoError(t, err) + require.Equal(t, vrfv2Contracts.VRFOwner.Address(), vrfCoordinatorOwner.String()) + + err = linkToken.Transfer( + vrfv2Contracts.LoadTestConsumers[0].Address(), + conversions.EtherToWei(big.NewFloat(5)), + ) + require.NoError(t, err, "error transferring link to consumer contract") + + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2.ErrWaitTXsComplete) + + consumerLinkBalance, err := linkToken.BalanceOf(testcontext.Get(t), vrfv2Contracts.LoadTestConsumers[0].Address()) + require.NoError(t, err, "error getting consumer link balance") + l.Info(). + Str("Balance", conversions.WeiToEther(consumerLinkBalance).String()). + Str("Consumer", vrfv2Contracts.LoadTestConsumers[0].Address()). + Msg("Consumer Link Balance") + + err = mockETHLinkFeed.SetBlockTimestampDeduction(big.NewInt(3)) + require.NoError(t, err) + err = env.EVMClient.WaitForEvents() + require.NoError(t, err, vrfv2.ErrWaitTXsComplete) + + // test and assert + _, randFulfilledEvent, _, err := vrfv2.RequestRandomnessWithForceFulfillAndWaitForFulfillment( + l, + vrfv2Contracts.LoadTestConsumers[0], + vrfv2Contracts.Coordinator, + vrfv2Contracts.VRFOwner, + vrfv2Data, + *configCopy.VRFv2.General.MinimumConfirmations, + *configCopy.VRFv2.General.CallbackGasLimit, + *configCopy.VRFv2.General.NumberOfWords, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2.General.RandomnessRequestCountPerRequestDeviation, + conversions.EtherToWei(big.NewFloat(5)), + common.HexToAddress(linkToken.Address()), + time.Minute*2, + ) + require.NoError(t, err, "error requesting randomness with force-fulfillment and waiting for fulfilment") + require.Equal(t, 0, randFulfilledEvent.Payment.Cmp(big.NewInt(0)), "Forced Fulfilled Randomness's Payment should be 0") + + status, err := vrfv2Contracts.LoadTestConsumers[0].GetRequestStatus(context.Background(), 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") + + require.Equal(t, *configCopy.VRFv2.General.NumberOfWords, uint32(len(status.RandomWords))) + for _, w := range status.RandomWords { + l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") + require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") + } + + coordinatorConfig, err := vrfv2Contracts.Coordinator.GetConfig(testcontext.Get(t)) + require.NoError(t, err, "error getting coordinator config") + + coordinatorFeeConfig, err := vrfv2Contracts.Coordinator.GetFeeConfig(testcontext.Get(t)) + require.NoError(t, err, "error getting coordinator fee config") + + coordinatorFallbackWeiPerUnitLinkConfig, err := vrfv2Contracts.Coordinator.GetFallbackWeiPerUnitLink(testcontext.Get(t)) + require.NoError(t, err, "error getting coordinator FallbackWeiPerUnitLink") + + require.Equal(t, *configCopy.VRFv2.General.StalenessSeconds, coordinatorConfig.StalenessSeconds) + require.Equal(t, *configCopy.VRFv2.General.GasAfterPaymentCalculation, coordinatorConfig.GasAfterPaymentCalculation) + 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()) + }) +} diff --git a/integration-tests/smoke/vrfv2plus_test.go b/integration-tests/smoke/vrfv2plus_test.go index f4f52b6ee01..9309070f647 100644 --- a/integration-tests/smoke/vrfv2plus_test.go +++ b/integration-tests/smoke/vrfv2plus_test.go @@ -10,18 +10,19 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - "github.com/kelseyhightower/envconfig" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv2plus" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/vrf_v2plus_upgraded_version" "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) @@ -29,37 +30,41 @@ func TestVRFv2Plus(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) - require.NoError(t, err) + config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + if err != nil { + t.Fatal(err) + } + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - // register proving key against oracle address (sending key) in order to test oracleWithdraw + // default wallet address is used to test Withdraw defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() numberOfTxKeysToCreate := 2 vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( env, - vrfv2PlusConfig, + &config, linkToken, mockETHLinkFeed, - defaultWalletAddress, numberOfTxKeysToCreate, 1, 1, @@ -75,7 +80,7 @@ func TestVRFv2Plus(t *testing.T) { vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) t.Run("Link Billing", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false subBalanceBeforeRequest := subscription.Balance @@ -89,9 +94,12 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -111,14 +119,16 @@ func TestVRFv2Plus(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, *configCopy.VRFv2Plus.General.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) + t.Run("Native Billing", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) + testConfig := configCopy.VRFv2Plus.General var isNativeBilling = true subNativeTokenBalanceBeforeRequest := subscription.NativeBalance @@ -132,9 +142,12 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -153,17 +166,17 @@ func TestVRFv2Plus(t *testing.T) { require.True(t, status.Fulfilled) l.Debug().Bool("Fulfilment Status", status.Fulfilled).Msg("Random Words Request Fulfilment Status") - require.Equal(t, testConfig.NumberOfWords, uint32(len(status.RandomWords))) + require.Equal(t, *testConfig.NumberOfWords, uint32(len(status.RandomWords))) for _, w := range status.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) t.Run("Direct Funding (VRFV2PlusWrapper)", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) wrapperContracts, wrapperSubID, err := vrfv2plus.SetupVRFV2PlusWrapperEnvironment( env, - testConfig, + &configCopy, linkToken, mockETHLinkFeed, vrfv2PlusContracts.Coordinator, @@ -173,7 +186,8 @@ func TestVRFv2Plus(t *testing.T) { require.NoError(t, err) t.Run("Link Billing", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) + testConfig := configCopy.VRFv2Plus.General var isNativeBilling = false wrapperConsumerJuelsBalanceBeforeRequest, err := linkToken.BalanceOf(testcontext.Get(t), wrapperContracts.LoadTestConsumers[0].Address()) @@ -189,8 +203,12 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, wrapperSubID, isNativeBilling, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -215,14 +233,15 @@ func TestVRFv2Plus(t *testing.T) { //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) - require.Equal(t, testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + require.Equal(t, *testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) for _, w := range consumerStatus.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") } }) t.Run("Native Billing", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) + testConfig := configCopy.VRFv2Plus.General var isNativeBilling = true wrapperConsumerBalanceBeforeRequestWei, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(wrapperContracts.LoadTestConsumers[0].Address())) @@ -238,8 +257,12 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, wrapperSubID, isNativeBilling, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -264,7 +287,7 @@ func TestVRFv2Plus(t *testing.T) { //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) - require.Equal(t, testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) + require.Equal(t, *testConfig.NumberOfWords, uint32(len(consumerStatus.RandomWords))) for _, w := range consumerStatus.RandomWords { l.Info().Str("Output", w.String()).Msg("Randomness fulfilled") require.Equal(t, 1, w.Cmp(big.NewInt(0)), "Expected the VRF job give an answer bigger than 0") @@ -272,14 +295,16 @@ func TestVRFv2Plus(t *testing.T) { }) }) t.Run("Canceling Sub And Returning Funds", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) subIDsForCancelling, err := vrfv2plus.CreateFundSubsAndAddConsumers( env, - testConfig, + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, vrfv2PlusContracts.Coordinator, vrfv2PlusContracts.LoadTestConsumers, 1, + vrfv2plus_config.BillingType(*configCopy.GetVRFv2PlusConfig().General.SubscriptionBillingType), ) require.NoError(t, err) subIDForCancelling := subIDsForCancelling[0] @@ -364,18 +389,22 @@ func TestVRFv2Plus(t *testing.T) { }) t.Run("Owner Canceling Sub And Returning Funds While Having Pending Requests", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) + testConfig := configCopy.VRFv2Plus.General + //underfund subs in order rand fulfillments to fail - testConfig.SubscriptionFundingAmountNative = float64(0.000000000000000001) //1 Wei - testConfig.SubscriptionFundingAmountLink = float64(0.000000000000000001) //1 Juels + testConfig.SubscriptionFundingAmountNative = ptr.Ptr(float64(0.000000000000000001)) //1 Wei + testConfig.SubscriptionFundingAmountLink = ptr.Ptr(float64(0.000000000000000001)) //1 Juels subIDsForCancelling, err := vrfv2plus.CreateFundSubsAndAddConsumers( env, - testConfig, + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, vrfv2PlusContracts.Coordinator, vrfv2PlusContracts.LoadTestConsumers, 1, + vrfv2plus_config.BillingType(*configCopy.GetVRFv2PlusConfig().General.SubscriptionBillingType), ) require.NoError(t, err) @@ -402,8 +431,11 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subIDForCancelling, false, - testConfig.RandomnessRequestCountPerRequest, - testConfig, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, randomWordsFulfilledEventTimeout, l, ) @@ -416,8 +448,11 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusData, subIDForCancelling, true, - testConfig.RandomnessRequestCountPerRequest, - testConfig, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, randomWordsFulfilledEventTimeout, l, ) @@ -518,28 +553,34 @@ func TestVRFv2Plus(t *testing.T) { "Active subscription ids should not contain sub id after sub cancellation", ) }) - t.Run("Oracle Withdraw", func(t *testing.T) { - testConfig := vrfv2PlusConfig - subIDsForOracleWithDraw, err := vrfv2plus.CreateFundSubsAndAddConsumers( + + t.Run("Owner Withdraw", func(t *testing.T) { + configCopy := config.MustCopy().(tc.TestConfig) + subIDsForWithdraw, err := vrfv2plus.CreateFundSubsAndAddConsumers( env, - testConfig, + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountNative), + big.NewFloat(*configCopy.GetVRFv2PlusConfig().General.SubscriptionFundingAmountLink), linkToken, vrfv2PlusContracts.Coordinator, vrfv2PlusContracts.LoadTestConsumers, 1, + vrfv2plus_config.BillingType(*configCopy.GetVRFv2PlusConfig().General.SubscriptionBillingType), ) require.NoError(t, err) - subIDForOracleWithdraw := subIDsForOracleWithDraw[0] + subIDForWithdraw := subIDsForWithdraw[0] fulfilledEventLink, err := vrfv2plus.RequestRandomnessAndWaitForFulfillment( vrfv2PlusContracts.LoadTestConsumers[0], vrfv2PlusContracts.Coordinator, vrfv2PlusData, - subIDForOracleWithdraw, + subIDForWithdraw, false, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err) @@ -548,20 +589,23 @@ func TestVRFv2Plus(t *testing.T) { vrfv2PlusContracts.LoadTestConsumers[0], vrfv2PlusContracts.Coordinator, vrfv2PlusData, - subIDForOracleWithdraw, + subIDForWithdraw, true, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err) amountToWithdrawLink := fulfilledEventLink.Payment - defaultWalletBalanceNativeBeforeOracleWithdraw, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) + defaultWalletBalanceNativeBeforeWithdraw, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - defaultWalletBalanceLinkBeforeOracleWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + defaultWalletBalanceLinkBeforeWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) l.Info(). @@ -569,9 +613,8 @@ func TestVRFv2Plus(t *testing.T) { Str("Amount", amountToWithdrawLink.String()). Msg("Invoking Oracle Withdraw for LINK") - err = vrfv2PlusContracts.Coordinator.OracleWithdraw( + err = vrfv2PlusContracts.Coordinator.Withdraw( common.HexToAddress(defaultWalletAddress), - amountToWithdrawLink, ) require.NoError(t, err, "error withdrawing LINK from coordinator to default wallet") amountToWithdrawNative := fulfilledEventNative.Payment @@ -581,24 +624,23 @@ func TestVRFv2Plus(t *testing.T) { Str("Amount", amountToWithdrawNative.String()). Msg("Invoking Oracle Withdraw for Native") - err = vrfv2PlusContracts.Coordinator.OracleWithdrawNative( + err = vrfv2PlusContracts.Coordinator.WithdrawNative( common.HexToAddress(defaultWalletAddress), - amountToWithdrawNative, ) require.NoError(t, err, "error withdrawing Native tokens from coordinator to default wallet") err = env.EVMClient.WaitForEvents() require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) - defaultWalletBalanceNativeAfterOracleWithdraw, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) + defaultWalletBalanceNativeAfterWithdraw, err := env.EVMClient.BalanceAt(testcontext.Get(t), common.HexToAddress(defaultWalletAddress)) require.NoError(t, err) - defaultWalletBalanceLinkAfterOracleWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) + defaultWalletBalanceLinkAfterWithdraw, err := linkToken.BalanceOf(testcontext.Get(t), defaultWalletAddress) require.NoError(t, err) //not possible to verify exact amount of Native/LINK returned as defaultWallet is used in other tests in parallel which might affect the balance - require.Equal(t, 1, defaultWalletBalanceNativeAfterOracleWithdraw.Cmp(defaultWalletBalanceNativeBeforeOracleWithdraw), "Native funds were not returned after oracle withdraw native") - require.Equal(t, 1, defaultWalletBalanceLinkAfterOracleWithdraw.Cmp(defaultWalletBalanceLinkBeforeOracleWithdraw), "LINK funds were not returned after oracle withdraw") + require.Equal(t, 1, defaultWalletBalanceNativeAfterWithdraw.Cmp(defaultWalletBalanceNativeBeforeWithdraw), "Native funds were not returned after oracle withdraw native") + require.Equal(t, 1, defaultWalletBalanceLinkAfterWithdraw.Cmp(defaultWalletBalanceLinkBeforeWithdraw), "LINK funds were not returned after oracle withdraw") }) } @@ -606,37 +648,38 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) - require.NoError(t, err) + config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + if err != nil { + t.Fatal(err) + } + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + mockETHLinkFeed, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkToken, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - // register proving key against oracle address (sending key) in order to test oracleWithdraw - defaultWalletAddress := env.EVMClient.GetDefaultWallet().Address() - numberOfTxKeysToCreate := 2 vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( env, - vrfv2PlusConfig, + &config, linkToken, mockETHLinkFeed, - defaultWalletAddress, numberOfTxKeysToCreate, 1, 1, @@ -652,7 +695,7 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { vrfv2plus.LogSubDetails(l, subscription, subID, vrfv2PlusContracts.Coordinator) t.Run("Request Randomness with multiple sending keys", func(t *testing.T) { - testConfig := vrfv2PlusConfig + configCopy := config.MustCopy().(tc.TestConfig) var isNativeBilling = false txKeys, _, err := env.ClCluster.Nodes[0].API.ReadTxKeys("evm") require.NoError(t, err, "error reading tx keys") @@ -667,9 +710,12 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { vrfv2PlusData, subID, isNativeBilling, - testConfig.RandomnessRequestCountPerRequest, - testConfig, - testConfig.RandomWordsFulfilledEventTimeout, + *configCopy.VRFv2Plus.General.MinimumConfirmations, + *configCopy.VRFv2Plus.General.CallbackGasLimit, + *configCopy.VRFv2Plus.General.NumberOfWords, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *configCopy.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, + configCopy.VRFv2Plus.General.RandomWordsFulfilledEventTimeout.Duration, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -696,35 +742,37 @@ func TestVRFv2PlusMultipleSendingKeys(t *testing.T) { func TestVRFv2PlusMigration(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - var vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig - err := envconfig.Process("VRFV2PLUS", &vrfv2PlusConfig) - require.NoError(t, err) + + config, err := tc.GetConfig("Smoke", tc.VRFv2Plus) + if err != nil { + t.Fatal(err) + } + + network, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") env, err := test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). - WithGeth(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(network). WithCLNodes(1). - WithFunding(big.NewFloat(vrfv2PlusConfig.ChainlinkNodeFunding)). + WithFunding(big.NewFloat(*config.Common.ChainlinkNodeFunding)). WithStandardCleanup(). Build() require.NoError(t, err, "error creating test env") env.ParallelTransactions(true) - mockETHLinkFeedAddress, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse)) + mockETHLinkFeedAddress, err := actions.DeployMockETHLinkFeed(env.ContractDeployer, big.NewInt(*config.VRFv2Plus.General.LinkNativeFeedResponse)) require.NoError(t, err, "error deploying mock ETH/LINK feed") linkAddress, err := actions.DeployLINKToken(env.ContractDeployer) require.NoError(t, err, "error deploying LINK contract") - nativeTokenPrimaryKeyAddress, err := env.ClCluster.NodeAPIs()[0].PrimaryEthAddress() - require.NoError(t, err, "error getting primary eth address") - vrfv2PlusContracts, subIDs, vrfv2PlusData, err := vrfv2plus.SetupVRFV2_5Environment( env, - vrfv2PlusConfig, + &config, linkAddress, mockETHLinkFeedAddress, - nativeTokenPrimaryKeyAddress, 0, 2, 1, @@ -754,18 +802,19 @@ func TestVRFv2PlusMigration(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) - _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfv2PlusData.VRFKey, vrfv2PlusData.PrimaryEthAddress, newCoordinator) + _, err = vrfv2plus.VRFV2PlusUpgradedVersionRegisterProvingKey(vrfv2PlusData.VRFKey, newCoordinator) require.NoError(t, err, fmt.Errorf("%s, err: %w", vrfv2plus.ErrRegisteringProvingKey, err)) + vrfv2PlusConfig := config.VRFv2Plus.General err = newCoordinator.SetConfig( - vrfv2PlusConfig.MinimumConfirmations, - vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, - vrfv2PlusConfig.StalenessSeconds, - vrfv2PlusConfig.GasAfterPaymentCalculation, - big.NewInt(vrfv2PlusConfig.LinkNativeFeedResponse), + *vrfv2PlusConfig.MinimumConfirmations, + *vrfv2PlusConfig.MaxGasLimitCoordinatorConfig, + *vrfv2PlusConfig.StalenessSeconds, + *vrfv2PlusConfig.GasAfterPaymentCalculation, + big.NewInt(*vrfv2PlusConfig.LinkNativeFeedResponse), vrf_v2plus_upgraded_version.VRFCoordinatorV2PlusUpgradedVersionFeeConfig{ - FulfillmentFlatFeeLinkPPM: vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, - FulfillmentFlatFeeNativePPM: vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, + FulfillmentFlatFeeLinkPPM: *vrfv2PlusConfig.FulfillmentFlatFeeLinkPPM, + FulfillmentFlatFeeNativePPM: *vrfv2PlusConfig.FulfillmentFlatFeeNativePPM, }, ) require.NoError(t, err) @@ -775,13 +824,23 @@ func TestVRFv2PlusMigration(t *testing.T) { err = env.EVMClient.WaitForEvents() require.NoError(t, err, vrfv2plus.ErrWaitTXsComplete) + vrfJobSpecConfig := vrfv2plus.VRFJobSpecConfig{ + ForwardingAllowed: false, + CoordinatorAddress: newCoordinator.Address(), + FromAddresses: []string{vrfv2PlusData.PrimaryEthAddress}, + EVMChainID: vrfv2PlusData.ChainID.String(), + MinIncomingConfirmations: int(*vrfv2PlusConfig.MinimumConfirmations), + PublicKey: vrfv2PlusData.VRFKey.Data.ID, + EstimateGasMultiplier: 1, + BatchFulfillmentEnabled: false, + BatchFulfillmentGasMultiplier: 1.15, + PollPeriod: time.Second * 1, + RequestTimeout: time.Hour * 24, + } + _, err = vrfv2plus.CreateVRFV2PlusJob( env.ClCluster.NodeAPIs()[0], - newCoordinator.Address(), - []string{vrfv2PlusData.PrimaryEthAddress}, - vrfv2PlusData.VRFKey.Data.ID, - vrfv2PlusData.ChainID.String(), - vrfv2PlusConfig.MinimumConfirmations, + vrfJobSpecConfig, ) require.NoError(t, err, vrfv2plus.ErrCreateVRFV2PlusJobs) @@ -867,7 +926,11 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, false, - vrfv2PlusConfig, + *config.VRFv2Plus.General.MinimumConfirmations, + *config.VRFv2Plus.General.CallbackGasLimit, + *config.VRFv2Plus.General.NumberOfWords, + *config.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *config.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") @@ -879,9 +942,12 @@ func TestVRFv2PlusMigration(t *testing.T) { vrfv2PlusData, subID, true, - vrfv2PlusConfig, + *config.VRFv2Plus.General.MinimumConfirmations, + *config.VRFv2Plus.General.CallbackGasLimit, + *config.VRFv2Plus.General.NumberOfWords, + *config.VRFv2Plus.General.RandomnessRequestCountPerRequest, + *config.VRFv2Plus.General.RandomnessRequestCountPerRequestDeviation, l, ) require.NoError(t, err, "error requesting randomness and waiting for fulfilment") - } diff --git a/integration-tests/soak/forwarder_ocr_test.go b/integration-tests/soak/forwarder_ocr_test.go index 538f5ff1569..b5355a6c3f5 100644 --- a/integration-tests/soak/forwarder_ocr_test.go +++ b/integration-tests/soak/forwarder_ocr_test.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) @@ -21,9 +22,12 @@ ForwardersEnabled = true` // fmt.Println(networks.AddNetworkDetailedConfig(config.BaseOCRP2PV1Config, customNetworkTOML, network)) // fmt.Println("---------------------") - ocrSoakTest, err := testsetups.NewOCRSoakTest(t, true) + config, err := tc.GetConfig("Soak", tc.OCR) + require.NoError(t, err, "Error getting config") + + ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config, true) require.NoError(t, err, "Error creating soak test") - ocrSoakTest.DeployEnvironment(customNetworkTOML) + ocrSoakTest.DeployEnvironment(customNetworkTOML, &config) if ocrSoakTest.Environment().WillUseRemoteRunner() { return } @@ -32,6 +36,6 @@ ForwardersEnabled = true` l.Error().Err(err).Msg("Error tearing down environment") } }) - ocrSoakTest.Setup() + ocrSoakTest.Setup(&config) ocrSoakTest.Run() } diff --git a/integration-tests/soak/ocr_test.go b/integration-tests/soak/ocr_test.go index 4d7971d678e..e25391e8450 100644 --- a/integration-tests/soak/ocr_test.go +++ b/integration-tests/soak/ocr_test.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink/integration-tests/actions" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/testsetups" ) @@ -21,10 +22,13 @@ func TestOCRSoak(t *testing.T) { // fmt.Println(networks.AddNetworkDetailedConfig(config.BaseOCR1Config, customNetworkTOML, network)) // fmt.Println("---------------------") - ocrSoakTest, err := testsetups.NewOCRSoakTest(t, false) + config, err := tc.GetConfig("Soak", tc.OCR) + require.NoError(t, err, "Error getting config") + + ocrSoakTest, err := testsetups.NewOCRSoakTest(t, &config, false) require.NoError(t, err, "Error creating soak test") if !ocrSoakTest.Interrupted() { - ocrSoakTest.DeployEnvironment(customNetworkTOML) + ocrSoakTest.DeployEnvironment(customNetworkTOML, &config) } if ocrSoakTest.Environment().WillUseRemoteRunner() { return @@ -39,7 +43,7 @@ func TestOCRSoak(t *testing.T) { require.NoError(t, err, "Error loading state") ocrSoakTest.Resume() } else { - ocrSoakTest.Setup() + ocrSoakTest.Setup(&config) ocrSoakTest.Run() } } diff --git a/integration-tests/testconfig/automation/automation.toml b/integration-tests/testconfig/automation/automation.toml new file mode 100644 index 00000000000..58b95f9b4cc --- /dev/null +++ b/integration-tests/testconfig/automation/automation.toml @@ -0,0 +1,49 @@ +# product defaults +[Common] +chainlink_node_funding = 0.5 + +# reorg test specific overrides +[Reorg.Automation] +[Reorg.Automation.General] +number_of_nodes=6 +duration=100 +block_time=1 +spec_type="minimum" +chainlink_node_log_level="info" +use_prometheus=false + +# load test specific overrides +[Load.Common] +chainlink_node_funding = 100 + +[Load.Automation] +[Load.Automation.General] +number_of_nodes=6 +duration=900 +block_time=1 +spec_type="minimum" +chainlink_node_log_level="info" +use_prometheus=false + +[[Load.Automation.Load]] +number_of_upkeeps=5 +number_of_events = 1 +number_of_spam_matching_events = 1 +number_of_spam_non_matching_events = 0 +check_burn_amount = 0 +perform_burn_amount = 0 +upkeep_gas_limit = 1000000 +shared_trigger = false + +[[Load.Automation.Load]] +number_of_upkeeps=5 +number_of_events = 1 +number_of_spam_matching_events = 0 +number_of_spam_non_matching_events = 1 +check_burn_amount = 0 +perform_burn_amount = 0 +upkeep_gas_limit = 1000000 +shared_trigger = true + +[Load.Pyroscope] +enabled=false \ No newline at end of file diff --git a/integration-tests/testconfig/automation/config.go b/integration-tests/testconfig/automation/config.go new file mode 100644 index 00000000000..4431a640d0d --- /dev/null +++ b/integration-tests/testconfig/automation/config.go @@ -0,0 +1,91 @@ +package automation + +import ( + "errors" + "math/big" +) + +type Config struct { + General *General `toml:"General"` + Load []Load `toml:"Load"` +} + +func (c *Config) Validate() error { + if c.General != nil { + if err := c.General.Validate(); err != nil { + return err + } + } + if len(c.Load) > 0 { + for _, load := range c.Load { + if err := load.Validate(); err != nil { + return err + } + } + } + return nil +} + +// General is a common configuration for all automation performance tests +type General struct { + NumberOfNodes *int `toml:"number_of_nodes"` + Duration *int `toml:"duration"` + BlockTime *int `toml:"block_time"` + SpecType *string `toml:"spec_type"` + ChainlinkNodeLogLevel *string `toml:"chainlink_node_log_level"` + UsePrometheus *bool `toml:"use_prometheus"` +} + +func (c *General) Validate() error { + if c.NumberOfNodes == nil || *c.NumberOfNodes < 1 { + return errors.New("number_of_nodes must be set to a positive integer") + } + if c.Duration == nil || *c.Duration < 1 { + return errors.New("duration must be set to a positive integer") + } + if c.BlockTime == nil || *c.BlockTime < 1 { + return errors.New("block_time must be set to a positive integer") + } + if c.SpecType == nil { + return errors.New("spec_type must be set") + } + if c.ChainlinkNodeLogLevel == nil { + return errors.New("chainlink_node_log_level must be set") + } + + return nil +} + +type Load struct { + NumberOfUpkeeps *int `toml:"number_of_upkeeps"` + NumberOfEvents *int `toml:"number_of_events"` + NumberOfSpamMatchingEvents *int `toml:"number_of_spam_matching_events"` + NumberOfSpamNonMatchingEvents *int `toml:"number_of_spam_non_matching_events"` + CheckBurnAmount *big.Int `toml:"check_burn_amount"` + PerformBurnAmount *big.Int `toml:"perform_burn_amount"` + SharedTrigger *bool `toml:"shared_trigger"` + UpkeepGasLimit *uint32 `toml:"upkeep_gas_limit"` +} + +func (c *Load) Validate() error { + if c.NumberOfUpkeeps == nil || *c.NumberOfUpkeeps < 1 { + return errors.New("number_of_upkeeps must be set to a positive integer") + } + if c.NumberOfEvents == nil || *c.NumberOfEvents < 0 { + return errors.New("number_of_events must be set to a non-negative integer") + } + if c.NumberOfSpamMatchingEvents == nil || *c.NumberOfSpamMatchingEvents < 0 { + return errors.New("number_of_spam_matching_events must be set to a non-negative integer") + } + if c.NumberOfSpamNonMatchingEvents == nil || *c.NumberOfSpamNonMatchingEvents < 0 { + return errors.New("number_of_spam_non_matching_events must be set to a non-negative integer") + } + if c.CheckBurnAmount == nil || c.CheckBurnAmount.Cmp(big.NewInt(0)) < 0 { + return errors.New("check_burn_amount must be set to a non-negative integer") + } + if c.PerformBurnAmount == nil || c.PerformBurnAmount.Cmp(big.NewInt(0)) < 0 { + return errors.New("perform_burn_amount must be set to a non-negative integer") + } + + return nil +} diff --git a/integration-tests/testconfig/automation/example.toml b/integration-tests/testconfig/automation/example.toml new file mode 100644 index 00000000000..a8e0510d83c --- /dev/null +++ b/integration-tests/testconfig/automation/example.toml @@ -0,0 +1,90 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Product part +[Automation] +[Automation.General] +number_of_nodes=6 +duration=100 +block_time=1 +number_of_events=1 +spec_type="minimum" +chainlink_node_log_level="info" +use_prometheus=false + +# upgrade test specific override +[TestAutomationNodeUpgrade.ChainlinkUpgradeImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.8.0" \ No newline at end of file diff --git a/integration-tests/testconfig/configs_embed.go b/integration-tests/testconfig/configs_embed.go new file mode 100644 index 00000000000..67e954ff503 --- /dev/null +++ b/integration-tests/testconfig/configs_embed.go @@ -0,0 +1,21 @@ +//go:build embed +// +build embed + +package testconfig + +import "embed" + +//go:embed default.toml +//go:embed automation/automation.toml +//go:embed functions/functions.toml +//go:embed keeper/keeper.toml +//go:embed log_poller/log_poller.toml +//go:embed node/node.toml +//go:embed ocr/ocr.toml +//go:embed vrfv2/vrfv2.toml +//go:embed vrfv2plus/vrfv2plus.toml +var embeddedConfigsFs embed.FS + +func init() { + areConfigsEmbedded = true +} diff --git a/integration-tests/testconfig/configs_noembed.go b/integration-tests/testconfig/configs_noembed.go new file mode 100644 index 00000000000..95572c4a044 --- /dev/null +++ b/integration-tests/testconfig/configs_noembed.go @@ -0,0 +1,12 @@ +//go:build !embed +// +build !embed + +package testconfig + +import "embed" + +var embeddedConfigsFs embed.FS + +func init() { + areConfigsEmbedded = false +} diff --git a/integration-tests/testconfig/default.toml b/integration-tests/testconfig/default.toml new file mode 100644 index 00000000000..a65c23d70dc --- /dev/null +++ b/integration-tests/testconfig/default.toml @@ -0,0 +1,22 @@ +[Logging] +test_log_collect=false + +[Logging.LogStream] +log_targets=["file"] +log_producer_timeout="10s" +log_producer_retry_limit=10 + +[Network] +selected_networks=["simulated"] + +[PrivateEthereumNetwork] +consensus_type="pow" +execution_layer="geth" + +[PrivateEthereumNetwork.EthereumChainConfig] +seconds_per_slot=3 +slots_per_epoch=2 +genesis_delay=15 +validator_count=4 +chain_id=1337 +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] \ No newline at end of file diff --git a/integration-tests/testconfig/functions/config.go b/integration-tests/testconfig/functions/config.go new file mode 100644 index 00000000000..88c0e052951 --- /dev/null +++ b/integration-tests/testconfig/functions/config.go @@ -0,0 +1,118 @@ +package functions + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink-testing-framework/utils/net" +) + +const ( + ErrReadPerfConfig = "failed to read TOML config for performance tests" + ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" +) + +type Config struct { + Performance *Performance `toml:"Performance"` + Common *Common `toml:"Common"` +} + +type Common struct { + NodeFunds *big.Float `toml:"node_funds"` + SubFunds *big.Int `toml:"sub_funds"` + LINKTokenAddr *string `toml:"link_token_addr"` + Coordinator *string `toml:"coordinator_addr"` + Router *string `toml:"router_addr"` + LoadTestClient *string `toml:"client_addr"` + SubscriptionID *uint64 `toml:"subscription_id"` + DONID *string `toml:"don_id"` + GatewayURL *string `toml:"gateway_url"` + Receiver *string `toml:"receiver"` + FunctionsCallPayloadHTTP *string `toml:"functions_call_payload_http"` + FunctionsCallPayloadWithSecrets *string `toml:"functions_call_payload_with_secrets"` + FunctionsCallPayloadReal *string `toml:"functions_call_payload_real"` + SecretsSlotID *uint8 `toml:"secrets_slot_id"` + SecretsVersionID *uint64 `toml:"secrets_version_id"` + // Secrets these are for CI secrets + Secrets *string `toml:"secrets"` +} + +func (c *Common) Validate() error { + if c.SubFunds == nil { + return errors.New("sub_funds must be set") + } + if c.LINKTokenAddr == nil || *c.LINKTokenAddr == "" { + return errors.New("link_token_addr must be set") + } + if !common.IsHexAddress(*c.LINKTokenAddr) { + return errors.New("link_token_addr must be a valid address") + } + if c.Coordinator == nil || *c.Coordinator == "" { + return errors.New("coordinator must be set") + } + if !common.IsHexAddress(*c.Coordinator) { + return errors.New("coordinator must be a valid address") + } + if c.Router == nil || *c.Router == "" { + return errors.New("router must be set") + } + if !common.IsHexAddress(*c.Router) { + return errors.New("router must be a valid address") + } + if c.DONID == nil || *c.DONID == "" { + return errors.New("don_id must be set") + } + if c.GatewayURL == nil || *c.GatewayURL == "" { + return errors.New("gateway_url must be set") + } + if !net.IsValidURL(*c.GatewayURL) { + return errors.New("gateway_url must be a valid URL") + } + if c.Receiver == nil || *c.Receiver == "" { + return errors.New("receiver must be set") + } + if !common.IsHexAddress(*c.Receiver) { + return errors.New("receiver must be a valid address") + } + return nil +} + +type Performance struct { + RPS *int64 `toml:"rps"` + RequestsPerCall *uint32 `toml:"requests_per_call"` + Duration *blockchain.StrDuration `toml:"duration"` +} + +func (c *Performance) Validate() error { + if c.RPS == nil || *c.RPS < 1 { + return errors.New("rps must be greater than 0") + } + if c.RequestsPerCall != nil && *c.RequestsPerCall < 1 { + return errors.New("requests_per_call must be greater than 0") + } + if c.Duration == nil || c.Duration.Duration < 1 { + return errors.New("duration must be greater than 0") + } + return nil +} + +func (c *Config) Validate() error { + if c == nil { + return nil + } + if c.Common != nil { + if err := c.Common.Validate(); err != nil { + return err + } + } + if c.Performance != nil { + if err := c.Performance.Validate(); err != nil { + return err + } + } + + return nil +} diff --git a/integration-tests/testconfig/functions/example.toml b/integration-tests/testconfig/functions/example.toml new file mode 100644 index 00000000000..7628fbeee32 --- /dev/null +++ b/integration-tests/testconfig/functions/example.toml @@ -0,0 +1,113 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use simulated network +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Product part +[Functions] +[Functions.Common] +# Polygon Mumbai only for now +receiver = "0x3098B6665589959711A48a6bAe5B7F2908f6a3bE" +don_id = "fun-staging-mumbai-1" +gateway_url = "https://gateway-stg-one.main.stage.cldev.sh" +link_token_addr = "0x326C977E6efc84E512bB9C30f76E30c160eD06FB" +coordinator_addr = "0x6D6a83BB356b7242E88C1A2b290102fde26590D0" +router_addr = "0x2673266D3Cd08b53494B5a92B66DEec7F1408E7A" + +# comment "client_addr" and "subscription_id" and test will create a new pair +# get it from logs and save +client_addr = "0x89D4b58D859a536D0B888ecD5093eF5FF9e4F977" +subscription_id = 47 +sub_funds = 10 + +functions_call_payload_with_secrets = "return Functions.encodeString(JSON.stringify(secrets))" +functions_call_payload_http = """ +const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/1' }); +return Functions.encodeUint256(response.data.id); +""" +functions_call_payload_real = """ +const arg1 = args[0]; +const arg2 = args[1]; +const arg3 = args[2]; +const arg4 = args[3]; + +const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/products/${arg1}' }); +return Functions.encodeString(JSON.stringify(secrets)); +""" +secrets_slot_id = 0 +secrets_version_id = 1693945705 + +[Functions.Performance] +rps = 95 +requests_per_call = 20 +duration = "10m" \ No newline at end of file diff --git a/integration-tests/load/functions/config.toml b/integration-tests/testconfig/functions/functions.toml similarity index 63% rename from integration-tests/load/functions/config.toml rename to integration-tests/testconfig/functions/functions.toml index 2de3ba9282c..a4bcb6439e4 100644 --- a/integration-tests/load/functions/config.toml +++ b/integration-tests/testconfig/functions/functions.toml @@ -1,42 +1,6 @@ -[Soak] -rps = 1 -requests_per_call = 40 -duration = "10m" - -[Stress] -rps = 1 -requests_per_call = 78 -duration = "10m" - -[SecretsSoak] -rps = 1 -requests_per_call = 20 -duration = "10m" - -[SecretsStress] -rps = 1 -requests_per_call = 40 -duration = "10m" - -[RealSoak] -rps = 1 -requests_per_call = 20 -duration = "10m" - -[RealStress] -rps = 1 -requests_per_call = 40 -duration = "10m" - -[GatewayListSoak] -rps = 95 -duration = "10m" - -[GatewaySetSoak] -rps = 95 -duration = "10m" - -[Common] +# product defaults +[Functions] +[Functions.Common] # Polygon Mumbai only for now receiver = "0x3098B6665589959711A48a6bAe5B7F2908f6a3bE" don_id = "fun-staging-mumbai-1" @@ -66,8 +30,62 @@ const response = await Functions.makeHttpRequest({ url: 'http://dummyjson.com/pr return Functions.encodeString(JSON.stringify(secrets)); """ secrets_slot_id = 0 -secrets_version = 1693945705 +secrets_version_id = 1693945705 # uncomment to upload new secrets to s4 and use it in your run # TODO: not working now -#secrets = "{\"secrets\": \"secretValue\"}" \ No newline at end of file +#secrets = "{\"secrets\": \"secretValue\"}" + +# gateway-list specific test configuration +[GatewayList.Functions] +[GatewayList.Functions.Performance] +rps = 95 +duration = "10m" + +# gateway-set specific test configuration +[GatewaySet.Functions] +[GatewaySet.Functions.Performance] +rps = 95 +duration = "10m" + +# real-soak specific test configuration +[RealSoak.Functions] +[RealSoak.Functions.Performance] +rps = 1 +requests_per_call = 20 +duration = "10m" + +# real-stress specific test configuration +[RealStress.Functions] +[RealStress.Functions.Performance] +rps = 1 +requests_per_call = 40 +duration = "10m" + +# secrets-soak specific test configuration +[SecretsSoak.Functions] +[SecretsSoak.Functions.Performance] +rps = 1 +requests_per_call = 20 +duration = "10m" + +# secrets-stress specific test configuration +[SecretsStress.Functions] +[SecretsStress.Functions.Performance] +rps = 1 +requests_per_call = 40 +duration = "10m" + +# soak specific test configuration +[Soak.Functions] +[Soak.Functions.Performance] +rps = 1 +requests_per_call = 40 +duration = "10m" + +# soak specific test configuration +[Stress.Functions] +[Stress.Functions.Performance] +rps = 1 +requests_per_call = 78 +duration = "10m" \ No newline at end of file diff --git a/integration-tests/testconfig/keeper/config.go b/integration-tests/testconfig/keeper/config.go new file mode 100644 index 00000000000..da6cd7acc98 --- /dev/null +++ b/integration-tests/testconfig/keeper/config.go @@ -0,0 +1,85 @@ +package keeper + +import ( + "errors" +) + +type Config struct { + Common *Common `toml:"Common"` +} + +func (c *Config) Validate() error { + if c.Common == nil { + return nil + } + return c.Common.Validate() +} + +type Common struct { + RegistryToTest *string `toml:"registry_to_test"` + NumberOfRegistries *int `toml:"number_of_registries"` + NumberOfNodes *int `toml:"number_of_nodes"` + NumberOfUpkeeps *int `toml:"number_of_upkeeps"` + UpkeepGasLimit *int64 `toml:"upkeep_gas_limit"` + CheckGasToBurn *int64 `toml:"check_gas_to_burn"` + PerformGasToBurn *int64 `toml:"perform_gas_to_burn"` + MaxPerformGas *int64 `toml:"max_perform_gas"` + BlockRange *int64 `toml:"block_range"` + BlockInterval *int64 `toml:"block_interval"` + ForceSingleTxKey *bool `toml:"forces_single_tx_key"` + DeleteJobsOnEnd *bool `toml:"delete_jobs_on_end"` + RegistryAddress *string `toml:"registry_address"` + RegistrarAddress *string `toml:"registrar_address"` + LinkTokenAddress *string `toml:"link_token_address"` + EthFeedAddress *string `toml:"eth_feed_address"` + GasFeedAddress *string `toml:"gas_feed_address"` +} + +func (c *Common) Validate() error { + if c.RegistryToTest == nil || *c.RegistryToTest == "" { + return errors.New("registry_to_test must be set") + } + if c.NumberOfRegistries == nil || *c.NumberOfRegistries <= 0 { + return errors.New("number_of_registries must be a positive integer") + } + if c.NumberOfNodes == nil || *c.NumberOfNodes <= 0 { + return errors.New("number_of_nodes must be a positive integer") + } + if c.NumberOfUpkeeps == nil || *c.NumberOfUpkeeps <= 0 { + return errors.New("number_of_upkeeps must be a positive integer") + } + if c.UpkeepGasLimit == nil || *c.UpkeepGasLimit <= 0 { + return errors.New("upkeep_gas_limit must be a positive integer") + } + if c.CheckGasToBurn == nil || *c.CheckGasToBurn <= 0 { + return errors.New("check_gas_to_burn must be a positive integer") + } + if c.PerformGasToBurn == nil || *c.PerformGasToBurn <= 0 { + return errors.New("perform_gas_to_burn must be a positive integer") + } + if c.MaxPerformGas == nil || *c.MaxPerformGas <= 0 { + return errors.New("max_perform_gas must be a positive integer") + } + if c.BlockRange == nil || *c.BlockRange <= 0 { + return errors.New("block_range must be a positive integer") + } + if c.BlockInterval == nil || *c.BlockInterval <= 0 { + return errors.New("block_interval must be a positive integer") + } + if c.RegistryAddress == nil { + c.RegistryAddress = new(string) + } + if c.RegistrarAddress == nil { + c.RegistrarAddress = new(string) + } + if c.LinkTokenAddress == nil { + c.LinkTokenAddress = new(string) + } + if c.EthFeedAddress == nil { + c.EthFeedAddress = new(string) + } + if c.GasFeedAddress == nil { + c.GasFeedAddress = new(string) + } + return nil +} diff --git a/integration-tests/testconfig/keeper/example.toml b/integration-tests/testconfig/keeper/example.toml new file mode 100644 index 00000000000..6bdd6537bc3 --- /dev/null +++ b/integration-tests/testconfig/keeper/example.toml @@ -0,0 +1,88 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Product part +[Common] +chainlink_node_funding = 0.5 + +[Keeper.Common] +registry_to_test = "2_1" +number_of_registries = 1 +number_of_nodes = 6 +number_of_upkeeps = 500 +upkeep_gas_limit = 150000 +check_gas_to_burn = 100000 +perform_gas_to_burn = 50000 +max_perform_gas = 5000000 +block_range = 3600 +block_interval = 20 +forces_single_tx_key = false +delete_jobs_on_end = true \ No newline at end of file diff --git a/integration-tests/testconfig/keeper/keeper.toml b/integration-tests/testconfig/keeper/keeper.toml new file mode 100644 index 00000000000..516dbb35a63 --- /dev/null +++ b/integration-tests/testconfig/keeper/keeper.toml @@ -0,0 +1,17 @@ +# product defaults +[Common] +chainlink_node_funding = 0.5 + +[Keeper.Common] +registry_to_test = "2_1" +number_of_registries = 1 +number_of_nodes = 6 +number_of_upkeeps = 500 +upkeep_gas_limit = 1500000 +check_gas_to_burn = 100000 +perform_gas_to_burn = 50000 +max_perform_gas = 5000000 +block_range = 3600 +block_interval = 20 +forces_single_tx_key = false +delete_jobs_on_end = true \ No newline at end of file diff --git a/integration-tests/testconfig/log_poller/config.go b/integration-tests/testconfig/log_poller/config.go new file mode 100644 index 00000000000..96c3b55c276 --- /dev/null +++ b/integration-tests/testconfig/log_poller/config.go @@ -0,0 +1,158 @@ +package logpoller + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" +) + +const ( + ErrReadPerfConfig = "failed to read TOML config for performance tests" + ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" +) + +type GeneratorType = string + +const ( + GeneratorType_WASP = "wasp" + GeneratorType_Looped = "looped" +) + +type Config struct { + General *General `toml:"General"` + ChaosConfig *ChaosConfig `toml:"Chaos"` + Wasp *WaspConfig `toml:"Wasp"` + LoopedConfig *LoopedConfig `toml:"Looped"` +} + +func (c *Config) Validate() error { + if c.General == nil { + return fmt.Errorf("General config must be set") + } + + err := c.General.Validate() + if err != nil { + return fmt.Errorf("General config validation failed: %w", err) + } + + switch *c.General.Generator { + case GeneratorType_WASP: + if c.Wasp == nil { + return fmt.Errorf("wasp config is nil") + } + err = c.Wasp.Validate() + if err != nil { + return fmt.Errorf("wasp config validation failed: %w", err) + } + case GeneratorType_Looped: + if c.LoopedConfig == nil { + return fmt.Errorf("looped config is nil") + } + err = c.LoopedConfig.Validate() + if err != nil { + return fmt.Errorf("looped config validation failed: %w", err) + } + default: + return fmt.Errorf("unknown generator type: %s", *c.General.Generator) + } + + if c.ChaosConfig != nil { + if err := c.ChaosConfig.Validate(); err != nil { + return fmt.Errorf("chaos config validation failed: %w", err) + } + } + + return nil +} + +type LoopedConfig struct { + ExecutionCount *int `toml:"execution_count"` + MinEmitWaitTimeMs *int `toml:"min_emit_wait_time_ms"` + MaxEmitWaitTimeMs *int `toml:"max_emit_wait_time_ms"` +} + +func (l *LoopedConfig) Validate() error { + if l.ExecutionCount == nil || *l.ExecutionCount == 0 { + return fmt.Errorf("execution_count must be set and > 0") + } + + if l.MinEmitWaitTimeMs == nil || *l.MinEmitWaitTimeMs == 0 { + return fmt.Errorf("min_emit_wait_time_ms must be set and > 0") + } + + if l.MaxEmitWaitTimeMs == nil || *l.MaxEmitWaitTimeMs == 0 { + return fmt.Errorf("max_emit_wait_time_ms must be set and > 0") + } + + return nil +} + +type General struct { + Generator *string `toml:"generator"` + EventsToEmit []abi.Event `toml:"-"` + Contracts *int `toml:"contracts"` + EventsPerTx *int `toml:"events_per_tx"` + UseFinalityTag *bool `toml:"use_finality_tag"` +} + +func (g *General) Validate() error { + if g.Generator == nil || *g.Generator == "" { + return fmt.Errorf("generator is empty") + } + + if g.Contracts == nil || *g.Contracts == 0 { + return fmt.Errorf("contracts is 0, but must be > 0") + } + + if g.EventsPerTx == nil || *g.EventsPerTx == 0 { + return fmt.Errorf("events_per_tx is 0, but must be > 0") + } + + return nil +} + +type ChaosConfig struct { + ExperimentCount *int `toml:"experiment_count"` + TargetComponent *string `toml:"target_component"` +} + +func (c *ChaosConfig) Validate() error { + if c.ExperimentCount != nil && *c.ExperimentCount == 0 { + return fmt.Errorf("experiment_count must be > 0") + } + + return nil +} + +type WaspConfig struct { + RPS *int64 `toml:"rps"` + LPS *int64 `toml:"lps"` + RateLimitUnitDuration *blockchain.StrDuration `toml:"rate_limit_unit_duration"` + Duration *blockchain.StrDuration `toml:"duration"` + CallTimeout *blockchain.StrDuration `toml:"call_timeout"` +} + +func (w *WaspConfig) Validate() error { + if w.RPS == nil && w.LPS == nil { + return fmt.Errorf("either RPS or LPS needs to be set") + } + if *w.RPS == 0 && *w.LPS == 0 { + return fmt.Errorf("either RPS or LPS needs to be a positive integer") + } + if *w.RPS != 0 && *w.LPS != 0 { + return fmt.Errorf("only one of RPS or LPS can be set") + } + if w.Duration == nil || w.Duration.Duration == 0 { + return fmt.Errorf("duration must be set and > 0") + } + if w.CallTimeout == nil || w.CallTimeout.Duration == 0 { + return fmt.Errorf("call_timeout must be set and > 0") + } + if w.RateLimitUnitDuration == nil || w.RateLimitUnitDuration.Duration == 0 { + return fmt.Errorf("rate_limit_unit_duration must be set and > 0") + } + + return nil +} diff --git a/integration-tests/testconfig/log_poller/example.toml b/integration-tests/testconfig/log_poller/example.toml new file mode 100644 index 00000000000..90ec89a3ed1 --- /dev/null +++ b/integration-tests/testconfig/log_poller/example.toml @@ -0,0 +1,87 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Product part +[LogPoller] +[LogPoller.General] +generator = "looped" +contracts = 2 +events_per_tx = 4 +use_finality_tag = true + +[LogPoller.Looped] +execution_count = 100 +min_emit_wait_time_ms = 200 +max_emit_wait_time_ms = 500 \ No newline at end of file diff --git a/integration-tests/testconfig/log_poller/log_poller.toml b/integration-tests/testconfig/log_poller/log_poller.toml new file mode 100644 index 00000000000..2f46ebf11c2 --- /dev/null +++ b/integration-tests/testconfig/log_poller/log_poller.toml @@ -0,0 +1,61 @@ +# product defaults +[LogPoller] +[LogPoller.General] +generator = "looped" +contracts = 2 +events_per_tx = 4 +use_finality_tag = true + +[LogPoller.Looped] +execution_count = 100 +min_emit_wait_time_ms = 200 +max_emit_wait_time_ms = 500 + +# test-specific +[TestLogPollerFewFiltersFixedDepth.LogPoller.General] +use_finality_tag = false + +[TestLogManyFiltersPollerFinalityTag.LogPoller.General] +contracts = 300 +events_per_tx = 3 + +[TestLogManyFiltersPollerFinalityTag.LogPoller.Looped] +execution_count = 30 + +[TestLogManyFiltersPollerFixedDepth.LogPoller.General] +use_finality_tag = false +contracts = 300 +events_per_tx = 3 + +[TestLogManyFiltersPollerFixedDepth.LogPoller.Looped] +execution_count = 30 + +[TestLogPollerWithChaosFinalityTag.LogPoller.General] +execution_count = 30 +[TestLogPollerWithChaosFinalityTag.LogPoller.Chaos] +experiment_count = 4 +target_component = "chainlink" + +[TestLogPollerWithChaosFixedDepth.LogPoller.General] +execution_count = 30 +use_finality_tag = false +[TestLogPollerWithChaosFixedDepth.LogPoller.Chaos] +experiment_count = 4 +target_component = "chainlink" + +[TestLogPollerWithChaosPostgresFinalityTag.LogPoller.General] +execution_count = 30 +[TestLogPollerWithChaosPostgresFinalityTag.LogPoller.Chaos] +experiment_count = 4 +target_component = "postgres" + +[TestLogPollerWithChaosPostgresFixedDepth.LogPoller.General] +execution_count = 30 +use_finality_tag = false +[TestLogPollerWithChaosPostgresFixedDepth.LogPoller.Chaos] +experiment_count = 4 +target_component = "postgres" + +[TestLogPollerReplayFixedDepth.LogPoller.General] +use_finality_tag = false + diff --git a/integration-tests/testconfig/node/example.toml b/integration-tests/testconfig/node/example.toml new file mode 100644 index 00000000000..55ee1ffccf1 --- /dev/null +++ b/integration-tests/testconfig/node/example.toml @@ -0,0 +1,79 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Test-specific part +[ChainlinkUpgradeImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.8.0" \ No newline at end of file diff --git a/integration-tests/testconfig/node/node.toml b/integration-tests/testconfig/node/node.toml new file mode 100644 index 00000000000..683b55a35a1 --- /dev/null +++ b/integration-tests/testconfig/node/node.toml @@ -0,0 +1,5 @@ +# original image +[ChainlinkImage] + +# image to upgrade to +[ChainlinkUpgradeImage] \ No newline at end of file diff --git a/integration-tests/testconfig/ocr/example.toml b/integration-tests/testconfig/ocr/example.toml new file mode 100644 index 00000000000..6cbdbef1555 --- /dev/null +++ b/integration-tests/testconfig/ocr/example.toml @@ -0,0 +1,96 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# load test specific configuration +[Load.OCR] +[Load.OCR.Common] +eth_funds = 3 + +[Load.OCR.Load] +test_duration = "3m" +rate_limit_unit_duration = "1m" +rate = 3 +verification_interval = "5s" +verification_timeout = "3m" +ea_change_interval = "5s" + +# soak test specific configuration +[Soak.Common] +chainlink_node_funding = 100 + +[Soak.OCR] +[Soak.OCR.Common] +test_duration="15m" + +[Soak.OCR.Soak] +ocr_version="1" +number_of_contracts=2 +time_between_rounds="1m" \ No newline at end of file diff --git a/integration-tests/testconfig/ocr/ocr.go b/integration-tests/testconfig/ocr/ocr.go new file mode 100644 index 00000000000..0fd995a96f1 --- /dev/null +++ b/integration-tests/testconfig/ocr/ocr.go @@ -0,0 +1,136 @@ +package ocr + +import ( + "errors" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" +) + +type Config struct { + Soak *SoakConfig `toml:"Soak"` + Load *Load `toml:"Load"` + Volume *Volume `toml:"Volume"` + Common *Common `toml:"Common"` +} + +func (o *Config) Validate() error { + if o.Common != nil { + if err := o.Common.Validate(); err != nil { + return err + } + } + if o.Soak != nil { + if err := o.Soak.Validate(); err != nil { + return err + } + } + if o.Volume != nil { + if err := o.Volume.Validate(); err != nil { + return err + } + } + return nil +} + +type Common struct { + ETHFunds *int `toml:"eth_funds"` + TestDuration *blockchain.StrDuration `toml:"test_duration"` +} + +func (o *Common) Validate() error { + if o.ETHFunds != nil && *o.ETHFunds < 0 { + return errors.New("eth_funds must be set and cannot be negative") + } + return nil +} + +type Load struct { + Rate *int64 `toml:"rate"` + RequestsPerUnit *int `toml:"requests_per_unit"` + RateLimitUnitDuration *blockchain.StrDuration `toml:"rate_limit_unit_duration"` + VerificationInterval *blockchain.StrDuration `toml:"verification_interval"` + VerificationTimeout *blockchain.StrDuration `toml:"verification_timeout"` + EAChangeInterval *blockchain.StrDuration `toml:"ea_change_interval"` + TestDuration *blockchain.StrDuration `toml:"test_duration"` +} + +func (o *Load) Validate() error { + if o.TestDuration == nil { + return errors.New("load test duration must be set") + } + if o.Rate == nil || *o.Rate <= 0 { + return errors.New("rate must be set and be a positive integer") + } + if o.RequestsPerUnit == nil || *o.RequestsPerUnit <= 0 { + return errors.New("vu_requests_per_unit must be set and be a positive integer") + } + if o.RateLimitUnitDuration == nil || o.RateLimitUnitDuration.Duration == 0 { + return errors.New("rate_limit_unit_duration must be set and be a positive integer") + } + if o.VerificationInterval == nil || o.VerificationInterval.Duration == 0 { + return errors.New("verification_interval must be set and be a positive integer") + } + if o.VerificationTimeout == nil || o.VerificationTimeout.Duration == 0 { + return errors.New("verification_timeout must be set and be a positive integer") + } + if o.EAChangeInterval == nil || o.EAChangeInterval.Duration == 0 { + return errors.New("ea_change_interval must be set and be a positive integer") + } + + return nil +} + +type Volume struct { + Rate *int64 `toml:"rate"` + VURequestsPerUnit *int `toml:"vu_requests_per_unit"` + RateLimitUnitDuration *blockchain.StrDuration `toml:"rate_limit_unit_duration"` + VerificationInterval *blockchain.StrDuration `toml:"verification_interval"` + VerificationTimeout *blockchain.StrDuration `toml:"verification_timeout"` + EAChangeInterval *blockchain.StrDuration `toml:"ea_change_interval"` + TestDuration *blockchain.StrDuration `toml:"test_duration"` +} + +func (o *Volume) Validate() error { + if o.TestDuration == nil { + return errors.New("volume test duration must be set") + } + if o.Rate == nil || *o.Rate <= 0 { + return errors.New("rate must be set and be a positive integer") + } + if o.VURequestsPerUnit == nil || *o.VURequestsPerUnit <= 0 { + return errors.New("vu_requests_per_unit must be set and be a positive integer") + } + if o.RateLimitUnitDuration == nil || o.RateLimitUnitDuration.Duration == 0 { + return errors.New("rate_limit_unit_duration must be set and be a positive integer") + } + if o.VerificationInterval == nil || o.VerificationInterval.Duration == 0 { + return errors.New("verification_interval must be set and be a positive integer") + } + if o.VerificationTimeout == nil || o.VerificationTimeout.Duration == 0 { + return errors.New("verification_timeout must be set and be a positive integer") + } + if o.EAChangeInterval == nil || o.EAChangeInterval.Duration == 0 { + return errors.New("ea_change_interval must be set and be a positive integer") + } + + return nil +} + +type SoakConfig struct { + OCRVersion *string `toml:"ocr_version"` + NumberOfContracts *int `toml:"number_of_contracts"` + TimeBetweenRounds *blockchain.StrDuration `toml:"time_between_rounds"` +} + +func (o *SoakConfig) Validate() error { + if o.OCRVersion == nil || *o.OCRVersion == "" { + return errors.New("ocr_version must be set to either 1 or 2") + } + if o.NumberOfContracts == nil || *o.NumberOfContracts <= 1 { + return errors.New("number_of_contracts must be set and be greater than 1") + } + if o.TimeBetweenRounds == nil || o.TimeBetweenRounds.Duration == 0 { + return errors.New("time_between_rounds must be set and be a positive integer") + } + return nil +} diff --git a/integration-tests/testconfig/ocr/ocr.toml b/integration-tests/testconfig/ocr/ocr.toml new file mode 100644 index 00000000000..8d3c73ca761 --- /dev/null +++ b/integration-tests/testconfig/ocr/ocr.toml @@ -0,0 +1,43 @@ +# product defaults +[Common] +chainlink_node_funding = 0.5 + +# load test specific configuration +[Load.OCR] +[Load.OCR.Common] +eth_funds = 3 + +[Load.OCR.Load] +test_duration = "3m" +rate_limit_unit_duration = "1m" +rate = 3 +verification_interval = "5s" +verification_timeout = "3m" +ea_change_interval = "5s" + +# volume test specific configuration +[Volume.OCR] +[Volume.OCR.Common] +eth_funds = 3 + +[Volume.OCR.Volume] +test_duration = "3m" +rate_limit_unit_duration = "1m" +vu_requests_per_unit = 10 +rate = 1 +verification_interval = "5s" +verification_timeout = "3m" +ea_change_interval = "5s" + +# soak test specific configuration +[Soak.Common] +chainlink_node_funding = 100 + +[Soak.OCR] +[Soak.OCR.Common] +test_duration="15m" + +[Soak.OCR.Soak] +ocr_version="1" +number_of_contracts=2 +time_between_rounds="1m" \ No newline at end of file diff --git a/integration-tests/testconfig/testconfig.go b/integration-tests/testconfig/testconfig.go new file mode 100644 index 00000000000..c80202bf45c --- /dev/null +++ b/integration-tests/testconfig/testconfig.go @@ -0,0 +1,540 @@ +package testconfig + +import ( + "embed" + "encoding/base64" + "fmt" + "os" + "slices" + "strings" + + "github.com/barkimedes/go-deepcopy" + "github.com/google/uuid" + "github.com/pelletier/go-toml/v2" + "github.com/pkg/errors" + "github.com/rs/zerolog" + "golang.org/x/text/cases" + "golang.org/x/text/language" + + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" + "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" + k8s_config "github.com/smartcontractkit/chainlink-testing-framework/k8s/config" + "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/utils/osutil" + a_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/automation" + f_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/functions" + keeper_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/keeper" + lp_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/log_poller" + ocr_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/ocr" + vrf_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrf" + vrfv2_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" + vrfv2plus_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2plus" +) + +type GlobalTestConfig interface { + GetChainlinkImageConfig() *ctf_config.ChainlinkImageConfig + GetLoggingConfig() *ctf_config.LoggingConfig + GetNetworkConfig() *ctf_config.NetworkConfig + GetPrivateEthereumNetworkConfig() *test_env.EthereumNetwork + GetPyroscopeConfig() *ctf_config.PyroscopeConfig +} + +type UpgradeableChainlinkTestConfig interface { + GetChainlinkUpgradeImageConfig() *ctf_config.ChainlinkImageConfig +} + +type CommonTestConfig interface { + GetCommonConfig() *Common +} + +type VRFv2TestConfig interface { + GetVRFv2Config() *vrfv2_config.Config +} + +type VRFv2PlusTestConfig interface { + GetVRFv2PlusConfig() *vrfv2plus_config.Config +} + +type FunctionsTestConfig interface { + GetFunctionsConfig() *f_config.Config +} + +type KeeperTestConfig interface { + GetKeeperConfig() *keeper_config.Config +} + +type OcrTestConfig interface { + GetOCRConfig() *ocr_config.Config +} + +type NamedConfiguration interface { + GetConfigurationName() string +} + +type TestConfig struct { + ChainlinkImage *ctf_config.ChainlinkImageConfig `toml:"ChainlinkImage"` + ChainlinkUpgradeImage *ctf_config.ChainlinkImageConfig `toml:"ChainlinkUpgradeImage"` + Logging *ctf_config.LoggingConfig `toml:"Logging"` + Network *ctf_config.NetworkConfig `toml:"Network"` + Pyroscope *ctf_config.PyroscopeConfig `toml:"Pyroscope"` + PrivateEthereumNetwork *ctf_test_env.EthereumNetwork `toml:"PrivateEthereumNetwork"` + + Common *Common `toml:"Common"` + Automation *a_config.Config `toml:"Automation"` + Functions *f_config.Config `toml:"Functions"` + Keeper *keeper_config.Config `toml:"Keeper"` + LogPoller *lp_config.Config `toml:"LogPoller"` + OCR *ocr_config.Config `toml:"OCR"` + VRF *vrf_config.Config `toml:"VRF"` + VRFv2 *vrfv2_config.Config `toml:"VRFv2"` + VRFv2Plus *vrfv2plus_config.Config `toml:"VRFv2Plus"` + + ConfigurationName string `toml:"-"` +} + +var embeddedConfigs embed.FS +var areConfigsEmbedded bool + +func init() { + embeddedConfigs = embeddedConfigsFs +} + +// Returns Grafana URL from Logging config +func (c *TestConfig) GetGrafanaBaseURL() (string, error) { + if c.Logging.Grafana == nil || c.Logging.Grafana.BaseUrl == nil { + return "", errors.New("grafana base url not set") + } + + return strings.TrimSuffix(*c.Logging.Grafana.BaseUrl, "/"), nil +} + +// Returns Grafana Dashboard URL from Logging config +func (c *TestConfig) GetGrafanaDashboardURL() (string, error) { + if c.Logging.Grafana == nil || c.Logging.Grafana.DashboardUrl == nil { + return "", errors.New("grafana dashboard url not set") + } + + url := *c.Logging.Grafana.DashboardUrl + if !strings.HasPrefix(url, "/") { + url = "/" + url + } + + return url, nil +} + +// Saves Test Config to a local file +func (c *TestConfig) Save() (string, error) { + filePath := fmt.Sprintf("test_config-%s.toml", uuid.New()) + + content, err := toml.Marshal(*c) + if err != nil { + return "", errors.Wrapf(err, "error marshaling test config") + } + + err = os.WriteFile(filePath, content, 0600) + if err != nil { + return "", errors.Wrapf(err, "error writing test config") + } + + return filePath, nil +} + +// MustCopy Returns a deep copy of the Test Config or panics on error +func (c TestConfig) MustCopy() any { + return deepcopy.MustAnything(c).(TestConfig) +} + +// MustCopy Returns a deep copy of struct passed to it and returns a typed copy (or panics on error) +func MustCopy[T any](c T) T { + return deepcopy.MustAnything(c).(T) +} + +func (c *TestConfig) GetLoggingConfig() *ctf_config.LoggingConfig { + return c.Logging +} + +func (c TestConfig) GetNetworkConfig() *ctf_config.NetworkConfig { + return c.Network +} + +func (c TestConfig) GetChainlinkImageConfig() *ctf_config.ChainlinkImageConfig { + return c.ChainlinkImage +} + +func (c TestConfig) GetPrivateEthereumNetworkConfig() *ctf_test_env.EthereumNetwork { + return c.PrivateEthereumNetwork +} + +func (c TestConfig) GetPyroscopeConfig() *ctf_config.PyroscopeConfig { + return c.Pyroscope +} + +func (c TestConfig) GetCommonConfig() *Common { + return c.Common +} + +func (c TestConfig) GetVRFv2Config() *vrfv2_config.Config { + return c.VRFv2 +} + +func (c TestConfig) GetFunctionsConfig() *f_config.Config { + return c.Functions +} + +func (c TestConfig) GetVRFv2PlusConfig() *vrfv2plus_config.Config { + return c.VRFv2Plus +} + +func (c TestConfig) GetChainlinkUpgradeImageConfig() *ctf_config.ChainlinkImageConfig { + return c.ChainlinkUpgradeImage +} + +func (c TestConfig) GetKeeperConfig() *keeper_config.Config { + return c.Keeper +} + +func (c TestConfig) GetOCRConfig() *ocr_config.Config { + return c.OCR +} + +func (c TestConfig) GetConfigurationName() string { + return c.ConfigurationName +} + +type Common struct { + ChainlinkNodeFunding *float64 `toml:"chainlink_node_funding"` +} + +func (c *Common) Validate() error { + if c.ChainlinkNodeFunding != nil && *c.ChainlinkNodeFunding < 0 { + return fmt.Errorf("chainlink node funding must be positive") + } + + return nil +} + +type Product string + +const ( + Automation Product = "automation" + Cron Product = "cron" + DirectRequest Product = "direct_request" + Flux Product = "flux" + ForwarderOcr Product = "forwarder_ocr" + ForwarderOcr2 Product = "forwarder_ocr2" + Functions Product = "functions" + Keeper Product = "keeper" + LogPoller Product = "log_poller" + Node Product = "node" + OCR Product = "ocr" + OCR2 Product = "ocr2" + OCR2VRF Product = "ocr2vrf" + RunLog Product = "runlog" + VRF Product = "vrf" + VRFv2 Product = "vrfv2" + VRFv2Plus Product = "vrfv2plus" +) + +var TestTypesWithLoki = []string{"Load", "Soak", "Stress", "Spike", "Volume"} + +const TestTypeEnvVarName = "TEST_TYPE" + +func GetConfigurationNameFromEnv() (string, error) { + testType := os.Getenv(TestTypeEnvVarName) + if testType == "" { + return "", fmt.Errorf("%s env var not set", TestTypeEnvVarName) + } + + return cases.Title(language.English, cases.NoLower).String(testType), nil +} + +const ( + Base64OverrideEnvVarName = k8s_config.EnvBase64ConfigOverride + NoKey = "NO_KEY" +) + +func GetConfig(configurationName string, product Product) (TestConfig, error) { + logger := logging.GetTestLogger(nil) + + configurationName = strings.ReplaceAll(configurationName, "/", "_") + configurationName = strings.ReplaceAll(configurationName, " ", "_") + configurationName = cases.Title(language.English, cases.NoLower).String(configurationName) + fileNames := []string{ + "default.toml", + fmt.Sprintf("%s.toml", product), + "overrides.toml", + } + + testConfig := TestConfig{} + testConfig.ConfigurationName = configurationName + logger.Debug().Msgf("Will apply configuration named '%s' if it is found in any of the configs", configurationName) + + var handleSpecialOverrides = func(logger zerolog.Logger, filename, configurationName string, target *TestConfig, content []byte, product Product) error { + switch product { + case Automation: + return handleAutomationConfigOverride(logger, filename, configurationName, target, content) + default: + err := ctf_config.BytesToAnyTomlStruct(logger, filename, configurationName, &testConfig, content) + if err != nil { + return errors.Wrapf(err, "error reading file %s", filename) + } + + return nil + } + } + + // read embedded configs is build tag "embed" is set + // this makes our life much easier when using a binary + if areConfigsEmbedded { + logger.Info().Msg("Reading embedded configs") + embeddedFiles := []string{"default.toml", fmt.Sprintf("%s/%s.toml", product, product)} + for _, fileName := range embeddedFiles { + file, err := embeddedConfigs.ReadFile(fileName) + if err != nil && errors.Is(err, os.ErrNotExist) { + logger.Debug().Msgf("Embedded config file %s not found. Continuing", fileName) + continue + } else if err != nil { + return TestConfig{}, errors.Wrapf(err, "error reading embedded config") + } + + err = handleSpecialOverrides(logger, fileName, configurationName, &testConfig, file, product) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error unmarshalling embedded config") + } + } + } + + logger.Info().Msg("Reading configs from file system") + for _, fileName := range fileNames { + logger.Debug().Msgf("Looking for config file %s", fileName) + filePath, err := osutil.FindFile(fileName, osutil.DEFAULT_STOP_FILE_NAME, 3) + + if err != nil && errors.Is(err, os.ErrNotExist) { + logger.Debug().Msgf("Config file %s not found", fileName) + continue + } else if err != nil { + return TestConfig{}, errors.Wrapf(err, "error looking for file %s", filePath) + } + logger.Debug().Str("location", filePath).Msgf("Found config file %s", fileName) + + content, err := readFile(filePath) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error reading file %s", filePath) + } + + err = handleSpecialOverrides(logger, fileName, configurationName, &testConfig, content, product) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error reading file %s", filePath) + } + } + + logger.Info().Msg("Reading configs from Base64 override env var") + configEncoded, isSet := os.LookupEnv(Base64OverrideEnvVarName) + if isSet && configEncoded != "" { + logger.Debug().Msgf("Found base64 config override environment variable '%s' found", Base64OverrideEnvVarName) + decoded, err := base64.StdEncoding.DecodeString(configEncoded) + if err != nil { + return TestConfig{}, err + } + + err = handleSpecialOverrides(logger, Base64OverrideEnvVarName, configurationName, &testConfig, decoded, product) + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error unmarshaling base64 config") + } + } else { + logger.Debug().Msg("Base64 config override from environment variable not found") + } + + // it neede some custom logic, so we do it separately + err := testConfig.readNetworkConfiguration() + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error reading network config") + } + + logger.Debug().Msg("Validating test config") + err = testConfig.Validate() + if err != nil { + return TestConfig{}, errors.Wrapf(err, "error validating test config") + } + + if testConfig.Common == nil { + testConfig.Common = &Common{} + } + + logger.Debug().Msg("Correct test config constructed successfully") + return testConfig, nil +} + +func (c *TestConfig) readNetworkConfiguration() error { + // currently we need to read that kind of secrets only for network configuration + if c == nil { + c.Network = &ctf_config.NetworkConfig{} + } + + c.Network.UpperCaseNetworkNames() + err := c.Network.Default() + if err != nil { + return errors.Wrapf(err, "error reading default network config") + } + + // this is the only value we need to generate dynamically before starting a new simulated chain + if c.PrivateEthereumNetwork != nil && c.PrivateEthereumNetwork.EthereumChainConfig != nil { + c.PrivateEthereumNetwork.EthereumChainConfig.GenerateGenesisTimestamp() + } + + return nil +} + +func (c *TestConfig) Validate() error { + defer func() { + if r := recover(); r != nil { + panic(fmt.Errorf("Panic during test config validation: '%v'. Most probably due to presence of partial product config", r)) + } + }() + if c.ChainlinkImage == nil { + return fmt.Errorf("chainlink image config must be set") + } + if err := c.ChainlinkImage.Validate(); err != nil { + return errors.Wrapf(err, "chainlink image config validation failed") + } + if c.ChainlinkUpgradeImage != nil { + if err := c.ChainlinkUpgradeImage.Validate(); err != nil { + return errors.Wrapf(err, "chainlink upgrade image config validation failed") + } + } + if err := c.Network.Validate(); err != nil { + return errors.Wrapf(err, "network config validation failed") + } + + if c.Logging == nil { + return fmt.Errorf("logging config must be set") + } + + if err := c.Logging.Validate(); err != nil { + return errors.Wrapf(err, "logging config validation failed") + } + + // require Loki config only if these tests run locally + _, willUseRemoteRunner := os.LookupEnv(k8s_config.EnvVarJobImage) + _, isInsideK8s := os.LookupEnv(k8s_config.EnvVarInsideK8s) + if (!willUseRemoteRunner && !isInsideK8s) && slices.Contains(TestTypesWithLoki, c.ConfigurationName) { + if c.Logging.Loki == nil { + return fmt.Errorf("for local execution you must set Loki config in logging config") + } + + if err := c.Logging.Loki.Validate(); err != nil { + return errors.Wrapf(err, "loki config validation failed") + } + } + + if c.Logging.LogStream != nil && slices.Contains(c.Logging.LogStream.LogTargets, "loki") { + if c.Logging.Loki == nil { + return fmt.Errorf("in order to use Loki as logging target you must set Loki config in logging config") + } + + if err := c.Logging.Loki.Validate(); err != nil { + return errors.Wrapf(err, "loki config validation failed") + } + } + + if c.Pyroscope != nil { + if err := c.Pyroscope.Validate(); err != nil { + return errors.Wrapf(err, "pyroscope config validation failed") + } + } + + if c.PrivateEthereumNetwork != nil { + if err := c.PrivateEthereumNetwork.Validate(); err != nil { + return errors.Wrapf(err, "private ethereum network config validation failed") + } + } + + if c.Common != nil { + if err := c.Common.Validate(); err != nil { + return errors.Wrapf(err, "Common config validation failed") + } + } + + if c.Automation != nil { + if err := c.Automation.Validate(); err != nil { + return errors.Wrapf(err, "Automation config validation failed") + } + } + + if c.Functions != nil { + if err := c.Functions.Validate(); err != nil { + return errors.Wrapf(err, "Functions config validation failed") + } + } + + if c.Keeper != nil { + if err := c.Keeper.Validate(); err != nil { + return errors.Wrapf(err, "Keeper config validation failed") + } + } + + if c.LogPoller != nil { + if err := c.LogPoller.Validate(); err != nil { + return errors.Wrapf(err, "LogPoller config validation failed") + } + } + + if c.OCR != nil { + if err := c.OCR.Validate(); err != nil { + return errors.Wrapf(err, "OCR config validation failed") + } + } + + if c.VRF != nil { + if err := c.VRF.Validate(); err != nil { + return errors.Wrapf(err, "VRF config validation failed") + } + } + + if c.VRFv2 != nil { + if err := c.VRFv2.Validate(); err != nil { + return errors.Wrapf(err, "VRFv2 config validation failed") + } + } + + if c.VRFv2Plus != nil { + if err := c.VRFv2Plus.Validate(); err != nil { + return errors.Wrapf(err, "VRFv2Plus config validation failed") + } + } + + return nil +} + +func readFile(filePath string) ([]byte, error) { + content, err := os.ReadFile(filePath) + if err != nil { + return nil, errors.Wrapf(err, "error reading file %s", filePath) + } + + return content, nil +} + +func handleAutomationConfigOverride(logger zerolog.Logger, filename, configurationName string, target *TestConfig, content []byte) error { + logger.Debug().Msgf("Handling automation config override for %s", filename) + oldConfig := MustCopy(target) + newConfig := TestConfig{} + + err := ctf_config.BytesToAnyTomlStruct(logger, filename, configurationName, &target, content) + if err != nil { + return errors.Wrapf(err, "error reading file %s", filename) + } + + err = ctf_config.BytesToAnyTomlStruct(logger, filename, configurationName, &newConfig, content) + if err != nil { + return errors.Wrapf(err, "error reading file %s", filename) + } + + // override instead of merging + if (newConfig.Automation != nil && len(newConfig.Automation.Load) > 0) && (oldConfig != nil && oldConfig.Automation != nil && len(oldConfig.Automation.Load) > 0) { + target.Automation.Load = newConfig.Automation.Load + } + + return nil +} diff --git a/integration-tests/testconfig/testconfig_test.go b/integration-tests/testconfig/testconfig_test.go new file mode 100644 index 00000000000..4a9dbdaade3 --- /dev/null +++ b/integration-tests/testconfig/testconfig_test.go @@ -0,0 +1,88 @@ +package testconfig + +import ( + "encoding/base64" + "math/big" + "os" + "testing" + + "github.com/pelletier/go-toml/v2" + "github.com/test-go/testify/require" + + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" + "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + a_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/automation" +) + +func TestBase64ConfigRead(t *testing.T) { + networkConfigTOML := ` + [RpcHttpUrls] + arbitrum_goerli = ["https://devnet-1.mt/ABC/rpc/"] + optimism_goerli = ["https://devnet-3.mt/ABC/rpc/"] + + [RpcWsUrls] + arbitrum_goerli = ["wss://devnet-1.mt/ABC/rpc/"] + optimism_goerli = ["wss://devnet-2.mt/ABC/rpc/"] + ` + networksEncoded := base64.StdEncoding.EncodeToString([]byte(networkConfigTOML)) + os.Setenv(ctf_config.Base64NetworkConfigEnvVarName, networksEncoded) + + testConfig := TestConfig{ + Automation: &a_config.Config{ + General: &a_config.General{ + NumberOfNodes: ptr.Ptr(7), + Duration: ptr.Ptr(9), + BlockTime: ptr.Ptr(10), + SpecType: ptr.Ptr("minimum"), + ChainlinkNodeLogLevel: ptr.Ptr("debug"), + }, + Load: []a_config.Load{ + { + NumberOfUpkeeps: ptr.Ptr(1), + NumberOfEvents: ptr.Ptr(2), + NumberOfSpamMatchingEvents: ptr.Ptr(3), + NumberOfSpamNonMatchingEvents: ptr.Ptr(4), + CheckBurnAmount: big.NewInt(5), + PerformBurnAmount: big.NewInt(6), + SharedTrigger: ptr.Ptr(true), + }, + { + NumberOfUpkeeps: ptr.Ptr(3), + NumberOfEvents: ptr.Ptr(2), + NumberOfSpamMatchingEvents: ptr.Ptr(3), + NumberOfSpamNonMatchingEvents: ptr.Ptr(7), + CheckBurnAmount: big.NewInt(5), + PerformBurnAmount: big.NewInt(6), + SharedTrigger: ptr.Ptr(false), + }, + }, + }, + Network: &ctf_config.NetworkConfig{ + SelectedNetworks: []string{"OPTIMISM_GOERLI"}, + RpcHttpUrls: map[string][]string{ + "OPTIMISM_GOERLI": {"http://localhost:8545"}, + }, + WalletKeys: map[string][]string{ + "OPTIMISM_GOERLI": {"0x3333333333333333333333333333333333333333"}, + }, + }, + } + + configMarshalled, err := toml.Marshal(testConfig) + require.NoError(t, err, "Error marshalling test config") + + testConfigEncoded := base64.StdEncoding.EncodeToString(configMarshalled) + os.Setenv(Base64OverrideEnvVarName, testConfigEncoded) + + readConfig, err := GetConfig("test", Automation) + require.NoError(t, err, "Error reading config") + + require.NotNil(t, readConfig.Automation, "Automation config read from base64 is nil") + require.Equal(t, testConfig.Automation.General, readConfig.Automation.General, "General automation config does not match expected") + require.EqualValues(t, testConfig.Automation.Load, readConfig.Automation.Load, "Load automation config does not match expected") + require.NotNil(t, readConfig.Network, "Network config read from base64 is nil") + require.Equal(t, testConfig.Network.SelectedNetworks, readConfig.Network.SelectedNetworks, "SelectedNetwork config entry read from base64 does not match expected") + require.Equal(t, []string{"http://localhost:8545"}, readConfig.Network.RpcHttpUrls["OPTIMISM_GOERLI"], "RpcHttpUrls config entry read from base64 does not match expected") + require.Equal(t, []string{"wss://devnet-2.mt/ABC/rpc/"}, readConfig.Network.RpcWsUrls["OPTIMISM_GOERLI"], "RpcWsUrls config entry read from base64 network defaults does not match expected") + require.Equal(t, testConfig.Network.WalletKeys, readConfig.Network.WalletKeys, "WalletKeys config entry read from base64 does not match expected") +} diff --git a/integration-tests/testconfig/vrf/config.go b/integration-tests/testconfig/vrf/config.go new file mode 100644 index 00000000000..d009f5bf667 --- /dev/null +++ b/integration-tests/testconfig/vrf/config.go @@ -0,0 +1,8 @@ +package vrf + +type Config struct { +} + +func (o *Config) Validate() error { + return nil +} diff --git a/integration-tests/testconfig/vrfv2/config.go b/integration-tests/testconfig/vrfv2/config.go new file mode 100644 index 00000000000..f539d91799c --- /dev/null +++ b/integration-tests/testconfig/vrfv2/config.go @@ -0,0 +1,330 @@ +package testconfig + +import ( + "errors" + + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" +) + +const ( + ErrDeviationShouldBeLessThanOriginal = "`RandomnessRequestCountPerRequestDeviation` should be less than `RandomnessRequestCountPerRequest`" +) + +type Config struct { + Common *Common `toml:"Common"` + General *General `toml:"General"` + ExistingEnvConfig *ExistingEnvConfig `toml:"ExistingEnv"` + NewEnvConfig *NewEnvConfig `toml:"NewEnv"` + Performance *PerformanceConfig `toml:"Performance"` +} + +func (c *Config) Validate() error { + if c.Common != nil { + if err := c.Common.Validate(); err != nil { + return err + } + } + if c.General != nil { + if err := c.General.Validate(); err != nil { + return err + } + } + if c.Performance != nil { + if err := c.Performance.Validate(); err != nil { + return err + } + if *c.Performance.UseExistingEnv { + if c.ExistingEnvConfig != nil { + if err := c.ExistingEnvConfig.Validate(); err != nil { + return err + } + } + } else { + if c.NewEnvConfig != nil { + if err := c.NewEnvConfig.Validate(); err != nil { + return err + } + } + } + } + + return nil +} + +type Common struct { + CancelSubsAfterTestRun *bool `toml:"cancel_subs_after_test_run"` +} + +func (c *Common) Validate() error { + return nil +} + +type PerformanceConfig struct { + TestDuration *blockchain.StrDuration `toml:"test_duration"` + RPS *int64 `toml:"rps"` + RateLimitUnitDuration *blockchain.StrDuration `toml:"rate_limit_unit_duration"` + + // Using existing environment and contracts + UseExistingEnv *bool `toml:"use_existing_env"` + CoordinatorAddress *string + ConsumerAddress *string + LinkAddress *string + SubID *uint64 + KeyHash *string +} + +func (c *PerformanceConfig) Validate() error { + if c.TestDuration == nil || c.TestDuration.Duration == 0 { + return errors.New("test_duration must be set to a positive value") + } + if c.RPS == nil || *c.RPS == 0 { + return errors.New("rps must be set to a positive value") + } + if c.RateLimitUnitDuration == nil { + return errors.New("rate_limit_unit_duration must be set ") + } + if c.UseExistingEnv == nil { + return errors.New("use_existing_env must be set ") + } + + return nil +} + +type ExistingEnvConfig struct { + CoordinatorAddress *string `toml:"coordinator_address"` + ConsumerAddress *string `toml:"consumer_address"` + LinkAddress *string `toml:"link_address"` + SubID *uint64 `toml:"sub_id"` + KeyHash *string `toml:"key_hash"` + CreateFundSubsAndAddConsumers *bool `toml:"create_fund_subs_and_add_consumers"` + NodeSendingKeys []string `toml:"node_sending_keys"` + Funding +} + +func (c *ExistingEnvConfig) Validate() error { + if c.CreateFundSubsAndAddConsumers == nil { + return errors.New("create_fund_subs_and_add_consumers must be set ") + } + if c.CoordinatorAddress == nil { + return errors.New("coordinator_address must be set when using existing environment") + } + if !common.IsHexAddress(*c.CoordinatorAddress) { + return errors.New("coordinator_address must be a valid hex address") + } + if c.KeyHash == nil { + return errors.New("key_hash must be set when using existing environment") + } + if *c.KeyHash == "" { + return errors.New("key_hash must be a non-empty string") + } + if c.LinkAddress != nil && !common.IsHexAddress(*c.LinkAddress) { + return errors.New("link_address must be a valid hex address") + } + + if *c.CreateFundSubsAndAddConsumers { + if err := c.Funding.Validate(); err != nil { + return err + } + if err := c.Funding.SubFunding.Validate(); err != nil { + return err + } + } else { + if c.ConsumerAddress == nil || *c.ConsumerAddress == "" { + return errors.New("consumer_address must be set when using existing environment") + } + if !common.IsHexAddress(*c.ConsumerAddress) { + return errors.New("consumer_address must be a valid hex address") + } + if c.SubID == nil { + return errors.New("sub_id must be set when using existing environment") + } + if *c.SubID == 0 { + return errors.New("sub_id must be a positive value") + } + } + + if c.NodeSendingKeys != nil { + for _, key := range c.NodeSendingKeys { + if !common.IsHexAddress(key) { + return errors.New("node_sending_keys must be a valid hex address") + } + } + } + + return nil +} + +type NewEnvConfig struct { + *Funding +} + +func (c *NewEnvConfig) Validate() error { + if c.Funding != nil { + return c.Funding.Validate() + } + + return nil +} + +type Funding struct { + SubFunding + NodeSendingKeyFunding *float64 `toml:"node_sending_key_funding"` + NodeSendingKeyFundingMin *float64 `toml:"node_sending_key_funding_min"` +} + +func (c *Funding) Validate() error { + if c.NodeSendingKeyFunding != nil && *c.NodeSendingKeyFunding <= 0 { + return errors.New("when set node_sending_key_funding must be a positive value") + } + if c.NodeSendingKeyFundingMin != nil && *c.NodeSendingKeyFundingMin <= 0 { + return errors.New("when set node_sending_key_funding_min must be a positive value") + } + + return nil +} + +type SubFunding struct { + SubFundsLink *float64 `toml:"sub_funds_link"` +} + +func (c *SubFunding) Validate() error { + if c.SubFundsLink != nil && *c.SubFundsLink < 0 { + return errors.New("when set sub_funds_link must be a non-negative value") + } + + return nil +} + +type General struct { + CLNodeMaxGasPriceGWei *int64 `toml:"max_gas_price_gwei"` // Max gas price in GWei for the chainlink node + LinkNativeFeedResponse *int64 `toml:"link_native_feed_response"` // Response of the LINK/ETH feed + MinimumConfirmations *uint16 `toml:"minimum_confirmations" ` // Minimum number of confirmations for the VRF Coordinator + SubscriptionFundingAmountLink *float64 `toml:"subscription_funding_amount_link"` // Amount of LINK to fund the subscription with + 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 + 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 + FulfillmentFlatFeeLinkPPMTier1 *uint32 `toml:"fulfilment_flat_fee_link_ppm_tier_1"` + FulfillmentFlatFeeLinkPPMTier2 *uint32 `toml:"fulfilment_flat_fee_link_ppm_tier_2"` + FulfillmentFlatFeeLinkPPMTier3 *uint32 `toml:"fulfilment_flat_fee_link_ppm_tier_3"` + FulfillmentFlatFeeLinkPPMTier4 *uint32 `toml:"fulfilment_flat_fee_link_ppm_tier_4"` + FulfillmentFlatFeeLinkPPMTier5 *uint32 `toml:"fulfilment_flat_fee_link_ppm_tier_5"` + ReqsForTier2 *int64 `toml:"reqs_for_tier_2"` + ReqsForTier3 *int64 `toml:"reqs_for_tier_3"` + ReqsForTier4 *int64 `toml:"reqs_for_tier_4"` + ReqsForTier5 *int64 `toml:"reqs_for_tier_5"` + + NumberOfSubToCreate *int `toml:"number_of_sub_to_create"` // Number of subscriptions to create + + RandomnessRequestCountPerRequest *uint16 `toml:"randomness_request_count_per_request"` // How many randomness requests to send per request + RandomnessRequestCountPerRequestDeviation *uint16 `toml:"randomness_request_count_per_request_deviation"` // How many randomness requests to send per request + + RandomWordsFulfilledEventTimeout *blockchain.StrDuration `toml:"random_words_fulfilled_event_timeout"` // How long to wait for the RandomWordsFulfilled event to be emitted + + // Wrapper Config + WrapperGasOverhead *uint32 `toml:"wrapped_gas_overhead"` + CoordinatorGasOverhead *uint32 `toml:"coordinator_gas_overhead"` + WrapperPremiumPercentage *uint8 `toml:"wrapper_premium_percentage"` + 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"` +} + +func (c *General) Validate() error { + if c.CLNodeMaxGasPriceGWei == nil || *c.CLNodeMaxGasPriceGWei == 0 { + return errors.New("max_gas_price_gwei must be set to a positive value") + } + if c.LinkNativeFeedResponse == nil || *c.LinkNativeFeedResponse == 0 { + return errors.New("link_native_feed_response must be set to a positive value") + } + if c.MinimumConfirmations == nil { + return errors.New("minimum_confirmations must be set to a non-negative value") + } + if c.SubscriptionFundingAmountLink == nil || *c.SubscriptionFundingAmountLink == 0 { + return errors.New("subscription_funding_amount_link must be set to a positive value") + } + if c.NumberOfWords == nil || *c.NumberOfWords == 0 { + return errors.New("number_of_words must be set to a positive value") + } + if c.CallbackGasLimit == nil || *c.CallbackGasLimit == 0 { + return errors.New("callback_gas_limit must be set to a positive value") + } + 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.StalenessSeconds == nil || *c.StalenessSeconds == 0 { + return errors.New("staleness_seconds must be set to a positive value") + } + if c.GasAfterPaymentCalculation == nil || *c.GasAfterPaymentCalculation == 0 { + return errors.New("gas_after_payment_calculation must be set to a positive value") + } + if c.FulfillmentFlatFeeLinkPPMTier1 == nil || *c.FulfillmentFlatFeeLinkPPMTier1 == 0 { + return errors.New("fulfilment_flat_fee_link_ppm_tier_1 must be set to a positive value") + } + if c.FulfillmentFlatFeeLinkPPMTier2 == nil || *c.FulfillmentFlatFeeLinkPPMTier2 == 0 { + return errors.New("fulfilment_flat_fee_link_ppm_tier_2 must be set to a positive value") + } + if c.FulfillmentFlatFeeLinkPPMTier3 == nil || *c.FulfillmentFlatFeeLinkPPMTier3 == 0 { + return errors.New("fulfilment_flat_fee_link_ppm_tier_3 must be set to a positive value") + } + if c.FulfillmentFlatFeeLinkPPMTier4 == nil || *c.FulfillmentFlatFeeLinkPPMTier4 == 0 { + return errors.New("fulfilment_flat_fee_link_ppm_tier_4 must be set to a positive value") + } + if c.FulfillmentFlatFeeLinkPPMTier5 == nil || *c.FulfillmentFlatFeeLinkPPMTier5 == 0 { + return errors.New("fulfilment_flat_fee_link_ppm_tier_5 must be set to a positive value") + } + if c.ReqsForTier2 == nil || *c.ReqsForTier2 < 0 { + return errors.New("reqs_for_tier_2 must be set to a non-negative value") + } + if c.ReqsForTier3 == nil || *c.ReqsForTier3 < 0 { + return errors.New("reqs_for_tier_3 must be set to a non-negative value") + } + if c.ReqsForTier4 == nil || *c.ReqsForTier4 < 0 { + return errors.New("reqs_for_tier_4 must be set to a non-negative value") + } + if c.ReqsForTier5 == nil || *c.ReqsForTier5 < 0 { + return errors.New("reqs_for_tier_5 must be set to a non-negative value") + } + if c.NumberOfSubToCreate == nil || *c.NumberOfSubToCreate == 0 { + return errors.New("number_of_sub_to_create must be set to a positive value") + } + if c.RandomnessRequestCountPerRequest == nil || *c.RandomnessRequestCountPerRequest == 0 { + return errors.New("randomness_request_count_per_request must be set to a positive value") + } + if c.RandomnessRequestCountPerRequestDeviation == nil { + return errors.New("randomness_request_count_per_request_deviation must be set to a non-negative value") + } + if c.RandomWordsFulfilledEventTimeout == nil || c.RandomWordsFulfilledEventTimeout.Duration == 0 { + return errors.New("random_words_fulfilled_event_timeout must be set to a positive value") + } + 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") + } + if c.WrapperConsumerFundingAmountNativeToken == nil || *c.WrapperConsumerFundingAmountNativeToken < 0 { + return errors.New("wrapper_consumer_funding_amount_native_token must be set to a non-negative value") + } + if c.WrapperConsumerFundingAmountLink == nil || *c.WrapperConsumerFundingAmountLink < 0 { + return errors.New("wrapper_consumer_funding_amount_link must be set to a non-negative value") + } + if *c.RandomnessRequestCountPerRequest <= *c.RandomnessRequestCountPerRequestDeviation { + return errors.New(ErrDeviationShouldBeLessThanOriginal) + } + + return nil +} diff --git a/integration-tests/testconfig/vrfv2/example.toml b/integration-tests/testconfig/vrfv2/example.toml new file mode 100644 index 00000000000..bc826ebe05e --- /dev/null +++ b/integration-tests/testconfig/vrfv2/example.toml @@ -0,0 +1,136 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Product part +[VRFv2] +[VRFv2.Common] +cancel_subs_after_test_run = true + +[VRFv2.General] +max_gas_price_gwei = 1000 +link_native_feed_response = 1000000000000000000 +minimum_confirmations = 3 +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 +staleness_seconds = 86400 +gas_after_payment_calculation = 33825 +fulfilment_flat_fee_link_ppm_tier_1 = 500 +fulfilment_flat_fee_link_ppm_tier_2 = 500 +fulfilment_flat_fee_link_ppm_tier_3 = 500 +fulfilment_flat_fee_link_ppm_tier_4 = 500 +fulfilment_flat_fee_link_ppm_tier_5 = 500 +reqs_for_tier_2 = 0 +reqs_for_tier_3 = 0 +reqs_for_tier_4 = 0 +reqs_for_tier_5 = 0 +number_of_sub_to_create = 1 +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 +wrapper_premium_percentage = 25 +wrapper_max_number_of_words = 10 +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 10 + +[VRFv2.Performance] +rate_limit_unit_duration = "3s" +rps = 1 + +[VRFv2.NewEnv] +sub_funds_link = 1000 +node_sending_key_funding = 1000 + +[VRFv2.ExistingEnv] +coordinator_address = "" +consumer_address = "" +sub_id = 1 +key_hash = "" +create_fund_subs_and_add_consumers = true +link_address = "" +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [ + "", + "", + "", + "", + "", + "", +] \ No newline at end of file diff --git a/integration-tests/testconfig/vrfv2/vrfv2.toml b/integration-tests/testconfig/vrfv2/vrfv2.toml new file mode 100644 index 00000000000..64e628c4afa --- /dev/null +++ b/integration-tests/testconfig/vrfv2/vrfv2.toml @@ -0,0 +1,143 @@ +# default config +[Common] +chainlink_node_funding = 0.1 + +[VRFv2] +[VRFv2.General] +max_gas_price_gwei = 10 +link_native_feed_response = 1000000000000000000 +minimum_confirmations = 3 +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 +staleness_seconds = 86400 +gas_after_payment_calculation = 33825 +fulfilment_flat_fee_link_ppm_tier_1 = 500 +fulfilment_flat_fee_link_ppm_tier_2 = 500 +fulfilment_flat_fee_link_ppm_tier_3 = 500 +fulfilment_flat_fee_link_ppm_tier_4 = 500 +fulfilment_flat_fee_link_ppm_tier_5 = 500 +reqs_for_tier_2 = 0 +reqs_for_tier_3 = 0 +reqs_for_tier_4 = 0 +reqs_for_tier_5 = 0 +number_of_sub_to_create = 1 +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 +wrapper_premium_percentage = 25 +wrapper_max_number_of_words = 10 +wrapper_consumer_funding_amount_native_token = 1.0 +wrapper_consumer_funding_amount_link = 10 + +# load test specific config +[Load.VRFv2] +[Load.VRFv2.Common] +cancel_subs_after_test_run = true + +[Load.VRFv2.General] +minimum_confirmations = 3 +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 + +[Load.VRFv2.Performance] +# approx 60 RPM - 1 tx request with 3 rand requests in each tx every 3 seconds +rate_limit_unit_duration = "3s" +rps = 1 + +[Load.VRFv2.NewEnv] +sub_funds_link = 1000 +node_sending_key_funding = 1000 + +[Load.VRFv2.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# soak test specific config +[Soak.VRFv2] +[VRFv2.Common] +cancel_subs_after_test_run = true + +[Soak.VRFv2.General] +minimum_confirmations = 3 +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 + +[Soak.VRFv2.Performance] +# 10 RPM - 1 tx request with 1 rand request in each tx every 6 seconds +rate_limit_unit_duration = "6s" +rps = 1 + +[Soak.VRFv2.NewEnv] +sub_funds_link = 1000 +node_sending_key_funding = 1000 + +[Soak.VRFv2.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# spike test specific config +[Spike.VRFv2] +[Spike.VRFv2.Common] +cancel_subs_after_test_run = true + +[Spike.VRFv2.General] +minimum_confirmations = 3 +randomness_request_count_per_request = 150 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 + +[Spike.VRFv2.Performance] +# approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds +rate_limit_unit_duration = "1m" +rps = 1 + +[Spike.VRFv2.NewEnv] +sub_funds_link = 1000 +node_sending_key_funding = 1000 + +[Spike.VRFv2.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# stress test specific config +[Stress.VRFv2] +[Stress.VRFv2.Common] +cancel_subs_after_test_run = true + +[Stress.VRFv2.General] +minimum_confirmations = 3 +randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 + +[Stress.VRFv2.Performance] +# approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx +rate_limit_unit_duration = "1s" +rps = 3 + +[Stress.VRFv2.NewEnv] +sub_funds_link = 1000 +node_sending_key_funding = 1000 + +[Stress.VRFv2.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] diff --git a/integration-tests/testconfig/vrfv2plus/config.go b/integration-tests/testconfig/vrfv2plus/config.go new file mode 100644 index 00000000000..667803e06b6 --- /dev/null +++ b/integration-tests/testconfig/vrfv2plus/config.go @@ -0,0 +1,158 @@ +package testconfig + +import ( + "errors" + + vrfv2 "github.com/smartcontractkit/chainlink/integration-tests/testconfig/vrfv2" +) + +type BillingType string + +const ( + BillingType_Link BillingType = "LINK" + BillingType_Native BillingType = "NATIVE" + BillingType_Link_and_Native BillingType = "LINK_AND_NATIVE" +) + +type Config struct { + Common *Common `toml:"Common"` + General *General `toml:"General"` + ExistingEnvConfig *ExistingEnvConfig `toml:"ExistingEnv"` + NewEnvConfig *NewEnvConfig `toml:"NewEnv"` + Performance *vrfv2.PerformanceConfig `toml:"Performance"` +} + +func (c *Config) Validate() error { + if c.Common != nil { + if err := c.Common.Validate(); err != nil { + return err + } + } + if c.General != nil { + if err := c.General.Validate(); err != nil { + return err + } + } + if c.Performance != nil { + if err := c.Performance.Validate(); err != nil { + return err + } + if *c.Performance.UseExistingEnv { + if c.ExistingEnvConfig != nil { + if err := c.ExistingEnvConfig.Validate(); err != nil { + return err + } + } + } else { + if c.NewEnvConfig != nil { + if err := c.NewEnvConfig.Validate(); err != nil { + return err + } + } + } + } + + return nil +} + +type Common struct { + *vrfv2.Common +} + +func (c *Common) Validate() error { + if c.Common == nil { + return nil + } + return c.Common.Validate() +} + +type General struct { + *vrfv2.General + SubscriptionBillingType *string `toml:"subscription_billing_type"` // Billing type for the subscription + SubscriptionFundingAmountNative *float64 `toml:"subscription_funding_amount_native"` // Amount of LINK to fund the subscription with + FulfillmentFlatFeeLinkPPM *uint32 `toml:"fulfillment_flat_fee_link_ppm"` // Flat fee in ppm for LINK for the VRF Coordinator config + FulfillmentFlatFeeNativePPM *uint32 `toml:"fulfillment_flat_fee_native_ppm"` // Flat fee in ppm for native currency for the VRF Coordinator config +} + +func (c *General) Validate() error { + if err := c.General.Validate(); err != nil { + return err + } + if c.SubscriptionBillingType == nil || *c.SubscriptionBillingType == "" { + return errors.New("subscription_billing_type must be set to either: LINK, NATIVE, LINK_AND_NATIVE") + } + if c.SubscriptionFundingAmountNative == nil || *c.SubscriptionFundingAmountNative <= 0 { + return errors.New("subscription_funding_amount_native must be greater than 0") + } + if c.FulfillmentFlatFeeLinkPPM == nil || *c.FulfillmentFlatFeeLinkPPM <= 0 { + return errors.New("fulfillment_flat_fee_link_ppm must be greater than 0") + } + if c.FulfillmentFlatFeeNativePPM == nil || *c.FulfillmentFlatFeeNativePPM <= 0 { + return errors.New("fulfillment_flat_fee_native_ppm must be greater than 0") + } + + return nil +} + +type NewEnvConfig struct { + *Funding +} + +func (c *NewEnvConfig) Validate() error { + if c.Funding == nil { + return nil + } + + return c.Funding.Validate() +} + +type ExistingEnvConfig struct { + *vrfv2.ExistingEnvConfig + Funding +} + +func (c *ExistingEnvConfig) Validate() error { + if c.ExistingEnvConfig != nil { + if err := c.ExistingEnvConfig.Validate(); err != nil { + return err + } + } + + return c.Funding.Validate() +} + +type Funding struct { + SubFunding + NodeSendingKeyFunding *float64 `toml:"node_sending_key_funding"` + NodeSendingKeyFundingMin *float64 `toml:"node_sending_key_funding_min"` +} + +func (c *Funding) Validate() error { + if c.NodeSendingKeyFunding != nil && *c.NodeSendingKeyFunding <= 0 { + return errors.New("when set node_sending_key_funding must be a positive value") + } + if c.NodeSendingKeyFundingMin != nil && *c.NodeSendingKeyFundingMin <= 0 { + return errors.New("when set node_sending_key_funding_min must be a positive value") + } + + return c.SubFunding.Validate() +} + +type SubFunding struct { + SubFundsLink *float64 `toml:"sub_funds_link"` + SubFundsNative *float64 `toml:"sub_funds_native"` +} + +func (c *SubFunding) Validate() error { + if c.SubFundsLink == nil || c.SubFundsNative == nil { + return errors.New("both sub_funds_link and sub_funds_native must be set") + } + if c.SubFundsLink != nil && *c.SubFundsLink < 0 { + return errors.New("sub_funds_link must be a non-negative number") + } + if c.SubFundsNative != nil && *c.SubFundsNative < 0 { + return errors.New("sub_funds_native must be a non-negative number") + } + + return nil +} diff --git a/integration-tests/testconfig/vrfv2plus/example.toml b/integration-tests/testconfig/vrfv2plus/example.toml new file mode 100644 index 00000000000..a9ce5b2dcf5 --- /dev/null +++ b/integration-tests/testconfig/vrfv2plus/example.toml @@ -0,0 +1,144 @@ +# Example of full config with all fields +# General part +[ChainlinkImage] +image="public.ecr.aws/chainlink/chainlink" +version="2.7.0" + +[Logging] +# if set to true will save logs even if test did not fail +test_log_collect=false + +[Logging.LogStream] +# supported targets: file, loki, in-memory. if empty no logs will be persistet +log_targets=["file"] +# context timeout for starting log producer and also time-frame for requesting logs +log_producer_timeout="10s" +# number of retries before log producer gives up and stops listening to logs +log_producer_retry_limit=10 + +[Logging.Loki] +tenant_id="tenant_id" +# full URL of Loki ingest endpoint +endpoint="https://loki.url/api/v3/push" +# currently only needed when using public instance +basic_auth="loki-basic-auth" +# only needed for cloud grafana +bearer_token="bearer_token" + +# LogStream will try to shorten Grafana URLs by default (if all 3 variables are set) +[Logging.Grafana] +# grafana url (trailing "/" will be stripped) +base_url="http://grafana.url" +# url of your grafana dashboard (prefix and suffix "/" are stirpped), example: /d/ad61652-2712-1722/my-dashboard +dashboard_url="/d/your-dashboard" +bearer_token="my-awesome-token" + +# if you want to use polygon_mumbial +[Network] +selected_networks=["polygon_mumbai"] + +[Network.RpcHttpUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.RpcWsUrls] +polygon_mumbai = ["https://my-rpc-endpoint.io"] + +[Network.WalletKeys] +polygon_mumbai = ["change-me-to-your-PK"] + +[PrivateEthereumNetwork] +# pos or pow +consensus_type="pos" +# only prysm supported currently +consensus_layer="prysm" +# geth, besu, nethermind or erigon +execution_layer="geth" +# if true after env started it will wait for at least 1 epoch to be finalised before continuing +wait_for_finalization=false + +[PrivateEthereumNetwork.EthereumChainConfig] +# duration of single slot, lower => faster block production, must be >= 4 +seconds_per_slot=12 +# numer of slots in epoch, lower => faster epoch finalisation, must be >= 4 +slots_per_epoch=6 +# extra genesis gelay, no need to modify, but it should be after all validators/beacon chain starts +genesis_delay=15 +# number of validators in the network +validator_count=8 +chain_id=1337 +# list of addresses to be prefunded in genesis +addresses_to_fund=["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"] + +# Common +[Common] +chainlink_node_funding = 0.5 + +# Product part +[VRFv2Plus] +[VRFv2Plus.Common] +cancel_subs_after_test_run = true + +[VRFv2Plus.General] +max_gas_price_gwei = 1000 +link_native_feed_response = 1000000000000000000 +minimum_confirmations = 3 +subscription_billing_type = "LINK_AND_NATIVE" +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 +staleness_seconds = 86400 +gas_after_payment_calculation = 33825 +fulfilment_flat_fee_link_ppm_tier_1 = 500 +fulfilment_flat_fee_link_ppm_tier_2 = 500 +fulfilment_flat_fee_link_ppm_tier_3 = 500 +fulfilment_flat_fee_link_ppm_tier_4 = 500 +fulfilment_flat_fee_link_ppm_tier_5 = 500 +reqs_for_tier_2 = 0 +reqs_for_tier_3 = 0 +reqs_for_tier_4 = 0 +reqs_for_tier_5 = 0 +number_of_sub_to_create = 1 +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 +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 + +[VRFv2Plus.Performance] +test_duration = "2m" +rate_limit_unit_duration = "3s" +rps = 1 +use_existing_env = false + +[VRFv2Plus.NewEnv] +sub_funds_link = 1 +sub_funds_native = 1 +node_funds = 10 +node_sending_key_funding = 1000 + +[VRFv2Plus.ExistingEnv] +coordinator_address = "" +consumer_address = "" +sub_id = 1 +key_hash = "" +create_fund_subs_and_add_consumers = true +link_address = "" +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [ + "", + "", + "", + "", + "", + "", +] \ No newline at end of file diff --git a/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml new file mode 100644 index 00000000000..5e187d9de3a --- /dev/null +++ b/integration-tests/testconfig/vrfv2plus/vrfv2plus.toml @@ -0,0 +1,161 @@ +# default config +[Common] +chainlink_node_funding = 0.1 + +[VRFv2Plus] +[VRFv2Plus.General] +max_gas_price_gwei = 10 +link_native_feed_response = 1000000000000000000 +minimum_confirmations = 3 +subscription_billing_type = "LINK_AND_NATIVE" +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 +staleness_seconds = 86400 +gas_after_payment_calculation = 33825 +fulfilment_flat_fee_link_ppm_tier_1 = 500 +fulfilment_flat_fee_link_ppm_tier_2 = 500 +fulfilment_flat_fee_link_ppm_tier_3 = 500 +fulfilment_flat_fee_link_ppm_tier_4 = 500 +fulfilment_flat_fee_link_ppm_tier_5 = 500 +reqs_for_tier_2 = 0 +reqs_for_tier_3 = 0 +reqs_for_tier_4 = 0 +reqs_for_tier_5 = 0 +number_of_sub_to_create = 1 +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 +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 + +# load test specific config +[Load.VRFv2Plus] +[Load.VRFv2Plus.Common] +cancel_subs_after_test_run = true + +[Load.VRFv2Plus.General] +minimum_confirmations = 3 +randomness_request_count_per_request = 3 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 2 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 + +[Load.VRFv2Plus.Performance] +test_duration = "2m" +# approx 60 RPM - 1 tx request with 3 rand requests in each tx every 3 seconds +rate_limit_unit_duration = "3s" +rps = 1 + +[Load.VRFv2Plus.NewEnv] +sub_funds_link = 1 +sub_funds_native = 1 +node_funds = 10 +node_sending_key_funding = 1000 + +[Load.VRFv2Plus.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +link_address = "" +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# soak test specific config +[Soak.VRFv2Plus] +[Soak.VRFv2Plus.Common] +cancel_subs_after_test_run = true + +[Soak.VRFv2Plus.General] +minimum_confirmations = 3 +randomness_request_count_per_request = 1 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 + +[Soak.VRFv2Plus.Performance] +test_duration = "2m" +# 10 RPM - 1 tx request with 1 rand request in each tx every 6 seconds +rate_limit_unit_duration = "6s" +rps = 1 +use_existing_env = false + +[Soak.VRFv2Plus.NewEnv] +sub_funds_link = 1 +sub_funds_native = 1 +node_funds = 10 +node_sending_key_funding = 1000 + +[Soak.VRFv2Plus.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# spike test specific config +[Spike.VRFv2Plus] +[Spike.VRFv2Plus.Common] +cancel_subs_after_test_run = true + +[Spike.VRFv2Plus.General] +minimum_confirmations = 3 +randomness_request_count_per_request = 150 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 + +[Spike.VRFv2Plus.Performance] +test_duration = "2m" +# approx 150 RPM - 1 tx request with 150 rand requests in each tx every 60 seconds +rate_limit_unit_duration = "1m" +rps = 1 + +[Spike.VRFv2Plus.NewEnv] +sub_funds_link = 1 +sub_funds_native = 1 +node_funds = 10 +node_sending_key_funding = 1000 + +[Spike.VRFv2Plus.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] + +# stress test specific config +[Stress.VRFv2Plus] +[Stress.VRFv2Plus.Common] +cancel_subs_after_test_run = true + +[Stress.VRFv2Plus.General] +minimum_confirmations = 3 +randomness_request_count_per_request = 4 # amount of randomness requests to make per one TX request +randomness_request_count_per_request_deviation = 0 #NOTE - deviation should be less than randomness_request_count_per_request setting +number_of_sub_to_create = 1 + +[Stress.VRFv2Plus.Performance] +test_duration = "2m" +# approx 540 RPM - 3 tx requests per second with 4 rand requests in each tx +rate_limit_unit_duration = "1s" +rps = 3 + +[Stress.VRFv2Plus.NewEnv] +sub_funds_link = 1 +sub_funds_native = 1 +node_funds = 10 +node_sending_key_funding = 1000 + +[Stress.VRFv2Plus.ExistingEnv] +sub_id = 1 +create_fund_subs_and_add_consumers = true +sub_funds_link = 10 +node_sending_key_funding_min = 1 +node_sending_keys = [] \ No newline at end of file diff --git a/integration-tests/testreporters/keeper_benchmark.go b/integration-tests/testreporters/keeper_benchmark.go index 5db6cca3ec4..b878ff67a31 100644 --- a/integration-tests/testreporters/keeper_benchmark.go +++ b/integration-tests/testreporters/keeper_benchmark.go @@ -18,10 +18,6 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/client" ) -var ( - DashboardUrl = os.Getenv("GRAFANA_DASHBOARD_URL") -) - // KeeperBenchmarkTestReporter enables reporting on the keeper benchmark test type KeeperBenchmarkTestReporter struct { Reports []KeeperBenchmarkTestReport `json:"reports"` @@ -249,7 +245,7 @@ func (k *KeeperBenchmarkTestReporter) WriteReport(folderLocation string) error { } // SendSlackNotification sends a slack notification on the results of the test -func (k *KeeperBenchmarkTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { +func (k *KeeperBenchmarkTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client, grafanaUrlProvider testreporters.GrafanaURLProvider) error { if slackClient == nil { slackClient = slack.New(testreporters.SlackAPIKey) } @@ -267,7 +263,17 @@ func (k *KeeperBenchmarkTestReporter) SendSlackNotification(t *testing.T, slackC return err } - formattedDashboardUrl := fmt.Sprintf("%s&from=%d&to=%d&var-namespace=%s&var-cl_node=chainlink-0-0", DashboardUrl, k.Summary.StartTime, k.Summary.EndTime, k.namespace) + grafanaUrl, err := grafanaUrlProvider.GetGrafanaBaseURL() + if err != nil { + return err + } + + dashboardUrl, err := grafanaUrlProvider.GetGrafanaDashboardURL() + if err != nil { + return err + } + + formattedDashboardUrl := fmt.Sprintf("%s%s?from=%d&to=%d&var-namespace=%s&var-cl_node=chainlink-0-0", grafanaUrl, dashboardUrl, k.Summary.StartTime, k.Summary.EndTime, k.namespace) log.Info().Str("Dashboard", formattedDashboardUrl).Msg("Dashboard URL") if err := testreporters.UploadSlackFile(slackClient, slack.FileUploadParameters{ diff --git a/integration-tests/testreporters/ocr.go b/integration-tests/testreporters/ocr.go index abbb261fa74..9a9c4d0d4a0 100644 --- a/integration-tests/testreporters/ocr.go +++ b/integration-tests/testreporters/ocr.go @@ -21,6 +21,7 @@ import ( type OCRSoakTestReporter struct { StartTime time.Time AnomaliesDetected bool + OCRVersion string anomalies [][]string timeLine [][]string @@ -159,7 +160,7 @@ func (o *OCRSoakTestReporter) SetNamespace(namespace string) { // WriteReport writes OCR Soak test report to a CSV file and final report func (o *OCRSoakTestReporter) WriteReport(folderLocation string) error { - log.Debug().Msg("Writing OCR Soak Test Report") + log.Debug().Msgf("Writing OCRv%s Soak Test Report", o.OCRVersion) reportLocation := filepath.Join(folderLocation, "./ocr_soak_report.csv") o.csvLocation = reportLocation ocrReportFile, err := os.Create(reportLocation) @@ -170,7 +171,7 @@ func (o *OCRSoakTestReporter) WriteReport(folderLocation string) error { ocrReportWriter := csv.NewWriter(ocrReportFile) - err = ocrReportWriter.Write([]string{"OCR Soak Test Report"}) + err = ocrReportWriter.Write([]string{fmt.Sprintf("OCRv%s Soak Test Report", o.OCRVersion)}) if err != nil { return err } @@ -234,13 +235,13 @@ func (o *OCRSoakTestReporter) WriteReport(folderLocation string) error { } // SendNotification sends a slack message to a slack webhook and uploads test artifacts -func (o *OCRSoakTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { +func (o *OCRSoakTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client, _ testreporters.GrafanaURLProvider) error { if slackClient == nil { slackClient = slack.New(testreporters.SlackAPIKey) } testFailed := t.Failed() - headerText := ":white_check_mark: OCR Soak Test PASSED :white_check_mark:" + headerText := fmt.Sprintf(":white_check_mark: OCRv%s Soak Test PASSED :white_check_mark:", o.OCRVersion) if testFailed { headerText = ":x: OCR Soak Test FAILED :x:" } else if o.AnomaliesDetected { diff --git a/integration-tests/testreporters/profile.go b/integration-tests/testreporters/profile.go index ab9dec138e4..464cfd685e7 100644 --- a/integration-tests/testreporters/profile.go +++ b/integration-tests/testreporters/profile.go @@ -54,7 +54,7 @@ func (c *ChainlinkProfileTestReporter) WriteReport(folderLocation string) error } // SendNotification hasn't been implemented for this test -func (c *ChainlinkProfileTestReporter) SendSlackNotification(_ *testing.T, _ *slack.Client) error { +func (c *ChainlinkProfileTestReporter) SendSlackNotification(_ *testing.T, _ *slack.Client, _ testreporters.GrafanaURLProvider) error { log.Warn().Msg("No Slack notification integration for Chainlink profile tests") return nil } diff --git a/integration-tests/testreporters/vrfv2.go b/integration-tests/testreporters/vrfv2.go index 2a72e4d91d0..4f4c7dc8fd1 100644 --- a/integration-tests/testreporters/vrfv2.go +++ b/integration-tests/testreporters/vrfv2.go @@ -3,15 +3,14 @@ package testreporters import ( "fmt" "math/big" - "os" + "strings" "testing" "time" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2_actions/vrfv2_config" - "github.com/slack-go/slack" "github.com/smartcontractkit/chainlink-testing-framework/testreporters" + "github.com/smartcontractkit/chainlink/integration-tests/types" ) type VRFV2TestReporter struct { @@ -21,7 +20,7 @@ type VRFV2TestReporter struct { AverageFulfillmentInMillions *big.Int SlowestFulfillment *big.Int FastestFulfillment *big.Int - Vrfv2Config *vrfv2_config.VRFV2Config + VRFv2TestConfig types.VRFv2TestConfig } func (o *VRFV2TestReporter) SetReportData( @@ -31,7 +30,7 @@ func (o *VRFV2TestReporter) SetReportData( AverageFulfillmentInMillions *big.Int, SlowestFulfillment *big.Int, FastestFulfillment *big.Int, - vrfv2Config vrfv2_config.VRFV2Config, + vrfv2TestConfig types.VRFv2TestConfig, ) { o.TestType = testType o.RequestCount = RequestCount @@ -39,7 +38,7 @@ func (o *VRFV2TestReporter) SetReportData( o.AverageFulfillmentInMillions = AverageFulfillmentInMillions o.SlowestFulfillment = SlowestFulfillment o.FastestFulfillment = FastestFulfillment - o.Vrfv2Config = &vrfv2Config + o.VRFv2TestConfig = vrfv2TestConfig } // SendSlackNotification sends a slack message to a slack webhook @@ -54,7 +53,14 @@ func (o *VRFV2TestReporter) SendSlackNotification(t *testing.T, slackClient *sla headerText = fmt.Sprintf(":x: VRF V2 %s Test FAILED :x:", o.TestType) } - messageBlocks := testreporters.SlackNotifyBlocks(headerText, os.Getenv("SELECTED_NETWORKS"), []string{ + perfCfg := o.VRFv2TestConfig.GetVRFv2Config().Performance + var sb strings.Builder + for _, n := range o.VRFv2TestConfig.GetNetworkConfig().SelectedNetworks { + sb.WriteString(n) + sb.WriteString(", ") + } + + messageBlocks := testreporters.SlackNotifyBlocks(headerText, sb.String(), []string{ fmt.Sprintf( "Summary\n"+ "Perf Test Type: %s\n"+ @@ -70,17 +76,17 @@ func (o *VRFV2TestReporter) SendSlackNotification(t *testing.T, slackClient *sla "RandomnessRequestCountPerRequest: %d\n"+ "RandomnessRequestCountPerRequestDeviation: %d\n", o.TestType, - o.Vrfv2Config.TestDuration.Truncate(time.Second).String(), - o.Vrfv2Config.UseExistingEnv, + perfCfg.TestDuration.Duration.Truncate(time.Second).String(), + *perfCfg.UseExistingEnv, o.RequestCount.String(), o.FulfilmentCount.String(), o.AverageFulfillmentInMillions.String(), o.SlowestFulfillment.String(), o.FastestFulfillment.String(), - o.Vrfv2Config.RPS, - o.Vrfv2Config.RateLimitUnitDuration.String(), - o.Vrfv2Config.RandomnessRequestCountPerRequest, - o.Vrfv2Config.RandomnessRequestCountPerRequestDeviation, + *perfCfg.RPS, + perfCfg.RateLimitUnitDuration.String(), + *o.VRFv2TestConfig.GetVRFv2Config().General.RandomnessRequestCountPerRequest, + *o.VRFv2TestConfig.GetVRFv2Config().General.RandomnessRequestCountPerRequestDeviation, ), }) diff --git a/integration-tests/testreporters/vrfv2plus.go b/integration-tests/testreporters/vrfv2plus.go index 21e4e52695a..8d384b07868 100644 --- a/integration-tests/testreporters/vrfv2plus.go +++ b/integration-tests/testreporters/vrfv2plus.go @@ -3,11 +3,11 @@ package testreporters import ( "fmt" "math/big" - "os" + "strings" "testing" "time" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrfv2plus/vrfv2plus_config" + "github.com/smartcontractkit/chainlink/integration-tests/types" "github.com/slack-go/slack" @@ -21,7 +21,7 @@ type VRFV2PlusTestReporter struct { AverageFulfillmentInMillions *big.Int SlowestFulfillment *big.Int FastestFulfillment *big.Int - Vrfv2PlusConfig *vrfv2plus_config.VRFV2PlusConfig + VRFv2PlusTestConfig types.VRFv2PlusTestConfig } func (o *VRFV2PlusTestReporter) SetReportData( @@ -31,7 +31,7 @@ func (o *VRFV2PlusTestReporter) SetReportData( AverageFulfillmentInMillions *big.Int, SlowestFulfillment *big.Int, FastestFulfillment *big.Int, - vrfv2PlusConfig vrfv2plus_config.VRFV2PlusConfig, + vtfv2PlusTestConfig types.VRFv2PlusTestConfig, ) { o.TestType = testType o.RequestCount = RequestCount @@ -39,11 +39,11 @@ func (o *VRFV2PlusTestReporter) SetReportData( o.AverageFulfillmentInMillions = AverageFulfillmentInMillions o.SlowestFulfillment = SlowestFulfillment o.FastestFulfillment = FastestFulfillment - o.Vrfv2PlusConfig = &vrfv2PlusConfig + o.VRFv2PlusTestConfig = vtfv2PlusTestConfig } // SendSlackNotification sends a slack message to a slack webhook -func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client) error { +func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient *slack.Client, vtfv2PlusTestConfig types.VRFv2PlusTestConfig) error { if slackClient == nil { slackClient = slack.New(testreporters.SlackAPIKey) } @@ -54,7 +54,8 @@ func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient headerText = fmt.Sprintf(":x: VRF V2 Plus %s Test FAILED :x:", o.TestType) } - messageBlocks := testreporters.SlackNotifyBlocks(headerText, os.Getenv("SELECTED_NETWORKS"), []string{ + vrfv2lusConfig := o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().Performance + messageBlocks := testreporters.SlackNotifyBlocks(headerText, strings.Join(vtfv2PlusTestConfig.GetNetworkConfig().SelectedNetworks, ","), []string{ fmt.Sprintf( "Summary\n"+ "Perf Test Type: %s\n"+ @@ -70,17 +71,17 @@ func (o *VRFV2PlusTestReporter) SendSlackNotification(t *testing.T, slackClient "RandomnessRequestCountPerRequest: %d\n"+ "RandomnessRequestCountPerRequestDeviation: %d\n", o.TestType, - o.Vrfv2PlusConfig.TestDuration.Truncate(time.Second).String(), - o.Vrfv2PlusConfig.UseExistingEnv, + vrfv2lusConfig.TestDuration.Duration.Truncate(time.Second).String(), + *vrfv2lusConfig.UseExistingEnv, o.RequestCount.String(), o.FulfilmentCount.String(), o.AverageFulfillmentInMillions.String(), o.SlowestFulfillment.String(), o.FastestFulfillment.String(), - o.Vrfv2PlusConfig.RPS, - o.Vrfv2PlusConfig.RateLimitUnitDuration.String(), - o.Vrfv2PlusConfig.RandomnessRequestCountPerRequest, - o.Vrfv2PlusConfig.RandomnessRequestCountPerRequestDeviation, + *vrfv2lusConfig.RPS, + vrfv2lusConfig.RateLimitUnitDuration.String(), + *o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequest, + *o.VRFv2PlusTestConfig.GetVRFv2PlusConfig().General.RandomnessRequestCountPerRequestDeviation, ), }) diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index 575ed3e7de5..1330ea291b8 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -38,6 +38,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + tt "github.com/smartcontractkit/chainlink/integration-tests/types" ) // KeeperBenchmarkTest builds a test to check that chainlink nodes are able to upkeep a specified amount of Upkeep @@ -59,6 +60,7 @@ type KeeperBenchmarkTest struct { namespace string chainlinkNodes []*client.ChainlinkK8sClient chainClient blockchain.EVMClient + testConfig tt.KeeperBenchmarkTestConfig contractDeployer contracts.ContractDeployer linkToken contracts.LinkToken @@ -113,13 +115,14 @@ func NewKeeperBenchmarkTest(t *testing.T, inputs KeeperBenchmarkTestInputs) *Kee } // Setup prepares contracts for the test -func (k *KeeperBenchmarkTest) Setup(env *environment.Environment) { +func (k *KeeperBenchmarkTest) Setup(env *environment.Environment, config tt.KeeperBenchmarkTestConfig) { startTime := time.Now() k.TestReporter.Summary.StartTime = startTime.UnixMilli() k.ensureInputValues() k.env = env k.namespace = k.env.Cfg.Namespace inputs := k.Inputs + k.testConfig = config k.keeperRegistries = make([]contracts.KeeperRegistry, len(inputs.RegistryVersions)) k.keeperRegistrars = make([]contracts.KeeperRegistrar, len(inputs.RegistryVersions)) @@ -202,7 +205,7 @@ func (k *KeeperBenchmarkTest) Setup(env *environment.Environment) { } k.log.Info().Str("Setup Time", time.Since(startTime).String()).Msg("Finished Keeper Benchmark Test Setup") - err = k.SendSlackNotification(nil) + err = k.SendSlackNotification(nil, config) if err != nil { k.log.Warn().Msg("Sending test start slack notification failed") } @@ -405,9 +408,10 @@ func (k *KeeperBenchmarkTest) TearDownVals(t *testing.T) ( string, []*client.ChainlinkK8sClient, reportModel.TestReporter, + reportModel.GrafanaURLProvider, blockchain.EVMClient, ) { - return t, k.namespace, k.chainlinkNodes, &k.TestReporter, k.chainClient + return t, k.namespace, k.chainlinkNodes, &k.TestReporter, k.testConfig, k.chainClient } // ********************* @@ -571,13 +575,23 @@ func (k *KeeperBenchmarkTest) ensureInputValues() { } } -func (k *KeeperBenchmarkTest) SendSlackNotification(slackClient *slack.Client) error { +func (k *KeeperBenchmarkTest) SendSlackNotification(slackClient *slack.Client, config tt.KeeperBenchmarkTestConfig) error { if slackClient == nil { slackClient = slack.New(reportModel.SlackAPIKey) } + grafanaUrl, err := config.GetGrafanaBaseURL() + if err != nil { + return err + } + + dashboardUrl, err := config.GetGrafanaDashboardURL() + if err != nil { + return err + } + headerText := ":white_check_mark: Automation Benchmark Test STARTED :white_check_mark:" - formattedDashboardUrl := fmt.Sprintf("%s&from=%d&to=%s&var-namespace=%s&var-cl_node=chainlink-0-0", testreporters.DashboardUrl, k.TestReporter.Summary.StartTime, "now", k.env.Cfg.Namespace) + formattedDashboardUrl := fmt.Sprintf("%s%s?from=%d&to=%s&var-namespace=%s&var-cl_node=chainlink-0-0", grafanaUrl, dashboardUrl, k.TestReporter.Summary.StartTime, "now", k.env.Cfg.Namespace) log.Info().Str("Dashboard", formattedDashboardUrl).Msg("Dashboard URL") notificationBlocks := []slack.Block{} diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index a35d915ea92..a2e2fe42bae 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -10,7 +10,6 @@ import ( "os" "os/signal" "sort" - "strconv" "strings" "syscall" "testing" @@ -19,15 +18,16 @@ import ( geth "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/kelseyhightower/envconfig" "github.com/pelletier/go-toml/v2" "github.com/rs/zerolog" "github.com/stretchr/testify/require" "github.com/smartcontractkit/libocr/gethwrappers/offchainaggregator" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctfClient "github.com/smartcontractkit/chainlink-testing-framework/client" + ctf_config "github.com/smartcontractkit/chainlink-testing-framework/config" "github.com/smartcontractkit/chainlink-testing-framework/k8s/environment" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/chainlink" "github.com/smartcontractkit/chainlink-testing-framework/k8s/pkg/helm/ethereum" @@ -43,6 +43,9 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/config" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/testreporters" + tt "github.com/smartcontractkit/chainlink/integration-tests/types" + + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) const ( @@ -52,7 +55,7 @@ const ( // OCRSoakTest defines a typical OCR soak test type OCRSoakTest struct { - Inputs *OCRSoakTestInputs + Config *tc.TestConfig TestReporter testreporters.OCRSoakTestReporter OperatorForwarderFlow bool @@ -72,63 +75,37 @@ type OCRSoakTest struct { ocrRoundStates []*testreporters.OCRRoundState testIssues []*testreporters.TestIssue - ocrInstances []contracts.OffchainAggregator - ocrInstanceMap map[string]contracts.OffchainAggregator // address : instance -} - -// OCRSoakTestInputs define required inputs to run an OCR soak test -type OCRSoakTestInputs struct { - TestDuration time.Duration `envconfig:"TEST_DURATION" default:"15m"` // How long to run the test for - NumberOfContracts int `envconfig:"NUMBER_CONTRACTS" default:"2"` // Number of OCR contracts to launch - ChainlinkNodeFunding float64 `envconfig:"CHAINLINK_NODE_FUNDING" default:".1"` // Amount of native currency to fund each chainlink node with - bigChainlinkNodeFunding *big.Float // Convenience conversions for funding - TimeBetweenRounds time.Duration `envconfig:"TIME_BETWEEN_ROUNDS" default:"1m"` // How long to wait before starting a new round; controls frequency of rounds -} - -func (i OCRSoakTestInputs) setForRemoteRunner() { - os.Setenv("TEST_OCR_TEST_DURATION", i.TestDuration.String()) - os.Setenv("TEST_OCR_NUMBER_CONTRACTS", fmt.Sprint(i.NumberOfContracts)) - os.Setenv("TEST_OCR_CHAINLINK_NODE_FUNDING", strconv.FormatFloat(i.ChainlinkNodeFunding, 'f', -1, 64)) - os.Setenv("TEST_OCR_TIME_BETWEEN_ROUNDS", i.TimeBetweenRounds.String()) + ocrV1Instances []contracts.OffchainAggregator + ocrV1InstanceMap map[string]contracts.OffchainAggregator // address : instance - selectedNetworks := strings.Split(os.Getenv("SELECTED_NETWORKS"), ",") - for _, networkPrefix := range selectedNetworks { - urlEnv := fmt.Sprintf("%s_URLS", networkPrefix) - httpEnv := fmt.Sprintf("%s_HTTP_URLS", networkPrefix) - os.Setenv(fmt.Sprintf("TEST_%s", urlEnv), os.Getenv(urlEnv)) - os.Setenv(fmt.Sprintf("TEST_%s", httpEnv), os.Getenv(httpEnv)) - } + ocrV2Instances []contracts.OffchainAggregatorV2 + ocrV2InstanceMap map[string]contracts.OffchainAggregatorV2 // address : instance } // NewOCRSoakTest creates a new OCR soak test to setup and run -func NewOCRSoakTest(t *testing.T, forwarderFlow bool) (*OCRSoakTest, error) { - var testInputs OCRSoakTestInputs - err := envconfig.Process("OCR", &testInputs) - if err != nil { - return nil, err - } - testInputs.setForRemoteRunner() - +func NewOCRSoakTest(t *testing.T, config *tc.TestConfig, forwarderFlow bool) (*OCRSoakTest, error) { test := &OCRSoakTest{ - Inputs: &testInputs, + Config: config, OperatorForwarderFlow: forwarderFlow, TestReporter: testreporters.OCRSoakTestReporter{ - StartTime: time.Now(), + OCRVersion: *config.OCR.Soak.OCRVersion, + StartTime: time.Now(), }, - t: t, - startTime: time.Now(), - timeLeft: testInputs.TestDuration, - log: logging.GetTestLogger(t), - ocrRoundStates: make([]*testreporters.OCRRoundState, 0), - ocrInstanceMap: make(map[string]contracts.OffchainAggregator), + t: t, + startTime: time.Now(), + timeLeft: config.OCR.Common.TestDuration.Duration, + log: logging.GetTestLogger(t), + ocrRoundStates: make([]*testreporters.OCRRoundState, 0), + ocrV1InstanceMap: make(map[string]contracts.OffchainAggregator), + ocrV2InstanceMap: make(map[string]contracts.OffchainAggregatorV2), } return test, test.ensureInputValues() } // DeployEnvironment deploys the test environment, starting all Chainlink nodes and other components for the test -func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { - network := networks.MustGetSelectedNetworksFromEnv()[0] // Environment currently being used to soak test on - nsPre := "soak-ocr-" +func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string, ocrTestConfig tt.OcrTestConfig) { + network := networks.MustGetSelectedNetworkConfig(ocrTestConfig.GetNetworkConfig())[0] // Environment currently being used to soak test on + nsPre := fmt.Sprintf("soak-ocr-v%s-", *ocrTestConfig.GetOCRConfig().Soak.OCRVersion) if o.OperatorForwarderFlow { nsPre = fmt.Sprintf("%sforwarder-", nsPre) } @@ -140,13 +117,25 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { PreventPodEviction: true, } - cd := chainlink.New(0, map[string]any{ + var conf string + if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "1" { + conf = config.BaseOCR1Config + } else if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "2" { + conf = config.BaseOCR2Config + } + + var overrideFn = func(_ interface{}, target interface{}) { + ctf_config.MustConfigOverrideChainlinkVersion(ocrTestConfig.GetChainlinkImageConfig(), target) + ctf_config.MightConfigOverridePyroscopeKey(ocrTestConfig.GetPyroscopeConfig(), target) + } + + cd := chainlink.NewWithOverride(0, map[string]any{ "replicas": 6, - "toml": networks.AddNetworkDetailedConfig(config.BaseOCR1Config, customChainlinkNetworkTOML, network), + "toml": networks.AddNetworkDetailedConfig(conf, ocrTestConfig.GetPyroscopeConfig(), customChainlinkNetworkTOML, network), "db": map[string]any{ "stateful": true, // stateful DB by default for soak tests }, - }) + }, ocrTestConfig.GetChainlinkImageConfig(), overrideFn) testEnvironment := environment.New(baseEnvironmentConfig). AddHelm(mockservercfg.New(nil)). @@ -164,9 +153,9 @@ func (o *OCRSoakTest) DeployEnvironment(customChainlinkNetworkTOML string) { } // LoadEnvironment loads an existing test environment using the provided URLs -func (o *OCRSoakTest) LoadEnvironment(chainlinkURLs []string, mockServerURL string) { +func (o *OCRSoakTest) LoadEnvironment(chainlinkURLs []string, mockServerURL string, ocrTestConfig tt.OcrTestConfig) { var ( - network = networks.MustGetSelectedNetworksFromEnv()[0] + network = networks.MustGetSelectedNetworkConfig(ocrTestConfig.GetNetworkConfig())[0] err error ) o.chainClient, err = blockchain.ConnectEVMClient(network, o.log) @@ -183,10 +172,10 @@ func (o *OCRSoakTest) Environment() *environment.Environment { return o.testEnvironment } -func (o *OCRSoakTest) Setup() { +func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { var ( err error - network = networks.MustGetSelectedNetworksFromEnv()[0] + network = networks.MustGetSelectedNetworkConfig(ocrTestConfig.GetNetworkConfig())[0] ) // Environment currently being used to soak test on @@ -207,7 +196,8 @@ func (o *OCRSoakTest) Setup() { require.NoError(o.t, err, "Deploying Link Token Contract shouldn't fail") // Fund Chainlink nodes, excluding the bootstrap node - err = actions.FundChainlinkNodes(o.workerNodes, o.chainClient, o.Inputs.bigChainlinkNodeFunding) + o.log.Info().Float64("ETH amount per node", *o.Config.Common.ChainlinkNodeFunding).Msg("Funding Chainlink nodes") + err = actions.FundChainlinkNodes(o.workerNodes, o.chainClient, big.NewFloat(*o.Config.Common.ChainlinkNodeFunding)) require.NoError(o.t, err, "Error funding Chainlink nodes") if o.OperatorForwarderFlow { @@ -228,36 +218,67 @@ func (o *OCRSoakTest) Setup() { err = o.chainClient.WaitForEvents() } - o.ocrInstances = actions.DeployOCRContractsForwarderFlow( + o.ocrV1Instances = actions.DeployOCRContractsForwarderFlow( o.t, - o.Inputs.NumberOfContracts, + *o.Config.OCR.Soak.NumberOfContracts, linkTokenContract, contractDeployer, o.workerNodes, authorizedForwarders, o.chainClient, ) - } else { - o.ocrInstances, err = actions.DeployOCRContracts( - o.Inputs.NumberOfContracts, + } else if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "1" { + o.ocrV1Instances, err = actions.DeployOCRContracts( + *o.Config.OCR.Soak.NumberOfContracts, linkTokenContract, contractDeployer, o.workerNodes, o.chainClient, ) require.NoError(o.t, err) + } else if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "2" { + var transmitters []string + for _, node := range o.workerNodes { + nodeAddress, err := node.PrimaryEthAddress() + require.NoError(o.t, err, "Error getting node's primary ETH address") + transmitters = append(transmitters, nodeAddress) + } + ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() + o.ocrV2Instances, err = actions.DeployOCRv2Contracts( + *ocrTestConfig.GetOCRConfig().Soak.NumberOfContracts, + linkTokenContract, + contractDeployer, + transmitters, + o.chainClient, + ocrOffchainOptions, + ) + require.NoError(o.t, err, "Error deploying OCRv2 contracts") + contractConfig, err := actions.BuildMedianOCR2Config(o.workerNodes, ocrOffchainOptions) + require.NoError(o.t, err, "Error building median config") + err = actions.ConfigureOCRv2AggregatorContracts(o.chainClient, contractConfig, o.ocrV2Instances) + require.NoError(o.t, err, "Error configuring OCRv2 aggregator contracts") } err = o.chainClient.WaitForEvents() require.NoError(o.t, err, "Error waiting for OCR contracts to be deployed") - for _, ocrInstance := range o.ocrInstances { - o.ocrInstanceMap[ocrInstance.Address()] = ocrInstance + if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "1" { + for _, ocrInstance := range o.ocrV1Instances { + o.ocrV1InstanceMap[ocrInstance.Address()] = ocrInstance + } + } else if *ocrTestConfig.GetOCRConfig().Soak.OCRVersion == "2" { + for _, ocrInstance := range o.ocrV2Instances { + o.ocrV2InstanceMap[ocrInstance.Address()] = ocrInstance + } } + o.log.Info().Msg("OCR Soak Test Setup Complete") } // Run starts the OCR soak test func (o *OCRSoakTest) Run() { + config, err := tc.GetConfig("soak", tc.OCR) + require.NoError(o.t, err, "Error getting config") + ctx, cancel := context.WithTimeout(testcontext.Get(o.t), time.Second*5) latestBlockNum, err := o.chainClient.LatestBlockNumber(ctx) cancel() @@ -266,18 +287,22 @@ func (o *OCRSoakTest) Run() { startingValue := 5 if o.OperatorForwarderFlow { - actions.CreateOCRJobsWithForwarder(o.t, o.ocrInstances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) - } else { - err := actions.CreateOCRJobs(o.ocrInstances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) + actions.CreateOCRJobsWithForwarder(o.t, o.ocrV1Instances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) + } else if *config.OCR.Soak.OCRVersion == "1" { + err := actions.CreateOCRJobs(o.ocrV1Instances, o.bootstrapNode, o.workerNodes, startingValue, o.mockServer, o.chainClient.GetChainID().String()) + require.NoError(o.t, err, "Error creating OCR jobs") + } else if *config.OCR.Soak.OCRVersion == "2" { + err := actions.CreateOCRv2Jobs(o.ocrV2Instances, o.bootstrapNode, o.workerNodes, o.mockServer, startingValue, o.chainClient.GetChainID().Uint64(), o.OperatorForwarderFlow) require.NoError(o.t, err, "Error creating OCR jobs") } o.log.Info(). - Str("Test Duration", o.Inputs.TestDuration.Truncate(time.Second).String()). - Int("Number of OCR Contracts", len(o.ocrInstances)). + Str("Test Duration", o.Config.OCR.Common.TestDuration.Duration.Truncate(time.Second).String()). + Int("Number of OCR Contracts", *config.OCR.Soak.NumberOfContracts). + Str("OCR Version", *config.OCR.Soak.OCRVersion). Msg("Starting OCR Soak Test") - o.testLoop(o.Inputs.TestDuration, startingValue) + o.testLoop(o.Config.OCR.Common.TestDuration.Duration, startingValue) o.complete() } @@ -287,9 +312,10 @@ func (o *OCRSoakTest) TearDownVals(t *testing.T) ( string, []*client.ChainlinkK8sClient, reportModel.TestReporter, + reportModel.GrafanaURLProvider, blockchain.EVMClient, ) { - return t, o.namespace, append(o.workerNodes, o.bootstrapNode), &o.TestReporter, o.chainClient + return t, o.namespace, append(o.workerNodes, o.bootstrapNode), &o.TestReporter, o.Config, o.chainClient } // ********************* @@ -306,6 +332,7 @@ type OCRSoakTestState struct { TimeRunning time.Duration `toml:"timeRunning"` TestDuration time.Duration `toml:"testDuration"` OCRContractAddresses []string `toml:"ocrContractAddresses"` + OCRVersion string `toml:"ocrVersion"` BootStrapNodeURL string `toml:"bootstrapNodeURL"` WorkerNodeURLs []string `toml:"workerNodeURLs"` @@ -315,10 +342,7 @@ type OCRSoakTestState struct { // SaveState saves the current state of the test to a TOML file func (o *OCRSoakTest) SaveState() error { - ocrAddresses := make([]string, len(o.ocrInstances)) - for i, ocrInstance := range o.ocrInstances { - ocrAddresses[i] = ocrInstance.Address() - } + ocrAddresses := o.getContractAddressesString() workerNodeURLs := make([]string, len(o.workerNodes)) for i, workerNode := range o.workerNodes { workerNodeURLs[i] = workerNode.URL() @@ -331,8 +355,9 @@ func (o *OCRSoakTest) SaveState() error { StartingBlockNum: o.startingBlockNum, StartTime: o.startTime, TimeRunning: time.Since(o.startTime), - TestDuration: o.Inputs.TestDuration, + TestDuration: o.Config.OCR.Common.TestDuration.Duration, OCRContractAddresses: ocrAddresses, + OCRVersion: *o.Config.OCR.Soak.OCRVersion, ChainURL: o.chainClient.GetNetworkConfig().URL, MockServerURL: "http://mockserver:1080", // TODO: Make this dynamic @@ -378,16 +403,19 @@ func (o *OCRSoakTest) LoadState() error { o.namespace = testState.Namespace o.TestReporter = testreporters.OCRSoakTestReporter{ - StartTime: testState.StartTime, + OCRVersion: testState.OCRVersion, + StartTime: testState.StartTime, } + duration := blockchain.StrDuration{Duration: testState.TestDuration} o.ocrRoundStates = testState.OCRRoundStates o.testIssues = testState.TestIssues - o.Inputs.TestDuration = testState.TestDuration + o.Config.OCR.Common.TestDuration = &duration o.timeLeft = testState.TestDuration - testState.TimeRunning o.startTime = testState.StartTime o.startingBlockNum = testState.StartingBlockNum + o.Config.OCR.Soak.OCRVersion = &testState.OCRVersion - network := networks.MustGetSelectedNetworksFromEnv()[0] + network := networks.MustGetSelectedNetworkConfig(o.Config.Network)[0] o.chainClient, err = blockchain.ConnectEVMClient(network, o.log) if err != nil { return err @@ -405,15 +433,28 @@ func (o *OCRSoakTest) LoadState() error { return err } - o.ocrInstances = make([]contracts.OffchainAggregator, len(testState.OCRContractAddresses)) - for i, addr := range testState.OCRContractAddresses { - address := common.HexToAddress(addr) - instance, err := contractDeployer.LoadOffChainAggregator(&address) - if err != nil { - return err + if testState.OCRVersion == "1" { + o.ocrV1Instances = make([]contracts.OffchainAggregator, len(testState.OCRContractAddresses)) + for i, addr := range testState.OCRContractAddresses { + address := common.HexToAddress(addr) + instance, err := contractDeployer.LoadOffChainAggregator(&address) + if err != nil { + return err + } + o.ocrV1Instances[i] = instance + } + } else if testState.OCRVersion == "2" { + o.ocrV2Instances = make([]contracts.OffchainAggregatorV2, len(testState.OCRContractAddresses)) + for i, addr := range testState.OCRContractAddresses { + address := common.HexToAddress(addr) + instance, err := contractDeployer.LoadOffChainAggregatorV2(&address) + if err != nil { + return err + } + o.ocrV2Instances[i] = instance } - o.ocrInstances[i] = instance } + o.mockServer, err = ctfClient.ConnectMockServerURL(testState.MockServerURL) if err != nil { return err @@ -428,20 +469,34 @@ func (o *OCRSoakTest) Resume() { Message: "Test Resumed", }) o.log.Info(). - Str("Total Duration", o.Inputs.TestDuration.String()). + Str("Total Duration", o.Config.OCR.Common.TestDuration.String()). Str("Time Left", o.timeLeft.String()). Msg("Resuming OCR Soak Test") - ocrAddresses := make([]common.Address, len(o.ocrInstances)) - for i, ocrInstance := range o.ocrInstances { - ocrAddresses[i] = common.HexToAddress(ocrInstance.Address()) - } - contractABI, err := offchainaggregator.OffchainAggregatorMetaData.GetAbi() - require.NoError(o.t, err, "Error retrieving OCR contract ABI") - o.filterQuery = geth.FilterQuery{ - Addresses: ocrAddresses, - Topics: [][]common.Hash{{contractABI.Events["AnswerUpdated"].ID}}, - FromBlock: big.NewInt(0).SetUint64(o.startingBlockNum), + ocrAddresses := make([]common.Address, *o.Config.OCR.Soak.NumberOfContracts) + + if *o.Config.OCR.Soak.OCRVersion == "1" { + for i, ocrInstance := range o.ocrV1Instances { + ocrAddresses[i] = common.HexToAddress(ocrInstance.Address()) + } + contractABI, err := offchainaggregator.OffchainAggregatorMetaData.GetAbi() + require.NoError(o.t, err, "Error retrieving OCR contract ABI") + o.filterQuery = geth.FilterQuery{ + Addresses: ocrAddresses, + Topics: [][]common.Hash{{contractABI.Events["AnswerUpdated"].ID}}, + FromBlock: big.NewInt(0).SetUint64(o.startingBlockNum), + } + } else if *o.Config.OCR.Soak.OCRVersion == "2" { + for i, ocrInstance := range o.ocrV2Instances { + ocrAddresses[i] = common.HexToAddress(ocrInstance.Address()) + } + contractABI, err := ocr2aggregator.AggregatorInterfaceMetaData.GetAbi() + require.NoError(o.t, err, "Error retrieving OCR contract ABI") + o.filterQuery = geth.FilterQuery{ + Addresses: ocrAddresses, + Topics: [][]common.Hash{{contractABI.Events["AnswerUpdated"].ID}}, + FromBlock: big.NewInt(0).SetUint64(o.startingBlockNum), + } } startingValue := 5 @@ -449,7 +504,7 @@ func (o *OCRSoakTest) Resume() { o.log.Info().Msg("Test Complete, collecting on-chain events") - err = o.collectEvents() + err := o.collectEvents() o.log.Error().Err(err).Interface("Query", o.filterQuery).Msg("Error collecting on-chain events, expect malformed report") o.TestReporter.RecordEvents(o.ocrRoundStates, o.testIssues) } @@ -495,7 +550,7 @@ func (o *OCRSoakTest) testLoop(testDuration time.Duration, newValue int) { return case <-newRoundTrigger.C: err := o.triggerNewRound(newValue) - timerReset := o.Inputs.TimeBetweenRounds + timerReset := o.Config.OCR.Soak.TimeBetweenRounds.Duration if err != nil { timerReset = time.Second * 5 o.log.Error().Err(err). @@ -537,10 +592,7 @@ func (o *OCRSoakTest) complete() { // setFilterQuery to look for all events that happened func (o *OCRSoakTest) setFilterQuery() { - ocrAddresses := make([]common.Address, len(o.ocrInstances)) - for i, ocrInstance := range o.ocrInstances { - ocrAddresses[i] = common.HexToAddress(ocrInstance.Address()) - } + ocrAddresses := o.getContractAddresses() contractABI, err := offchainaggregator.OffchainAggregatorMetaData.GetAbi() require.NoError(o.t, err, "Error retrieving OCR contract ABI") o.filterQuery = geth.FilterQuery{ @@ -570,21 +622,39 @@ func (o *OCRSoakTest) observeOCREvents() error { for { select { case event := <-eventLogs: - answerUpdated, err := o.ocrInstances[0].ParseEventAnswerUpdated(event) - if err != nil { - o.log.Warn(). - Err(err). + if *o.Config.OCR.Soak.OCRVersion == "1" { + answerUpdated, err := o.ocrV1Instances[0].ParseEventAnswerUpdated(event) + if err != nil { + o.log.Warn(). + Err(err). + Str("Address", event.Address.Hex()). + Uint64("Block Number", event.BlockNumber). + Msg("Error parsing event as AnswerUpdated") + continue + } + o.log.Info(). Str("Address", event.Address.Hex()). Uint64("Block Number", event.BlockNumber). - Msg("Error parsing event as AnswerUpdated") - continue + Uint64("Round ID", answerUpdated.RoundId.Uint64()). + Int64("Answer", answerUpdated.Current.Int64()). + Msg("Answer Updated Event") + } else if *o.Config.OCR.Soak.OCRVersion == "2" { + answerUpdated, err := o.ocrV2Instances[0].ParseEventAnswerUpdated(event) + if err != nil { + o.log.Warn(). + Err(err). + Str("Address", event.Address.Hex()). + Uint64("Block Number", event.BlockNumber). + Msg("Error parsing event as AnswerUpdated") + continue + } + o.log.Info(). + Str("Address", event.Address.Hex()). + Uint64("Block Number", event.BlockNumber). + Uint64("Round ID", answerUpdated.RoundId.Uint64()). + Int64("Answer", answerUpdated.Current.Int64()). + Msg("Answer Updated Event") } - o.log.Info(). - Str("Address", event.Address.Hex()). - Uint64("Block Number", event.BlockNumber). - Uint64("Round ID", answerUpdated.RoundId.Uint64()). - Int64("Answer", answerUpdated.Current.Int64()). - Msg("Answer Updated Event") case err = <-eventSub.Err(): backoff := time.Second for err != nil { @@ -614,7 +684,12 @@ func (o *OCRSoakTest) triggerNewRound(newValue int) error { o.ocrRoundStates[len(o.ocrRoundStates)-1].EndTime = time.Now() } - err := actions.SetAllAdapterResponsesToTheSameValue(newValue, o.ocrInstances, o.workerNodes, o.mockServer) + var err error + if *o.Config.OCR.Soak.OCRVersion == "1" { + err = actions.SetAllAdapterResponsesToTheSameValue(newValue, o.ocrV1Instances, o.workerNodes, o.mockServer) + } else if *o.Config.OCR.Soak.OCRVersion == "2" { + err = actions.SetOCR2AllAdapterResponsesToTheSameValue(newValue, o.ocrV2Instances, o.workerNodes, o.mockServer) + } if err != nil { return err } @@ -624,9 +699,16 @@ func (o *OCRSoakTest) triggerNewRound(newValue int) error { Answer: int64(newValue), FoundEvents: make(map[string][]*testreporters.FoundEvent), } - for _, ocrInstance := range o.ocrInstances { - expectedState.FoundEvents[ocrInstance.Address()] = make([]*testreporters.FoundEvent, 0) + if *o.Config.OCR.Soak.OCRVersion == "1" { + for _, ocrInstance := range o.ocrV1Instances { + expectedState.FoundEvents[ocrInstance.Address()] = make([]*testreporters.FoundEvent, 0) + } + } else if *o.Config.OCR.Soak.OCRVersion == "2" { + for _, ocrInstance := range o.ocrV2Instances { + expectedState.FoundEvents[ocrInstance.Address()] = make([]*testreporters.FoundEvent, 0) + } } + o.ocrRoundStates = append(o.ocrRoundStates, expectedState) o.log.Info(). Int("Value", newValue). @@ -662,17 +744,31 @@ func (o *OCRSoakTest) collectEvents() error { sortedFoundEvents := make([]*testreporters.FoundEvent, 0) for _, event := range contractEvents { - answerUpdated, err := o.ocrInstances[0].ParseEventAnswerUpdated(event) - if err != nil { - return fmt.Errorf("error parsing EventAnswerUpdated for event: %v, %w", event, err) + if *o.Config.OCR.Soak.OCRVersion == "1" { + answerUpdated, err := o.ocrV1Instances[0].ParseEventAnswerUpdated(event) + if err != nil { + return fmt.Errorf("error parsing EventAnswerUpdated for event: %v, %w", event, err) + } + sortedFoundEvents = append(sortedFoundEvents, &testreporters.FoundEvent{ + StartTime: time.Unix(answerUpdated.UpdatedAt.Int64(), 0), + Address: event.Address.Hex(), + Answer: answerUpdated.Current.Int64(), + RoundID: answerUpdated.RoundId.Uint64(), + BlockNumber: event.BlockNumber, + }) + } else if *o.Config.OCR.Soak.OCRVersion == "2" { + answerUpdated, err := o.ocrV2Instances[0].ParseEventAnswerUpdated(event) + if err != nil { + return fmt.Errorf("error parsing EventAnswerUpdated for event: %v, %w", event, err) + } + sortedFoundEvents = append(sortedFoundEvents, &testreporters.FoundEvent{ + StartTime: time.Unix(answerUpdated.UpdatedAt.Int64(), 0), + Address: event.Address.Hex(), + Answer: answerUpdated.Current.Int64(), + RoundID: answerUpdated.RoundId.Uint64(), + BlockNumber: event.BlockNumber, + }) } - sortedFoundEvents = append(sortedFoundEvents, &testreporters.FoundEvent{ - StartTime: time.Unix(answerUpdated.UpdatedAt.Int64(), 0), - Address: event.Address.Hex(), - Answer: answerUpdated.Current.Int64(), - RoundID: answerUpdated.RoundId.Uint64(), - BlockNumber: event.BlockNumber, - }) } // Sort our events by time to make sure they are in order (don't trust RPCs) @@ -704,22 +800,61 @@ func (o *OCRSoakTest) collectEvents() error { // ensureValues ensures that all values needed to run the test are present func (o *OCRSoakTest) ensureInputValues() error { - inputs := o.Inputs - if inputs.NumberOfContracts <= 0 { - return fmt.Errorf("Number of OCR contracts must be greater than 0, found %d", inputs.NumberOfContracts) + ocrConfig := o.Config.OCR.Soak + if *ocrConfig.OCRVersion != "1" && *ocrConfig.OCRVersion != "2" { + return fmt.Errorf("OCR version must be 1 or 2, found %s", *ocrConfig.OCRVersion) + } + if ocrConfig.NumberOfContracts != nil && *ocrConfig.NumberOfContracts <= 0 { + return fmt.Errorf("Number of OCR contracts must be set and greater than 0, found %d", ocrConfig.NumberOfContracts) } - if inputs.ChainlinkNodeFunding <= 0 { - return fmt.Errorf("Chainlink node funding must be greater than 0, found %f", inputs.ChainlinkNodeFunding) + if o.Config.Common.ChainlinkNodeFunding != nil && *o.Config.Common.ChainlinkNodeFunding <= 0 { + return fmt.Errorf("Chainlink node funding must be greater than 0, found %f", *o.Config.Common.ChainlinkNodeFunding) } - if inputs.TestDuration <= time.Minute { - return fmt.Errorf("Test duration must be greater than 1 minute, found %s", inputs.TestDuration.String()) + if o.Config.OCR.Common.TestDuration != nil && o.Config.OCR.Common.TestDuration.Duration <= time.Minute { + return fmt.Errorf("Test duration must be greater than 1 minute, found %s", o.Config.OCR.Common.TestDuration) } - if inputs.TimeBetweenRounds >= time.Hour { - return fmt.Errorf("Time between rounds must be less than 1 hour, found %s", inputs.TimeBetweenRounds.String()) + if ocrConfig.TimeBetweenRounds != nil && ocrConfig.TimeBetweenRounds.Duration >= time.Hour { + return fmt.Errorf("Time between rounds must be less than 1 hour, found %s", ocrConfig.TimeBetweenRounds) } - if inputs.TimeBetweenRounds < time.Second*30 { - return fmt.Errorf("Time between rounds must be greater or equal to 30 seconds, found %s", inputs.TimeBetweenRounds.String()) + if ocrConfig.TimeBetweenRounds != nil && ocrConfig.TimeBetweenRounds.Duration < time.Second*30 { + return fmt.Errorf("Time between rounds must be greater or equal to 30 seconds, found %s", ocrConfig.TimeBetweenRounds) } - o.Inputs.bigChainlinkNodeFunding = big.NewFloat(inputs.ChainlinkNodeFunding) + return nil } + +// getContractAddressesString returns the addresses of all OCR contracts deployed as a string slice +func (o *OCRSoakTest) getContractAddressesString() []string { + contractAddresses := []string{} + if len(o.ocrV1Instances) != 0 { + for _, ocrInstance := range o.ocrV1Instances { + contractAddresses = append(contractAddresses, ocrInstance.Address()) + } + } else if len(o.ocrV2Instances) != 0 { + if len(o.ocrV2Instances) != 0 { + for _, ocrInstance := range o.ocrV2Instances { + contractAddresses = append(contractAddresses, ocrInstance.Address()) + } + } + } + + return contractAddresses +} + +// getContractAddresses returns the addresses of all OCR contracts deployed +func (o *OCRSoakTest) getContractAddresses() []common.Address { + contractAddresses := []common.Address{} + if len(o.ocrV1Instances) != 0 { + for _, ocrInstance := range o.ocrV1Instances { + contractAddresses = append(contractAddresses, common.HexToAddress(ocrInstance.Address())) + } + } else if len(o.ocrV2Instances) != 0 { + if len(o.ocrV2Instances) != 0 { + for _, ocrInstance := range o.ocrV2Instances { + contractAddresses = append(contractAddresses, common.HexToAddress(ocrInstance.Address())) + } + } + } + + return contractAddresses +} diff --git a/integration-tests/types/config/node/core.go b/integration-tests/types/config/node/core.go index ccbbce87a2e..3508f77555f 100644 --- a/integration-tests/types/config/node/core.go +++ b/integration-tests/types/config/node/core.go @@ -7,23 +7,22 @@ import ( "os" "time" - "go.uber.org/zap/zapcore" - "github.com/segmentio/ksuid" + "go.uber.org/zap/zapcore" commonassets "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-common/pkg/config" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" + ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" - "github.com/smartcontractkit/chainlink/v2/core/utils/config" - - it_utils "github.com/smartcontractkit/chainlink/integration-tests/utils" ) func NewBaseConfig() *chainlink.Config { @@ -46,7 +45,7 @@ func NewBaseConfig() *chainlink.Config { AllowOrigins: ptr.Ptr("*"), HTTPPort: ptr.Ptr[uint16](6688), SecureCookies: ptr.Ptr(false), - SessionTimeout: models.MustNewDuration(time.Hour * 999), + SessionTimeout: commonconfig.MustNewDuration(time.Hour * 999), TLS: toml.WebServerTLS{ HTTPSPort: ptr.Ptr[uint16](0), }, @@ -109,20 +108,6 @@ func WithOCR2() NodeConfigOpt { } } -// Deprecated: P2Pv1 is soon to be fully deprecated -// WithP2Pv1 enables P2Pv1 and disables P2Pv2 -func WithP2Pv1() NodeConfigOpt { - return func(c *chainlink.Config) { - c.P2P.V1 = toml.P2PV1{ - Enabled: ptr.Ptr(true), - ListenIP: it_utils.MustIP("0.0.0.0"), - ListenPort: ptr.Ptr[uint16](6690), - } - // disabled default - c.P2P.V2 = toml.P2PV2{Enabled: ptr.Ptr(false)} - } -} - func WithP2Pv2() NodeConfigOpt { return func(c *chainlink.Config) { c.P2P.V2 = toml.P2PV2{ @@ -176,7 +161,7 @@ func SetChainConfig( } cfg.EVM = evmcfg.EVMConfigs{ { - ChainID: utils.NewBig(big.NewInt(chain.ChainID)), + ChainID: ubig.New(big.NewInt(chain.ChainID)), Chain: chainConfig, Nodes: nodes, }, @@ -193,12 +178,12 @@ func WithPrivateEVMs(networks []blockchain.EVMNetwork) NodeConfigOpt { var evmConfigs []*evmcfg.EVMConfig for _, network := range networks { evmConfigs = append(evmConfigs, &evmcfg.EVMConfig{ - ChainID: utils.NewBig(big.NewInt(network.ChainID)), + ChainID: ubig.New(big.NewInt(network.ChainID)), Chain: evmcfg.Chain{ AutoCreateKey: ptr.Ptr(true), FinalityDepth: ptr.Ptr[uint32](50), MinContractPayment: commonassets.NewLinkFromJuels(0), - LogPollInterval: models.MustNewDuration(1 * time.Second), + LogPollInterval: commonconfig.MustNewDuration(1 * time.Second), HeadTracker: evmcfg.HeadTracker{ HistoryDepth: ptr.Ptr(uint32(100)), }, @@ -249,6 +234,6 @@ func WithVRFv2EVMEstimator(addresses []string, maxGasPriceGWei int64) NodeConfig func WithLogPollInterval(interval time.Duration) NodeConfigOpt { return func(c *chainlink.Config) { - c.EVM[0].Chain.LogPollInterval = models.MustNewDuration(interval) + c.EVM[0].Chain.LogPollInterval = commonconfig.MustNewDuration(interval) } } diff --git a/integration-tests/types/testconfigs.go b/integration-tests/types/testconfigs.go new file mode 100644 index 00000000000..0c704f0cd7b --- /dev/null +++ b/integration-tests/types/testconfigs.go @@ -0,0 +1,44 @@ +package types + +import ( + "github.com/smartcontractkit/chainlink-testing-framework/testreporters" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" +) + +type VRFv2TestConfig interface { + tc.CommonTestConfig + tc.GlobalTestConfig + tc.VRFv2TestConfig +} + +type VRFv2PlusTestConfig interface { + tc.CommonTestConfig + tc.GlobalTestConfig + tc.VRFv2PlusTestConfig +} + +type FunctionsTestConfig interface { + tc.CommonTestConfig + tc.GlobalTestConfig + tc.FunctionsTestConfig +} + +type AutomationTestConfig interface { + tc.GlobalTestConfig + tc.CommonTestConfig + tc.UpgradeableChainlinkTestConfig +} + +type KeeperBenchmarkTestConfig interface { + tc.GlobalTestConfig + tc.CommonTestConfig + tc.KeeperTestConfig + tc.NamedConfiguration + testreporters.GrafanaURLProvider +} + +type OcrTestConfig interface { + tc.GlobalTestConfig + tc.CommonTestConfig + tc.OcrTestConfig +} diff --git a/integration-tests/universal/log_poller/config.go b/integration-tests/universal/log_poller/config.go deleted file mode 100644 index 78a0da46bc6..00000000000 --- a/integration-tests/universal/log_poller/config.go +++ /dev/null @@ -1,249 +0,0 @@ -package logpoller - -import ( - "fmt" - "os" - "strconv" - - "cosmossdk.io/errors" - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/pelletier/go-toml/v2" - "github.com/rs/zerolog/log" - - "github.com/smartcontractkit/chainlink/v2/core/store/models" -) - -const ( - DefaultConfigFilename = "config.toml" - - ErrReadPerfConfig = "failed to read TOML config for performance tests" - ErrUnmarshalPerfConfig = "failed to unmarshal TOML config for performance tests" -) - -type GeneratorType = string - -const ( - GeneratorType_WASP = "wasp" - GeneratorType_Looped = "looped" -) - -type Config struct { - General *General `toml:"general"` - ChaosConfig *ChaosConfig `toml:"chaos"` - Wasp *WaspConfig `toml:"wasp"` - LoopedConfig *LoopedConfig `toml:"looped"` -} - -type LoopedConfig struct { - ContractConfig `toml:"contract"` - FuzzConfig `toml:"fuzz"` -} - -type ContractConfig struct { - ExecutionCount int `toml:"execution_count"` -} - -type FuzzConfig struct { - MinEmitWaitTimeMs int `toml:"min_emit_wait_time_ms"` - MaxEmitWaitTimeMs int `toml:"max_emit_wait_time_ms"` -} - -type General struct { - Generator string `toml:"generator"` - EventsToEmit []abi.Event `toml:"-"` - Contracts int `toml:"contracts"` - EventsPerTx int `toml:"events_per_tx"` - UseFinalityTag bool `toml:"use_finality_tag"` -} - -type ChaosConfig struct { - ExperimentCount int `toml:"experiment_count"` -} - -type WaspConfig struct { - Load *Load `toml:"load"` -} - -type Load struct { - RPS int64 `toml:"rps"` - LPS int64 `toml:"lps"` - RateLimitUnitDuration *models.Duration `toml:"rate_limit_unit_duration"` - Duration *models.Duration `toml:"duration"` - CallTimeout *models.Duration `toml:"call_timeout"` -} - -func ReadConfig(configName string) (*Config, error) { - var cfg *Config - d, err := os.ReadFile(configName) - if err != nil { - return nil, errors.Wrap(err, ErrReadPerfConfig) - } - err = toml.Unmarshal(d, &cfg) - if err != nil { - return nil, errors.Wrap(err, ErrUnmarshalPerfConfig) - } - - if err := cfg.validate(); err != nil { - return nil, err - } - - log.Debug().Interface("Config", cfg).Msg("Parsed config") - return cfg, nil -} - -func (c *Config) OverrideFromEnv() error { - if contr := os.Getenv("CONTRACTS"); contr != "" { - c.General.Contracts = mustParseInt(contr) - } - - if eventsPerTx := os.Getenv("EVENTS_PER_TX"); eventsPerTx != "" { - c.General.EventsPerTx = mustParseInt(eventsPerTx) - } - - if useFinalityTag := os.Getenv("USE_FINALITY_TAG"); useFinalityTag != "" { - c.General.UseFinalityTag = mustParseBool(useFinalityTag) - } - - if duration := os.Getenv("LOAD_DURATION"); duration != "" { - d, err := models.ParseDuration(duration) - if err != nil { - return err - } - - if c.General.Generator == GeneratorType_WASP { - c.Wasp.Load.Duration = &d - } else { - // this is completely arbitrary and practice shows that even with this values - // test executes much longer than specified, probably due to network latency - c.LoopedConfig.FuzzConfig.MinEmitWaitTimeMs = 400 - c.LoopedConfig.FuzzConfig.MaxEmitWaitTimeMs = 600 - // divide by 4 based on past runs, but we should do it in a better way - c.LoopedConfig.ContractConfig.ExecutionCount = int(d.Duration().Seconds() / 4) - } - } - - return nil -} - -func (c *Config) validate() error { - if c.General == nil { - return fmt.Errorf("General config is nil") - } - - err := c.General.validate() - if err != nil { - return fmt.Errorf("General config validation failed: %w", err) - } - - switch c.General.Generator { - case GeneratorType_WASP: - if c.Wasp == nil { - return fmt.Errorf("wasp config is nil") - } - if c.Wasp.Load == nil { - return fmt.Errorf("wasp load config is nil") - } - - err = c.Wasp.validate() - if err != nil { - return fmt.Errorf("wasp config validation failed: %w", err) - } - case GeneratorType_Looped: - if c.LoopedConfig == nil { - return fmt.Errorf("looped config is nil") - } - - err = c.LoopedConfig.validate() - if err != nil { - return fmt.Errorf("looped config validation failed: %w", err) - } - default: - return fmt.Errorf("unknown generator type: %s", c.General.Generator) - } - - return nil -} - -func (g *General) validate() error { - if g.Generator == "" { - return fmt.Errorf("generator is empty") - } - - if g.Contracts == 0 { - return fmt.Errorf("contracts is 0, but must be > 0") - } - - if g.EventsPerTx == 0 { - return fmt.Errorf("events_per_tx is 0, but must be > 0") - } - - return nil -} - -func (w *WaspConfig) validate() error { - if w.Load == nil { - return fmt.Errorf("Load config is nil") - } - - err := w.Load.validate() - if err != nil { - return fmt.Errorf("Load config validation failed: %w", err) - } - - return nil -} - -func (l *Load) validate() error { - if l.RPS == 0 && l.LPS == 0 { - return fmt.Errorf("either RPS or LPS needs to be set") - } - - if l.RPS != 0 && l.LPS != 0 { - return fmt.Errorf("only one of RPS or LPS can be set") - } - - if l.Duration == nil { - return fmt.Errorf("duration is nil") - } - - if l.CallTimeout == nil { - return fmt.Errorf("call_timeout is nil") - } - if l.RateLimitUnitDuration == nil { - return fmt.Errorf("rate_limit_unit_duration is nil") - } - - return nil -} - -func (l *LoopedConfig) validate() error { - if l.ExecutionCount == 0 { - return fmt.Errorf("execution_count is 0, but must be > 0") - } - - if l.MinEmitWaitTimeMs == 0 { - return fmt.Errorf("min_emit_wait_time_ms is 0, but must be > 0") - } - - if l.MaxEmitWaitTimeMs == 0 { - return fmt.Errorf("max_emit_wait_time_ms is 0, but must be > 0") - } - - return nil -} - -func mustParseInt(s string) int { - i, err := strconv.Atoi(s) - if err != nil { - panic(err) - } - return i -} - -func mustParseBool(s string) bool { - b, err := strconv.ParseBool(s) - if err != nil { - panic(err) - } - return b -} diff --git a/integration-tests/universal/log_poller/gun.go b/integration-tests/universal/log_poller/gun.go index 39286f1b53e..a75209aa101 100644 --- a/integration-tests/universal/log_poller/gun.go +++ b/integration-tests/universal/log_poller/gun.go @@ -39,7 +39,7 @@ func NewLogEmitterGun( } } -func (m *LogEmitterGun) Call(l *wasp.Generator) *wasp.CallResult { +func (m *LogEmitterGun) Call(l *wasp.Generator) *wasp.Response { localCounter := 0 logEmitter := (*m.contract) address := logEmitter.Address() @@ -58,7 +58,7 @@ func (m *LogEmitterGun) Call(l *wasp.Generator) *wasp.CallResult { } if err != nil { - return &wasp.CallResult{Error: err.Error(), Failed: true} + return &wasp.Response{Error: err.Error(), Failed: true} } localCounter++ } @@ -69,11 +69,11 @@ func (m *LogEmitterGun) Call(l *wasp.Generator) *wasp.CallResult { defer counter.mu.Unlock() counter.value += localCounter } else { - return &wasp.CallResult{ + return &wasp.Response{ Error: "SharedData did not contain a Counter", Failed: true, } } - return &wasp.CallResult{} + return &wasp.Response{} } diff --git a/integration-tests/universal/log_poller/helpers.go b/integration-tests/universal/log_poller/helpers.go index 7bf1657316f..db7eaee625b 100644 --- a/integration-tests/universal/log_poller/helpers.go +++ b/integration-tests/universal/log_poller/helpers.go @@ -17,17 +17,26 @@ import ( "github.com/ethereum/go-ethereum/common" geth_types "github.com/ethereum/go-ethereum/core/types" "github.com/jmoiron/sqlx" + "github.com/onsi/gomega" "github.com/rs/zerolog" "github.com/scylladb/go-reflectx" "github.com/stretchr/testify/require" "github.com/smartcontractkit/wasp" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-testing-framework/blockchain" ctf_test_env "github.com/smartcontractkit/chainlink-testing-framework/docker/test_env" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/ptr" + "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/client" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" + "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" + "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" cltypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" @@ -35,14 +44,9 @@ import ( le "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" - "github.com/smartcontractkit/chainlink/v2/core/store/models" - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/client" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" + tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + lp_config "github.com/smartcontractkit/chainlink/integration-tests/testconfig/log_poller" ) var ( @@ -134,6 +138,7 @@ var registerSingleTopicFilter = func(registry contracts.KeeperRegistry, upkeepID // return nil // } +// NewOrm returns a new logpoller.DbORM instance func NewOrm(logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_test_env.PostgresDb) (*logpoller.DbORM, *sqlx.DB, error) { dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", "127.0.0.1", postgresDb.ExternalPort, postgresDb.User, postgresDb.Password, postgresDb.DbName) db, err := sqlx.Open("postgres", dsn) @@ -150,7 +155,8 @@ type ExpectedFilter struct { topic common.Hash } -func getExpectedFilters(logEmitters []*contracts.LogEmitter, cfg *Config) []ExpectedFilter { +// GetExpectedFilters returns a slice of ExpectedFilter structs based on the provided log emitters and config +func GetExpectedFilters(logEmitters []*contracts.LogEmitter, cfg *lp_config.Config) []ExpectedFilter { expectedFilters := make([]ExpectedFilter, 0) for _, emitter := range logEmitters { for _, event := range cfg.General.EventsToEmit { @@ -164,16 +170,17 @@ func getExpectedFilters(logEmitters []*contracts.LogEmitter, cfg *Config) []Expe return expectedFilters } -var nodeHasExpectedFilters = func(expectedFilters []ExpectedFilter, logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_test_env.PostgresDb) (bool, error) { +// NodeHasExpectedFilters returns true if the provided node has all the expected filters registered +func NodeHasExpectedFilters(expectedFilters []ExpectedFilter, logger core_logger.SugaredLogger, chainID *big.Int, postgresDb *ctf_test_env.PostgresDb) (bool, string, error) { orm, db, err := NewOrm(logger, chainID, postgresDb) if err != nil { - return false, err + return false, "", err } defer db.Close() knownFilters, err := orm.LoadFilters() if err != nil { - return false, err + return false, "", err } for _, expectedFilter := range expectedFilters { @@ -186,14 +193,15 @@ var nodeHasExpectedFilters = func(expectedFilters []ExpectedFilter, logger core_ } if !filterFound { - return false, fmt.Errorf("no filter found for emitter %s and topic %s", expectedFilter.emitterAddress.String(), expectedFilter.topic.Hex()) + return false, fmt.Sprintf("no filter found for emitter %s and topic %s", expectedFilter.emitterAddress.String(), expectedFilter.topic.Hex()), nil } } - return true, nil + return true, "", nil } -var randomWait = func(minMilliseconds, maxMilliseconds int) { +// randomWait waits for a random amount of time between minMilliseconds and maxMilliseconds +func randomWait(minMilliseconds, maxMilliseconds int) { rand.New(rand.NewSource(time.Now().UnixNano())) randomMilliseconds := rand.Intn(maxMilliseconds-minMilliseconds+1) + minMilliseconds time.Sleep(time.Duration(randomMilliseconds) * time.Millisecond) @@ -202,10 +210,9 @@ var randomWait = func(minMilliseconds, maxMilliseconds int) { type LogEmitterChannel struct { logsEmitted int err error - // unused - // currentIndex int } +// getIntSlice returns a slice of ints of the provided length func getIntSlice(length int) []int { result := make([]int, length) for i := 0; i < length; i++ { @@ -215,6 +222,7 @@ func getIntSlice(length int) []int { return result } +// getStringSlice returns a slice of strings of the provided length func getStringSlice(length int) []string { result := make([]string, length) for i := 0; i < length; i++ { @@ -224,75 +232,67 @@ func getStringSlice(length int) []string { return result } -var emitEvents = func(ctx context.Context, l zerolog.Logger, logEmitter *contracts.LogEmitter, cfg *Config, wg *sync.WaitGroup, results chan LogEmitterChannel) { +// emitEvents emits events from the provided log emitter concurrently according to the provided config +func emitEvents(ctx context.Context, l zerolog.Logger, logEmitter *contracts.LogEmitter, cfg *lp_config.Config, wg *sync.WaitGroup, results chan LogEmitterChannel) { address := (*logEmitter).Address().String() localCounter := 0 - select { - case <-ctx.Done(): - l.Warn().Str("Emitter address", address).Msg("Context cancelled, not emitting events") - return - default: - defer wg.Done() - for i := 0; i < cfg.LoopedConfig.ExecutionCount; i++ { - for _, event := range cfg.General.EventsToEmit { + defer wg.Done() + for i := 0; i < *cfg.LoopedConfig.ExecutionCount; i++ { + for _, event := range cfg.General.EventsToEmit { + select { + case <-ctx.Done(): + l.Warn().Str("Emitter address", address).Msg("Context cancelled, not emitting events") + return + default: l.Debug().Str("Emitter address", address).Str("Event type", event.Name).Str("index", fmt.Sprintf("%d/%d", (i+1), cfg.LoopedConfig.ExecutionCount)).Msg("Emitting log from emitter") var err error switch event.Name { case "Log1": - _, err = (*logEmitter).EmitLogInts(getIntSlice(cfg.General.EventsPerTx)) + _, err = (*logEmitter).EmitLogInts(getIntSlice(*cfg.General.EventsPerTx)) case "Log2": - _, err = (*logEmitter).EmitLogIntsIndexed(getIntSlice(cfg.General.EventsPerTx)) + _, err = (*logEmitter).EmitLogIntsIndexed(getIntSlice(*cfg.General.EventsPerTx)) case "Log3": - _, err = (*logEmitter).EmitLogStrings(getStringSlice(cfg.General.EventsPerTx)) + _, err = (*logEmitter).EmitLogStrings(getStringSlice(*cfg.General.EventsPerTx)) + case "Log4": + _, err = (*logEmitter).EmitLogIntMultiIndexed(1, 1, *cfg.General.EventsPerTx) default: err = fmt.Errorf("unknown event name: %s", event.Name) } if err != nil { results <- LogEmitterChannel{ - logsEmitted: 0, - err: err, + err: err, } return } - localCounter += cfg.General.EventsPerTx + localCounter += *cfg.General.EventsPerTx - randomWait(cfg.LoopedConfig.FuzzConfig.MinEmitWaitTimeMs, cfg.LoopedConfig.FuzzConfig.MaxEmitWaitTimeMs) + randomWait(*cfg.LoopedConfig.MinEmitWaitTimeMs, *cfg.LoopedConfig.MaxEmitWaitTimeMs) } if (i+1)%10 == 0 { - l.Info().Str("Emitter address", address).Str("Index", fmt.Sprintf("%d/%d", i+1, cfg.LoopedConfig.ExecutionCount)).Msg("Emitted all three events") + l.Info().Str("Emitter address", address).Str("Index", fmt.Sprintf("%d/%d", i+1, *cfg.LoopedConfig.ExecutionCount)).Msg("Emitted all three events") } } - - l.Info().Str("Emitter address", address).Int("Total logs emitted", localCounter).Msg("Finished emitting events") - - results <- LogEmitterChannel{ - logsEmitted: localCounter, - err: nil, - } } -} -var chainHasFinalisedEndBlock = func(l zerolog.Logger, evmClient blockchain.EVMClient, endBlock int64) (bool, error) { - effectiveEndBlock := endBlock + 1 - lastFinalisedBlockHeader, err := evmClient.GetLatestFinalizedBlockHeader(context.Background()) - if err != nil { - return false, err - } + l.Info().Str("Emitter address", address).Int("Total logs emitted", localCounter).Msg("Finished emitting events") - l.Info().Int64("Last finalised block header", lastFinalisedBlockHeader.Number.Int64()).Int64("End block", effectiveEndBlock).Int64("Blocks left till end block", effectiveEndBlock-lastFinalisedBlockHeader.Number.Int64()).Msg("Waiting for the finalized block to move beyond end block") - - return lastFinalisedBlockHeader.Number.Int64() > effectiveEndBlock, nil + results <- LogEmitterChannel{ + logsEmitted: localCounter, + err: nil, + } } -var logPollerHasFinalisedEndBlock = func(endBlock int64, chainID *big.Int, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { +// LogPollerHasFinalisedEndBlock returns true if all CL nodes have finalised processing the provided end block +func LogPollerHasFinalisedEndBlock(endBlock int64, chainID *big.Int, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { wg := &sync.WaitGroup{} type boolQueryResult struct { - nodeName string - hasFinalised bool - err error + nodeName string + hasFinalised bool + finalizedBlock int64 + err error } endBlockCh := make(chan boolQueryResult, len(nodes.Nodes)-1) @@ -328,9 +328,10 @@ var logPollerHasFinalisedEndBlock = func(endBlock int64, chainID *big.Int, l zer } r <- boolQueryResult{ - nodeName: clNode.ContainerName, - hasFinalised: latestBlock.FinalizedBlockNumber > endBlock, - err: nil, + nodeName: clNode.ContainerName, + finalizedBlock: latestBlock.FinalizedBlockNumber, + hasFinalised: latestBlock.FinalizedBlockNumber > endBlock, + err: nil, } } @@ -353,7 +354,7 @@ var logPollerHasFinalisedEndBlock = func(endBlock int64, chainID *big.Int, l zer if r.hasFinalised { l.Info().Str("Node name", r.nodeName).Msg("CL node has finalised end block") } else { - l.Warn().Str("Node name", r.nodeName).Msg("CL node has not finalised end block yet") + l.Warn().Int64("Has", r.finalizedBlock).Int64("Want", endBlock).Str("Node name", r.nodeName).Msg("CL node has not finalised end block yet") } if len(foundMap) == len(nodes.Nodes)-1 { @@ -377,7 +378,8 @@ var logPollerHasFinalisedEndBlock = func(endBlock int64, chainID *big.Int, l zer return <-allFinalisedCh, err } -var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big.Int, expectedLogCount int, expectedFilters []ExpectedFilter, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { +// ClNodesHaveExpectedLogCount returns true if all CL nodes have the expected log count in the provided block range and matching the provided filters +func ClNodesHaveExpectedLogCount(startBlock, endBlock int64, chainID *big.Int, expectedLogCount int, expectedFilters []ExpectedFilter, l zerolog.Logger, coreLogger core_logger.SugaredLogger, nodes *test_env.ClCluster) (bool, error) { wg := &sync.WaitGroup{} type logQueryResult struct { @@ -387,13 +389,13 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. err error } - queryCh := make(chan logQueryResult, len(nodes.Nodes)-1) + resultChan := make(chan logQueryResult, len(nodes.Nodes)-1) ctx, cancelFn := context.WithCancel(context.Background()) for i := 1; i < len(nodes.Nodes); i++ { wg.Add(1) - go func(clNode *test_env.ClNode, r chan logQueryResult) { + go func(clNode *test_env.ClNode, resultChan chan logQueryResult) { defer wg.Done() select { case <-ctx.Done(): @@ -401,7 +403,7 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. default: orm, db, err := NewOrm(coreLogger, chainID, clNode.PostgresDb) if err != nil { - r <- logQueryResult{ + resultChan <- logQueryResult{ nodeName: clNode.ContainerName, logCount: 0, hasExpectedCount: false, @@ -415,7 +417,7 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. for _, filter := range expectedFilters { logs, err := orm.SelectLogs(startBlock, endBlock, filter.emitterAddress, filter.topic) if err != nil { - r <- logQueryResult{ + resultChan <- logQueryResult{ nodeName: clNode.ContainerName, logCount: 0, hasExpectedCount: false, @@ -426,14 +428,14 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. foundLogsCount += len(logs) } - r <- logQueryResult{ + resultChan <- logQueryResult{ nodeName: clNode.ContainerName, logCount: foundLogsCount, hasExpectedCount: foundLogsCount >= expectedLogCount, - err: err, + err: nil, } } - }(nodes.Nodes[i], queryCh) + }(nodes.Nodes[i], resultChan) } var err error @@ -441,7 +443,7 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. go func() { foundMap := make(map[string]bool, 0) - for r := range queryCh { + for r := range resultChan { if r.err != nil { err = r.err cancelFn() @@ -450,15 +452,22 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. foundMap[r.nodeName] = r.hasExpectedCount if r.hasExpectedCount { - l.Info().Str("Node name", r.nodeName).Int("Logs count", r.logCount).Msg("Expected log count found in CL node") + l.Debug(). + Str("Node name", r.nodeName). + Int("Logs count", r.logCount). + Msg("Expected log count found in CL node") } else { - l.Warn().Str("Node name", r.nodeName).Str("Found/Expected logs", fmt.Sprintf("%d/%d", r.logCount, expectedLogCount)).Int("Missing logs", expectedLogCount-r.logCount).Msg("Too low log count found in CL node") + l.Debug(). + Str("Node name", r.nodeName). + Str("Found/Expected logs", fmt.Sprintf("%d/%d", r.logCount, expectedLogCount)). + Int("Missing logs", expectedLogCount-r.logCount). + Msg("Too low log count found in CL node") } if len(foundMap) == len(nodes.Nodes)-1 { allFound := true - for _, v := range foundMap { - if !v { + for _, hadAllLogs := range foundMap { + if !hadAllLogs { allFound = false break } @@ -471,13 +480,14 @@ var clNodesHaveExpectedLogCount = func(startBlock, endBlock int64, chainID *big. }() wg.Wait() - close(queryCh) + close(resultChan) return <-allFoundCh, err } type MissingLogs map[string][]geth_types.Log +// IsEmpty returns true if there are no missing logs func (m *MissingLogs) IsEmpty() bool { for _, v := range *m { if len(v) > 0 { @@ -488,7 +498,8 @@ func (m *MissingLogs) IsEmpty() bool { return true } -var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient blockchain.EVMClient, clnodeCluster *test_env.ClCluster, l zerolog.Logger, coreLogger core_logger.SugaredLogger, cfg *Config) (MissingLogs, error) { +// GetMissingLogs returns a map of CL node name to missing logs in that node compared to EVM node to which the provided evm client is connected +func GetMissingLogs(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient blockchain.EVMClient, clnodeCluster *test_env.ClCluster, l zerolog.Logger, coreLogger core_logger.SugaredLogger, cfg *lp_config.Config) (MissingLogs, error) { wg := &sync.WaitGroup{} type dbQueryResult struct { @@ -512,7 +523,7 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L default: nodeName := clnodeCluster.Nodes[i].ContainerName - l.Info().Str("Node name", nodeName).Msg("Fetching log poller logs") + l.Debug().Str("Node name", nodeName).Msg("Fetching log poller logs") orm, db, err := NewOrm(coreLogger, evmClient.GetChainID(), clnodeCluster.Nodes[i].PostgresDb) if err != nil { r <- dbQueryResult{ @@ -529,7 +540,7 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L address := (*logEmitters[j]).Address() for _, event := range cfg.General.EventsToEmit { - l.Debug().Str("Event name", event.Name).Str("Emitter address", address.String()).Msg("Fetching single emitter's logs") + l.Trace().Str("Event name", event.Name).Str("Emitter address", address.String()).Msg("Fetching single emitter's logs") result, err := orm.SelectLogs(startBlock, endBlock, address, event.ID) if err != nil { r <- dbQueryResult{ @@ -545,11 +556,11 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L logs = append(logs, result...) - l.Debug().Str("Event name", event.Name).Str("Emitter address", address.String()).Int("Log count", len(result)).Msg("Logs found per node") + l.Trace().Str("Event name", event.Name).Str("Emitter address", address.String()).Int("Log count", len(result)).Msg("Logs found per node") } } - l.Warn().Int("Count", len(logs)).Str("Node name", nodeName).Msg("Fetched log poller logs") + l.Info().Int("Count", len(logs)).Str("Node name", nodeName).Msg("Fetched log poller logs") r <- dbQueryResult{ err: nil, @@ -596,16 +607,17 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L logs []geth_types.Log } - l.Info().Msg("Started comparison of logs from EVM node and CL nodes. This may take a while if there's a lot of logs") - missingCh := make(chan missingLogResult, len(clnodeCluster.Nodes)-1) evmLogCount := len(allLogsInEVMNode) + l.Info().Int("Log count", evmLogCount).Msg("Started comparison of logs from EVM node and CL nodes. This may take a while if there's a lot of logs") + + missingCh := make(chan missingLogResult, len(clnodeCluster.Nodes)-1) for i := 1; i < len(clnodeCluster.Nodes); i++ { wg.Add(1) go func(i int, result chan missingLogResult) { defer wg.Done() nodeName := clnodeCluster.Nodes[i].ContainerName - l.Info().Str("Node name", nodeName).Str("Progress", fmt.Sprintf("0/%d", evmLogCount)).Msg("Comparing single CL node's logs with EVM logs") + l.Debug().Str("Node name", nodeName).Str("Progress", fmt.Sprintf("0/%d", evmLogCount)).Msg("Comparing single CL node's logs with EVM logs") missingLogs := make([]geth_types.Log, 0) for i, evmLog := range allLogsInEVMNode { @@ -619,7 +631,7 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L } if i%10000 == 0 && i != 0 { - l.Info().Str("Node name", nodeName).Str("Progress", fmt.Sprintf("%d/%d", i, evmLogCount)).Msg("Comparing single CL node's logs with EVM logs") + l.Debug().Str("Node name", nodeName).Str("Progress", fmt.Sprintf("%d/%d", i, evmLogCount)).Msg("Comparing single CL node's logs with EVM logs") } if !logFound { @@ -649,15 +661,18 @@ var getMissingLogs = func(startBlock, endBlock int64, logEmitters []*contracts.L } } - expectedTotalLogsEmitted := getExpectedLogCount(cfg) + expectedTotalLogsEmitted := GetExpectedLogCount(cfg) if int64(len(allLogsInEVMNode)) != expectedTotalLogsEmitted { - l.Warn().Str("Actual/Expected", fmt.Sprintf("%d/%d", expectedTotalLogsEmitted, len(allLogsInEVMNode))).Msg("Some of the test logs were not found in EVM node. This is a bug in the test") + l.Warn(). + Str("Actual/Expected", fmt.Sprintf("%d/%d", expectedTotalLogsEmitted, len(allLogsInEVMNode))). + Msg("Some of the test logs were not found in EVM node. This is a bug in the test") } return missingLogs, nil } -var printMissingLogsByType = func(missingLogs map[string][]geth_types.Log, l zerolog.Logger, cfg *Config) { +// PrintMissingLogsInfo prints various useful information about the missing logs +func PrintMissingLogsInfo(missingLogs map[string][]geth_types.Log, l zerolog.Logger, cfg *lp_config.Config) { var findHumanName = func(topic common.Hash) string { for _, event := range cfg.General.EventsToEmit { if event.ID == topic { @@ -676,12 +691,39 @@ var printMissingLogsByType = func(missingLogs map[string][]geth_types.Log, l zer } } + l.Debug().Msg("Missing log by event name") for k, v := range missingByType { - l.Warn().Str("Event name", k).Int("Missing count", v).Msg("Missing logs by type") + l.Debug().Str("Event name", k).Int("Missing count", v).Msg("Missing logs by type") + } + + missingByBlock := make(map[uint64]int) + for _, logs := range missingLogs { + for _, l := range logs { + missingByBlock[l.BlockNumber]++ + } + } + + l.Debug().Msg("Missing logs by block") + for k, v := range missingByBlock { + l.Debug().Uint64("Block number", k).Int("Missing count", v).Msg("Missing logs by block") + } + + missingByEmitter := make(map[string]int) + for _, logs := range missingLogs { + for _, l := range logs { + missingByEmitter[l.Address.String()]++ + } + } + + l.Debug().Msg("Missing logs by emitter") + for k, v := range missingByEmitter { + l.Debug().Str("Emitter address", k).Int("Missing count", v).Msg("Missing logs by emitter") } } -var getEVMLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient blockchain.EVMClient, l zerolog.Logger, cfg *Config) ([]geth_types.Log, error) { +// getEVMLogs returns a slice of all logs emitted by the provided log emitters in the provided block range, +// which are present in the EVM node to which the provided evm client is connected +func getEVMLogs(startBlock, endBlock int64, logEmitters []*contracts.LogEmitter, evmClient blockchain.EVMClient, l zerolog.Logger, cfg *lp_config.Config) ([]geth_types.Log, error) { allLogsInEVMNode := make([]geth_types.Log, 0) for j := 0; j < len(logEmitters); j++ { address := (*logEmitters[j]).Address() @@ -706,27 +748,29 @@ var getEVMLogs = func(startBlock, endBlock int64, logEmitters []*contracts.LogEm } } - l.Warn().Int("Count", len(allLogsInEVMNode)).Msg("Logs in EVM node") + l.Info().Int("Count", len(allLogsInEVMNode)).Msg("Logs in EVM node") return allLogsInEVMNode, nil } -func executeGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmitter) (int, error) { - if cfg.General.Generator == GeneratorType_WASP { +// ExecuteGenerator executes the configured generator and returns the total number of logs emitted +func ExecuteGenerator(t *testing.T, cfg *lp_config.Config, logEmitters []*contracts.LogEmitter) (int, error) { + if *cfg.General.Generator == lp_config.GeneratorType_WASP { return runWaspGenerator(t, cfg, logEmitters) } return runLoopedGenerator(t, cfg, logEmitters) } -func runWaspGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmitter) (int, error) { +// runWaspGenerator runs the wasp generator and returns the total number of logs emitted +func runWaspGenerator(t *testing.T, cfg *lp_config.Config, logEmitters []*contracts.LogEmitter) (int, error) { l := logging.GetTestLogger(t) var RPSprime int64 // if LPS is set, we need to calculate based on countract count and events per transaction - if cfg.Wasp.Load.LPS > 0 { - RPSprime = cfg.Wasp.Load.LPS / int64(cfg.General.Contracts) / int64(cfg.General.EventsPerTx) / int64(len(cfg.General.EventsToEmit)) + if *cfg.Wasp.LPS > 0 { + RPSprime = *cfg.Wasp.LPS / int64(*cfg.General.Contracts) / int64(*cfg.General.EventsPerTx) / int64(len(cfg.General.EventsToEmit)) if RPSprime < 1 { return 0, fmt.Errorf("invalid load configuration, effective RPS would have been zero. Adjust LPS, contracts count, events per tx or events to emit") @@ -734,8 +778,8 @@ func runWaspGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmi } // if RPS is set simply split it between contracts - if cfg.Wasp.Load.RPS > 0 { - RPSprime = cfg.Wasp.Load.RPS / int64(cfg.General.Contracts) + if *cfg.Wasp.RPS > 0 { + RPSprime = *cfg.Wasp.RPS / int64(*cfg.General.Contracts) } counter := &Counter{ @@ -750,16 +794,16 @@ func runWaspGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmi T: t, LoadType: wasp.RPS, GenName: fmt.Sprintf("log_poller_gen_%s", (*logEmitter).Address().String()), - RateLimitUnitDuration: cfg.Wasp.Load.RateLimitUnitDuration.Duration(), - CallTimeout: cfg.Wasp.Load.CallTimeout.Duration(), + RateLimitUnitDuration: cfg.Wasp.RateLimitUnitDuration.Duration, + CallTimeout: cfg.Wasp.CallTimeout.Duration, Schedule: wasp.Plain( RPSprime, - cfg.Wasp.Load.Duration.Duration(), + cfg.Wasp.Duration.Duration, ), Gun: NewLogEmitterGun( logEmitter, cfg.General.EventsToEmit, - cfg.General.EventsPerTx, + *cfg.General.EventsPerTx, l, ), SharedData: counter, @@ -776,7 +820,8 @@ func runWaspGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmi return counter.value, nil } -func runLoopedGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogEmitter) (int, error) { +// runLoopedGenerator runs the looped generator and returns the total number of logs emitted +func runLoopedGenerator(t *testing.T, cfg *lp_config.Config, logEmitters []*contracts.LogEmitter) (int, error) { l := logging.GetTestLogger(t) // Start emitting events in parallel, each contract is emitting events in a separate goroutine @@ -798,82 +843,119 @@ func runLoopedGenerator(t *testing.T, cfg *Config, logEmitters []*contracts.LogE aggrChan := make(chan int, len(logEmitters)) go func() { - for emitter := range emitterCh { - if emitter.err != nil { - emitErr = emitter.err - cancelFn() + for { + select { + case <-ctx.Done(): return + case emitter := <-emitterCh: + if emitter.err != nil { + emitErr = emitter.err + cancelFn() + return + } + aggrChan <- emitter.logsEmitted } - aggrChan <- emitter.logsEmitted } }() wg.Wait() close(emitterCh) - for i := 0; i < len(logEmitters); i++ { - total += <-aggrChan - } - if emitErr != nil { return 0, emitErr } + for i := 0; i < len(logEmitters); i++ { + total += <-aggrChan + } + return int(total), nil } -func getExpectedLogCount(cfg *Config) int64 { - if cfg.General.Generator == GeneratorType_WASP { - if cfg.Wasp.Load.RPS != 0 { - return cfg.Wasp.Load.RPS * int64(cfg.Wasp.Load.Duration.Duration().Seconds()) * int64(cfg.General.EventsPerTx) +// GetExpectedLogCount returns the expected number of logs to be emitted based on the provided config +func GetExpectedLogCount(cfg *lp_config.Config) int64 { + if *cfg.General.Generator == lp_config.GeneratorType_WASP { + if *cfg.Wasp.RPS != 0 { + return *cfg.Wasp.RPS * int64(cfg.Wasp.Duration.Seconds()) * int64(*cfg.General.EventsPerTx) } - return cfg.Wasp.Load.LPS * int64(cfg.Wasp.Load.Duration.Duration().Seconds()) + return *cfg.Wasp.LPS * int64(cfg.Wasp.Duration.Duration.Seconds()) } - return int64(len(cfg.General.EventsToEmit) * cfg.LoopedConfig.ExecutionCount * cfg.General.Contracts * cfg.General.EventsPerTx) + return int64(len(cfg.General.EventsToEmit) * *cfg.LoopedConfig.ExecutionCount * *cfg.General.Contracts * *cfg.General.EventsPerTx) +} + +type PauseData struct { + StartBlock uint64 + EndBlock uint64 + TargetComponent string + ContaineName string } -var chaosPauseSyncFn = func(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv) error { +var ChaosPauses = []PauseData{} + +// chaosPauseSyncFn pauses ranom container of the provided type for a random amount of time between 5 and 20 seconds +func chaosPauseSyncFn(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, targetComponent string) ChaosPauseData { rand.New(rand.NewSource(time.Now().UnixNano())) - randomBool := rand.Intn(2) == 0 randomNode := testEnv.ClCluster.Nodes[rand.Intn(len(testEnv.ClCluster.Nodes)-1)+1] var component ctf_test_env.EnvComponent - if randomBool { + switch strings.ToLower(targetComponent) { + case "chainlink": component = randomNode.EnvComponent - } else { + case "postgres": component = randomNode.PostgresDb.EnvComponent + default: + return ChaosPauseData{Err: fmt.Errorf("unknown component %s", targetComponent)} } + ctx := context.Background() + pauseStartBlock, err := testEnv.EVMClient.LatestBlockNumber(ctx) + if err != nil { + return ChaosPauseData{Err: err} + } pauseTimeSec := rand.Intn(20-5) + 5 l.Info().Str("Container", component.ContainerName).Int("Pause time", pauseTimeSec).Msg("Pausing component") pauseTimeDur := time.Duration(pauseTimeSec) * time.Second - err := component.ChaosPause(l, pauseTimeDur) + err = component.ChaosPause(l, pauseTimeDur) + if err != nil { + return ChaosPauseData{Err: err} + } l.Info().Str("Container", component.ContainerName).Msg("Component unpaused") + pauseEndBlock, err := testEnv.EVMClient.LatestBlockNumber(ctx) if err != nil { - return err + return ChaosPauseData{Err: err} } - return nil + return ChaosPauseData{PauseData: PauseData{ + StartBlock: pauseStartBlock, + EndBlock: pauseEndBlock, + TargetComponent: targetComponent, + ContaineName: component.ContainerName, + }} } -var executeChaosExperiment = func(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, cfg *Config, errorCh chan error) { - if cfg.ChaosConfig == nil || cfg.ChaosConfig.ExperimentCount == 0 { +type ChaosPauseData struct { + Err error + PauseData PauseData +} + +// ExecuteChaosExperiment executes the configured chaos experiment, which consist of pausing CL node or Postgres containers +func ExecuteChaosExperiment(l zerolog.Logger, testEnv *test_env.CLClusterTestEnv, cfg *lp_config.Config, errorCh chan error) { + if cfg.ChaosConfig == nil || *cfg.ChaosConfig.ExperimentCount == 0 { errorCh <- nil return } - chaosChan := make(chan error, cfg.ChaosConfig.ExperimentCount) - + chaosChan := make(chan ChaosPauseData, *cfg.ChaosConfig.ExperimentCount) wg := &sync.WaitGroup{} go func() { // if we wanted to have more than 1 container paused, we'd need to make sure we aren't trying to pause an already paused one guardChan := make(chan struct{}, 1) - for i := 0; i < cfg.ChaosConfig.ExperimentCount; i++ { + for i := 0; i < *cfg.ChaosConfig.ExperimentCount; i++ { i := i wg.Add(1) guardChan <- struct{}{} @@ -881,9 +963,11 @@ var executeChaosExperiment = func(l zerolog.Logger, testEnv *test_env.CLClusterT defer func() { <-guardChan wg.Done() - l.Info().Str("Current/Total", fmt.Sprintf("%d/%d", i, cfg.ChaosConfig.ExperimentCount)).Msg("Done with experiment") + current := i + 1 + l.Info().Str("Current/Total", fmt.Sprintf("%d/%d", current, cfg.ChaosConfig.ExperimentCount)).Msg("Done with experiment") }() - chaosChan <- chaosPauseSyncFn(l, testEnv) + chaosChan <- chaosPauseSyncFn(l, testEnv, *cfg.ChaosConfig.TargetComponent) + time.Sleep(10 * time.Second) }() } @@ -893,25 +977,28 @@ var executeChaosExperiment = func(l zerolog.Logger, testEnv *test_env.CLClusterT }() go func() { - for err := range chaosChan { - // This will receive errors until chaosChan is closed - if err != nil { - // If an error is encountered, log it, send it to the error channel, and return from the function - l.Err(err).Msg("Error encountered during chaos experiment") - errorCh <- err + var pauseData []PauseData + for result := range chaosChan { + if result.Err != nil { + l.Err(result.Err).Msg("Error encountered during chaos experiment") + errorCh <- result.Err return // Return on actual error } - // No need for an else block here, because if err is nil (which happens when the channel is closed), - // the loop will exit and the following log and nil send will execute. + + pauseData = append(pauseData, result.PauseData) } - // After the loop exits, which it will do when chaosChan is closed, log that all experiments are finished. l.Info().Msg("All chaos experiments finished") errorCh <- nil // Only send nil once, after all errors have been handled and the channel is closed + + for _, p := range pauseData { + l.Debug().Str("Target component", p.TargetComponent).Str("Container", p.ContaineName).Str("Block range", fmt.Sprintf("%d - %d", p.StartBlock, p.EndBlock)).Msgf("Details of executed chaos pause") + } }() } -var GetFinalityDepth = func(chainId int64) (int64, error) { +// GetFinalityDepth returns the finality depth for the provided chain ID +func GetFinalityDepth(chainId int64) (int64, error) { var finalityDepth int64 switch chainId { // Ethereum Sepolia @@ -930,8 +1017,9 @@ var GetFinalityDepth = func(chainId int64) (int64, error) { return finalityDepth, nil } -var GetEndBlockToWaitFor = func(endBlock, chainId int64, cfg *Config) (int64, error) { - if cfg.General.UseFinalityTag { +// GetEndBlockToWaitFor returns the end block to wait for based on chain id and finality tag provided in config +func GetEndBlockToWaitFor(endBlock, chainId int64, cfg *lp_config.Config) (int64, error) { + if *cfg.General.UseFinalityTag { return endBlock + 1, nil } @@ -952,7 +1040,7 @@ const ( ) var ( - defaultOCRRegistryConfig = contracts.KeeperRegistrySettings{ + DefaultOCRRegistryConfig = contracts.KeeperRegistrySettings{ PaymentPremiumPPB: uint32(200000000), FlatFeeMicroLINK: uint32(0), BlockCountPerTurn: big.NewInt(10), @@ -983,13 +1071,15 @@ var ( } ) -func setupLogPollerTestDocker( +// SetupLogPollerTestDocker starts the DON and private Ethereum network +func SetupLogPollerTestDocker( t *testing.T, registryVersion ethereum.KeeperRegistryVersion, registryConfig contracts.KeeperRegistrySettings, upkeepsNeeded int, lpPollingInterval time.Duration, finalityTagEnabled bool, + testConfig *tc.TestConfig, ) ( blockchain.EVMClient, []*client.ChainlinkClient, @@ -1000,16 +1090,17 @@ func setupLogPollerTestDocker( *test_env.CLClusterTestEnv, ) { l := logging.GetTestLogger(t) + // Add registry version to config registryConfig.RegistryVersion = registryVersion - network := networks.MustGetSelectedNetworksFromEnv()[0] + network := networks.MustGetSelectedNetworkConfig(testConfig.Network)[0] finalityDepth, err := GetFinalityDepth(network.ChainID) require.NoError(t, err, "Error getting finality depth") // build the node config clNodeConfig := node.NewConfig(node.NewBaseConfig()) - syncInterval := models.MustMakeDuration(5 * time.Minute) + syncInterval := *commonconfig.MustNewDuration(5 * time.Minute) clNodeConfig.Feature.LogPoller = ptr.Ptr[bool](true) clNodeConfig.OCR2.Enabled = ptr.Ptr[bool](true) clNodeConfig.Keeper.TurnLookBack = ptr.Ptr[int64](int64(0)) @@ -1026,7 +1117,7 @@ func setupLogPollerTestDocker( clNodesCount := 5 var logPolllerSettingsFn = func(chain *evmcfg.Chain) *evmcfg.Chain { - chain.LogPollInterval = models.MustNewDuration(lpPollingInterval) + chain.LogPollInterval = commonconfig.MustNewDuration(lpPollingInterval) chain.FinalityDepth = ptr.Ptr[uint32](uint32(finalityDepth)) chain.FinalityTagEnabled = ptr.Ptr[bool](finalityTagEnabled) return chain @@ -1043,15 +1134,16 @@ func setupLogPollerTestDocker( WithConsensusType(ctf_test_env.ConsensusType_PoS). WithConsensusLayer(ctf_test_env.ConsensusLayer_Prysm). WithExecutionLayer(ctf_test_env.ExecutionLayer_Geth). - WithBeaconChainConfig(ctf_test_env.BeaconChainConfig{ - SecondsPerSlot: 8, + WithEthereumChainConfig(ctf_test_env.EthereumChainConfig{ + SecondsPerSlot: 4, SlotsPerEpoch: 2, }). Build() require.NoError(t, err, "Error building ethereum network config") env, err = test_env.NewCLTestEnvBuilder(). - WithTestLogger(t). + WithTestConfig(testConfig). + WithTestInstance(t). WithPrivateEthereumNetwork(cfg). WithCLNodes(clNodesCount). WithCLNodeConfig(clNodeConfig). @@ -1116,3 +1208,131 @@ func setupLogPollerTestDocker( return env.EVMClient, nodeClients, env.ContractDeployer, linkToken, registry, registrar, env } + +// UploadLogEmitterContractsAndWaitForFinalisation uploads the configured number of log emitter contracts and waits for the upload blocks to be finalised +func UploadLogEmitterContractsAndWaitForFinalisation(l zerolog.Logger, t *testing.T, testEnv *test_env.CLClusterTestEnv, cfg *lp_config.Config) []*contracts.LogEmitter { + logEmitters := make([]*contracts.LogEmitter, 0) + for i := 0; i < *cfg.General.Contracts; i++ { + logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() + logEmitters = append(logEmitters, &logEmitter) + require.NoError(t, err, "Error deploying log emitter contract") + l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") + time.Sleep(200 * time.Millisecond) + } + afterUploadBlock, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) + require.NoError(t, err, "Error getting latest block number") + + gom := gomega.NewGomegaWithT(t) + gom.Eventually(func(g gomega.Gomega) { + targetBlockNumber := int64(afterUploadBlock + 1) + finalized, err := testEnv.EVMClient.GetLatestFinalizedBlockHeader(testcontext.Get(t)) + if err != nil { + l.Warn().Err(err).Msg("Error checking if contract were uploaded. Retrying...") + return + } + finalizedBlockNumber := finalized.Number.Int64() + + if finalizedBlockNumber < targetBlockNumber { + l.Debug().Int64("Finalized block", finalized.Number.Int64()).Int64("After upload block", int64(afterUploadBlock+1)).Msg("Waiting for contract upload to finalise") + } + + g.Expect(finalizedBlockNumber >= targetBlockNumber).To(gomega.BeTrue(), "Contract upload did not finalize in time") + }, "2m", "10s").Should(gomega.Succeed()) + + return logEmitters +} + +// AssertUpkeepIdsUniqueness asserts that the provided upkeep IDs are unique +func AssertUpkeepIdsUniqueness(upkeepIDs []*big.Int) error { + upKeepIdSeen := make(map[int64]bool) + for _, upkeepID := range upkeepIDs { + if _, ok := upKeepIdSeen[upkeepID.Int64()]; ok { + return fmt.Errorf("Duplicate upkeep ID %d", upkeepID.Int64()) + } + upKeepIdSeen[upkeepID.Int64()] = true + } + + return nil +} + +// AssertContractAddressUniquneness asserts that the provided contract addresses are unique +func AssertContractAddressUniquneness(logEmitters []*contracts.LogEmitter) error { + contractAddressSeen := make(map[string]bool) + for _, logEmitter := range logEmitters { + address := (*logEmitter).Address().String() + if _, ok := contractAddressSeen[address]; ok { + return fmt.Errorf("Duplicate contract address %s", address) + } + contractAddressSeen[address] = true + } + + return nil +} + +// RegisterFiltersAndAssertUniquness registers the configured log filters and asserts that the filters are unique +// meaning that for each log emitter address and topic there is only one filter +func RegisterFiltersAndAssertUniquness(l zerolog.Logger, registry contracts.KeeperRegistry, upkeepIDs []*big.Int, logEmitters []*contracts.LogEmitter, cfg *lp_config.Config, upKeepsNeeded int) error { + uniqueFilters := make(map[string]bool) + + upkeepIdIndex := 0 + for i := 0; i < len(logEmitters); i++ { + for j := 0; j < len(cfg.General.EventsToEmit); j++ { + emitterAddress := (*logEmitters[i]).Address() + topicId := cfg.General.EventsToEmit[j].ID + + upkeepID := upkeepIDs[upkeepIdIndex] + l.Debug().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") + err := registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) + randomWait(150, 300) + if err != nil { + return fmt.Errorf("%w: Error registering log trigger for log emitter %s", err, emitterAddress.String()) + } + + if i%10 == 0 { + l.Info().Msgf("Registered log trigger for topic %d for log emitter %d/%d", j, i, len(logEmitters)) + } + + key := fmt.Sprintf("%s-%s", emitterAddress.String(), topicId.Hex()) + if _, ok := uniqueFilters[key]; ok { + return fmt.Errorf("Duplicate filter %s", key) + } + uniqueFilters[key] = true + upkeepIdIndex++ + } + } + + if upKeepsNeeded != len(uniqueFilters) { + return fmt.Errorf("Number of unique filters should be equal to number of upkeeps. Expected %d. Got %d", upKeepsNeeded, len(uniqueFilters)) + } + + return nil +} + +// FluentlyCheckIfAllNodesHaveLogCount checks if all CL nodes have the expected log count for the provided block range and expected filters +// It will retry until the provided duration is reached or until all nodes have the expected log count +func FluentlyCheckIfAllNodesHaveLogCount(duration string, startBlock, endBlock int64, expectedLogCount int, expectedFilters []ExpectedFilter, l zerolog.Logger, coreLogger core_logger.SugaredLogger, testEnv *test_env.CLClusterTestEnv) (bool, error) { + logCountWaitDuration, err := time.ParseDuration(duration) + if err != nil { + return false, err + } + endTime := time.Now().Add(logCountWaitDuration) + + // not using gomega here, because I want to see which logs were missing + allNodesLogCountMatches := false + for time.Now().Before(endTime) { + logCountMatches, clErr := ClNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), expectedLogCount, expectedFilters, l, coreLogger, testEnv.ClCluster) + if clErr != nil { + l.Warn(). + Err(clErr). + Msg("Error checking if CL nodes have expected log count. Retrying...") + } + if logCountMatches { + allNodesLogCountMatches = true + break + } + l.Warn(). + Msg("At least one CL node did not have expected log count. Retrying...") + } + + return allNodesLogCountMatches, nil +} diff --git a/integration-tests/universal/log_poller/scenarios.go b/integration-tests/universal/log_poller/scenarios.go deleted file mode 100644 index 5331c63f752..00000000000 --- a/integration-tests/universal/log_poller/scenarios.go +++ /dev/null @@ -1,496 +0,0 @@ -package logpoller - -import ( - "fmt" - "math/big" - "testing" - "time" - - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/logging" - "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - "github.com/smartcontractkit/chainlink/integration-tests/actions" - "github.com/smartcontractkit/chainlink/integration-tests/contracts" - "github.com/smartcontractkit/chainlink/integration-tests/contracts/ethereum" - core_logger "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -func ExecuteBasicLogPollerTest(t *testing.T, cfg *Config) { - l := logging.GetTestLogger(t) - coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ - - if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { - l.Warn().Msg("No events to emit specified, using all events from log emitter contract") - for _, event := range EmitterABI.Events { - cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) - } - } - - l.Info().Msg("Starting basic log poller test") - - var ( - err error - upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) - ) - - chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( - t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(500*time.Millisecond), cfg.General.UseFinalityTag, - ) - - _, upkeepIDs := actions.DeployConsumers( - t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, - upKeepsNeeded, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - true, - false, - ) - - // Deploy Log Emitter contracts - logEmitters := make([]*contracts.LogEmitter, 0) - for i := 0; i < cfg.General.Contracts; i++ { - logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() - logEmitters = append(logEmitters, &logEmitter) - require.NoError(t, err, "Error deploying log emitter contract") - l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") - time.Sleep(200 * time.Millisecond) - } - - // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) - // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) - for i := 0; i < len(upkeepIDs); i++ { - emitterAddress := (*logEmitters[i%cfg.General.Contracts]).Address() - upkeepID := upkeepIDs[i] - topicId := cfg.General.EventsToEmit[i%len(cfg.General.EventsToEmit)].ID - - l.Info().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") - err = registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) - randomWait(50, 200) - require.NoError(t, err, "Error registering log trigger for log emitter") - } - - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") - - // Make sure that all nodes have expected filters registered before starting to emit events - expectedFilters := getExpectedFilters(logEmitters, cfg) - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { - nodeName := testEnv.ClCluster.Nodes[i].ContainerName - l.Info().Str("Node name", nodeName).Msg("Fetching filters from log poller's DB") - - hasFilters, err := nodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) - if err != nil { - l.Warn().Err(err).Msg("Error checking if node has expected filters. Retrying...") - return - } - - g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") - } - }, "30s", "1s").Should(gomega.Succeed()) - l.Info().Msg("All nodes have expected filters registered") - l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") - - // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - startBlock := int64(sb) - - l.Info().Msg("STARTING EVENT EMISSION") - startTime := time.Now() - - // Start chaos experimnents by randomly pausing random containers (Chainlink nodes or their DBs) - chaosDoneCh := make(chan error, 1) - go func() { - executeChaosExperiment(l, testEnv, cfg, chaosDoneCh) - }() - - totalLogsEmitted, err := executeGenerator(t, cfg, logEmitters) - endTime := time.Now() - require.NoError(t, err, "Error executing event generator") - - expectedLogsEmitted := getExpectedLogCount(cfg) - duration := int(endTime.Sub(startTime).Seconds()) - l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") - - // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - - endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) - require.NoError(t, err, "Error getting end block to wait for") - - l.Info().Msg("Waiting before proceeding with test until all chaos experiments finish") - chaosError := <-chaosDoneCh - require.NoError(t, chaosError, "Error encountered during chaos experiment") - - // Wait until last block in which events were emitted has been finalised - // how long should we wait here until all logs are processed? wait for block X to be processed by all nodes? - waitDuration := "15m" - l.Warn().Str("Duration", waitDuration).Msg("Waiting for logs to be processed by all nodes and for chain to advance beyond finality") - - gom.Eventually(func(g gomega.Gomega) { - hasAdvanced, err := chainHasFinalisedEndBlock(l, testEnv.EVMClient, endBlock) - if err != nil { - l.Warn().Err(err).Msg("Error checking if chain has advanced beyond finality. Retrying...") - } - g.Expect(hasAdvanced).To(gomega.BeTrue(), "Chain has not advanced beyond finality") - }, waitDuration, "30s").Should(gomega.Succeed()) - - l.Warn().Str("Duration", "1m").Msg("Waiting for all CL nodes to have end block finalised") - gom.Eventually(func(g gomega.Gomega) { - hasFinalised, err := logPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) - if err != nil { - l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") - } - g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") - }, "1m", "30s").Should(gomega.Succeed()) - - gom.Eventually(func(g gomega.Gomega) { - logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), totalLogsEmitted, expectedFilters, l, coreLogger, testEnv.ClCluster) - if err != nil { - l.Warn().Err(err).Msg("Error checking if CL nodes have expected log count. Retrying...") - } - g.Expect(logCountMatches).To(gomega.BeTrue(), "Not all CL nodes have expected log count") - }, waitDuration, "5s").Should(gomega.Succeed()) - - // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has - logConsistencyWaitDuration := "1m" - l.Warn().Str("Duration", logConsistencyWaitDuration).Msg("Waiting for CL nodes to have all the logs that EVM node has") - - gom.Eventually(func(g gomega.Gomega) { - missingLogs, err := getMissingLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, testEnv.ClCluster, l, coreLogger, cfg) - if err != nil { - l.Warn().Err(err).Msg("Error getting missing logs. Retrying...") - } - - if !missingLogs.IsEmpty() { - printMissingLogsByType(missingLogs, l, cfg) - } - g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") - }, logConsistencyWaitDuration, "5s").Should(gomega.Succeed()) -} - -func ExecuteLogPollerReplay(t *testing.T, cfg *Config, consistencyTimeout string) { - l := logging.GetTestLogger(t) - coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ - - if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { - l.Warn().Msg("No events to emit specified, using all events from log emitter contract") - for _, event := range EmitterABI.Events { - cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) - } - } - - l.Info().Msg("Starting replay log poller test") - - var ( - err error - upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) - ) - - // we set blockBackfillDepth to 0, to make sure nothing will be backfilled and won't interfere with our test - chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( - t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(1000*time.Millisecond), cfg.General.UseFinalityTag) - - _, upkeepIDs := actions.DeployConsumers( - t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, - upKeepsNeeded, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - true, - false, - ) - - // Deploy Log Emitter contracts - logEmitters := make([]*contracts.LogEmitter, 0) - for i := 0; i < cfg.General.Contracts; i++ { - logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() - logEmitters = append(logEmitters, &logEmitter) - require.NoError(t, err, "Error deploying log emitter contract") - l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") - time.Sleep(200 * time.Millisecond) - } - - //wait for contracts to be uploaded to chain, TODO: could make this wait fluent - time.Sleep(5 * time.Second) - - // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - startBlock := int64(sb) - - l.Info().Msg("STARTING EVENT EMISSION") - startTime := time.Now() - totalLogsEmitted, err := executeGenerator(t, cfg, logEmitters) - endTime := time.Now() - require.NoError(t, err, "Error executing event generator") - expectedLogsEmitted := getExpectedLogCount(cfg) - duration := int(endTime.Sub(startTime).Seconds()) - l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") - - // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - - endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) - require.NoError(t, err, "Error getting end block to wait for") - - // Lets make sure no logs are in DB yet - expectedFilters := getExpectedFilters(logEmitters, cfg) - logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), 0, expectedFilters, l, coreLogger, testEnv.ClCluster) - require.NoError(t, err, "Error checking if CL nodes have expected log count") - require.True(t, logCountMatches, "Some CL nodes already had logs in DB") - l.Info().Msg("No logs were saved by CL nodes yet, as expected. Proceeding.") - - // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) - // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) - for i := 0; i < len(upkeepIDs); i++ { - emitterAddress := (*logEmitters[i%cfg.General.Contracts]).Address() - upkeepID := upkeepIDs[i] - topicId := cfg.General.EventsToEmit[i%len(cfg.General.EventsToEmit)].ID - - l.Info().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") - err = registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) - require.NoError(t, err, "Error registering log trigger for log emitter") - } - - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") - - // Make sure that all nodes have expected filters registered before starting to emit events - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { - nodeName := testEnv.ClCluster.Nodes[i].ContainerName - l.Info().Str("Node name", nodeName).Msg("Fetching filters from log poller's DB") - - hasFilters, err := nodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) - if err != nil { - l.Warn().Err(err).Msg("Error checking if node has expected filters. Retrying...") - return - } - - g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") - } - }, "30s", "1s").Should(gomega.Succeed()) - l.Info().Msg("All nodes have expected filters registered") - l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") - - l.Warn().Str("Duration", "1m").Msg("Waiting for all CL nodes to have end block finalised") - gom.Eventually(func(g gomega.Gomega) { - hasFinalised, err := logPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) - if err != nil { - l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") - } - g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") - }, "1m", "30s").Should(gomega.Succeed()) - - // Trigger replay - l.Info().Msg("Triggering log poller's replay") - for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { - nodeName := testEnv.ClCluster.Nodes[i].ContainerName - response, _, err := testEnv.ClCluster.Nodes[i].API.ReplayLogPollerFromBlock(startBlock, testEnv.EVMClient.GetChainID().Int64()) - require.NoError(t, err, "Error triggering log poller's replay on node %s", nodeName) - require.Equal(t, "Replay started", response.Data.Attributes.Message, "Unexpected response message from log poller's replay") - } - - l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for replay logs to be processed by all nodes") - - gom.Eventually(func(g gomega.Gomega) { - logCountMatches, err := clNodesHaveExpectedLogCount(startBlock, endBlock, testEnv.EVMClient.GetChainID(), totalLogsEmitted, expectedFilters, l, coreLogger, testEnv.ClCluster) - if err != nil { - l.Warn().Err(err).Msg("Error checking if CL nodes have expected log count. Retrying...") - } - g.Expect(logCountMatches).To(gomega.BeTrue(), "Not all CL nodes have expected log count") - }, consistencyTimeout, "30s").Should(gomega.Succeed()) - - // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has - l.Warn().Str("Duration", consistencyTimeout).Msg("Waiting for CL nodes to have all the logs that EVM node has") - - gom.Eventually(func(g gomega.Gomega) { - missingLogs, err := getMissingLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, testEnv.ClCluster, l, coreLogger, cfg) - if err != nil { - l.Warn().Err(err).Msg("Error getting missing logs. Retrying...") - } - - if !missingLogs.IsEmpty() { - printMissingLogsByType(missingLogs, l, cfg) - } - g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") - }, consistencyTimeout, "10s").Should(gomega.Succeed()) -} - -type FinalityBlockFn = func(chainId int64, endBlock int64) (int64, error) - -func ExecuteCILogPollerTest(t *testing.T, cfg *Config) { - l := logging.GetTestLogger(t) - coreLogger := core_logger.TestLogger(t) //needed by ORM ¯\_(ツ)_/¯ - - if cfg.General.EventsToEmit == nil || len(cfg.General.EventsToEmit) == 0 { - l.Warn().Msg("No events to emit specified, using all events from log emitter contract") - for _, event := range EmitterABI.Events { - cfg.General.EventsToEmit = append(cfg.General.EventsToEmit, event) - } - } - - l.Info().Msg("Starting CI log poller test") - - var ( - err error - upKeepsNeeded = cfg.General.Contracts * len(cfg.General.EventsToEmit) - ) - - chainClient, _, contractDeployer, linkToken, registry, registrar, testEnv := setupLogPollerTestDocker( - t, ethereum.RegistryVersion_2_1, defaultOCRRegistryConfig, upKeepsNeeded, time.Duration(1000*time.Millisecond), cfg.General.UseFinalityTag, - ) - - _, upkeepIDs := actions.DeployConsumers( - t, - registry, - registrar, - linkToken, - contractDeployer, - chainClient, - upKeepsNeeded, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - true, - false, - ) - - // Deploy Log Emitter contracts - logEmitters := make([]*contracts.LogEmitter, 0) - for i := 0; i < cfg.General.Contracts; i++ { - logEmitter, err := testEnv.ContractDeployer.DeployLogEmitterContract() - logEmitters = append(logEmitters, &logEmitter) - require.NoError(t, err, "Error deploying log emitter contract") - l.Info().Str("Contract address", logEmitter.Address().Hex()).Msg("Log emitter contract deployed") - time.Sleep(200 * time.Millisecond) - } - - // Register log triggered upkeep for each combination of log emitter contract and event signature (topic) - // We need to register a separate upkeep for each event signature, because log trigger doesn't support multiple topics (even if log poller does) - for i := 0; i < len(upkeepIDs); i++ { - emitterAddress := (*logEmitters[i%cfg.General.Contracts]).Address() - upkeepID := upkeepIDs[i] - topicId := cfg.General.EventsToEmit[i%len(cfg.General.EventsToEmit)].ID - - l.Info().Int("Upkeep id", int(upkeepID.Int64())).Str("Emitter address", emitterAddress.String()).Str("Topic", topicId.Hex()).Msg("Registering log trigger for log emitter") - err = registerSingleTopicFilter(registry, upkeepID, emitterAddress, topicId) - randomWait(50, 200) - require.NoError(t, err, "Error registering log trigger for log emitter") - } - - err = chainClient.WaitForEvents() - require.NoError(t, err, "Error encountered when waiting for setting trigger config for upkeeps") - - // Make sure that all nodes have expected filters registered before starting to emit events - expectedFilters := getExpectedFilters(logEmitters, cfg) - gom := gomega.NewGomegaWithT(t) - gom.Eventually(func(g gomega.Gomega) { - for i := 1; i < len(testEnv.ClCluster.Nodes); i++ { - nodeName := testEnv.ClCluster.Nodes[i].ContainerName - l.Info().Str("Node name", nodeName).Msg("Fetching filters from log poller's DB") - - hasFilters, err := nodeHasExpectedFilters(expectedFilters, coreLogger, testEnv.EVMClient.GetChainID(), testEnv.ClCluster.Nodes[i].PostgresDb) - if err != nil { - l.Warn().Err(err).Msg("Error checking if node has expected filters. Retrying...") - return - } - - g.Expect(hasFilters).To(gomega.BeTrue(), "Not all expected filters were found in the DB") - } - }, "1m", "1s").Should(gomega.Succeed()) - l.Info().Msg("All nodes have expected filters registered") - l.Info().Int("Count", len(expectedFilters)).Msg("Expected filters count") - - // Save block number before starting to emit events, so that we can later use it when querying logs - sb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - startBlock := int64(sb) - - l.Info().Msg("STARTING EVENT EMISSION") - startTime := time.Now() - - // Start chaos experimnents by randomly pausing random containers (Chainlink nodes or their DBs) - chaosDoneCh := make(chan error, 1) - go func() { - executeChaosExperiment(l, testEnv, cfg, chaosDoneCh) - }() - - totalLogsEmitted, err := executeGenerator(t, cfg, logEmitters) - endTime := time.Now() - require.NoError(t, err, "Error executing event generator") - - expectedLogsEmitted := getExpectedLogCount(cfg) - duration := int(endTime.Sub(startTime).Seconds()) - l.Info().Int("Total logs emitted", totalLogsEmitted).Int64("Expected total logs emitted", expectedLogsEmitted).Str("Duration", fmt.Sprintf("%d sec", duration)).Str("LPS", fmt.Sprintf("%d/sec", totalLogsEmitted/duration)).Msg("FINISHED EVENT EMISSION") - - // Save block number after finishing to emit events, so that we can later use it when querying logs - eb, err := testEnv.EVMClient.LatestBlockNumber(testcontext.Get(t)) - require.NoError(t, err, "Error getting latest block number") - - endBlock, err := GetEndBlockToWaitFor(int64(eb), testEnv.EVMClient.GetChainID().Int64(), cfg) - require.NoError(t, err, "Error getting end block to wait for") - - l.Info().Msg("Waiting before proceeding with test until all chaos experiments finish") - chaosError := <-chaosDoneCh - require.NoError(t, chaosError, "Error encountered during chaos experiment") - - // Wait until last block in which events were emitted has been finalised (with buffer) - waitDuration := "45m" - l.Warn().Str("Duration", waitDuration).Msg("Waiting for chain to advance beyond finality") - - gom.Eventually(func(g gomega.Gomega) { - hasAdvanced, err := chainHasFinalisedEndBlock(l, testEnv.EVMClient, endBlock) - if err != nil { - l.Warn().Err(err).Msg("Error checking if chain has advanced beyond finality. Retrying...") - } - g.Expect(hasAdvanced).To(gomega.BeTrue(), "Chain has not advanced beyond finality") - }, waitDuration, "30s").Should(gomega.Succeed()) - - l.Warn().Str("Duration", waitDuration).Msg("Waiting for all CL nodes to have end block finalised") - gom.Eventually(func(g gomega.Gomega) { - hasFinalised, err := logPollerHasFinalisedEndBlock(endBlock, testEnv.EVMClient.GetChainID(), l, coreLogger, testEnv.ClCluster) - if err != nil { - l.Warn().Err(err).Msg("Error checking if nodes have finalised end block. Retrying...") - } - g.Expect(hasFinalised).To(gomega.BeTrue(), "Some nodes have not finalised end block") - }, waitDuration, "30s").Should(gomega.Succeed()) - - // Wait until all CL nodes have exactly the same logs emitted by test contracts as the EVM node has - logConsistencyWaitDuration := "10m" - l.Warn().Str("Duration", logConsistencyWaitDuration).Msg("Waiting for CL nodes to have all the logs that EVM node has") - - gom.Eventually(func(g gomega.Gomega) { - missingLogs, err := getMissingLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, testEnv.ClCluster, l, coreLogger, cfg) - if err != nil { - l.Warn().Err(err).Msg("Error getting missing logs. Retrying...") - } - - if !missingLogs.IsEmpty() { - printMissingLogsByType(missingLogs, l, cfg) - } - g.Expect(missingLogs.IsEmpty()).To(gomega.BeTrue(), "Some CL nodes were missing logs") - }, logConsistencyWaitDuration, "20s").Should(gomega.Succeed()) - - evmLogs, _ := getEVMLogs(startBlock, endBlock, logEmitters, testEnv.EVMClient, l, cfg) - - if totalLogsEmitted != len(evmLogs) { - l.Warn().Int("Total logs emitted", totalLogsEmitted).Int("Total logs in EVM", len(evmLogs)).Msg("Test passed, but total logs emitted does not match total logs in EVM") - } -} diff --git a/integration-tests/utils/common.go b/integration-tests/utils/common.go index 34a40e396d2..cc77e4cc3b0 100644 --- a/integration-tests/utils/common.go +++ b/integration-tests/utils/common.go @@ -4,11 +4,11 @@ import ( "math/big" "net" - "github.com/smartcontractkit/chainlink/v2/core/store/models" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" ) -func MustURL(s string) *models.URL { - var u models.URL +func MustURL(s string) *commonconfig.URL { + var u commonconfig.URL if err := u.UnmarshalText([]byte(s)); err != nil { panic(err) } diff --git a/internal/testdb/testdb.go b/internal/testdb/testdb.go new file mode 100644 index 00000000000..9b531166113 --- /dev/null +++ b/internal/testdb/testdb.go @@ -0,0 +1,56 @@ +package testdb + +import ( + "database/sql" + "errors" + "fmt" + "net/url" + + "github.com/smartcontractkit/chainlink/v2/core/store/dialects" +) + +const ( + // PristineDBName is a clean copy of test DB with migrations. + PristineDBName = "chainlink_test_pristine" + // TestDBNamePrefix is a common prefix that will be auto-removed by the dangling DB cleanup process. + TestDBNamePrefix = "chainlink_test_" +) + +// CreateOrReplace creates a database named with a common prefix and the given suffix, and returns the URL. +// If the database already exists, it will be dropped and re-created. +// If withTemplate is true, the pristine DB will be used as a template. +func CreateOrReplace(parsed url.URL, suffix string, withTemplate bool) (string, error) { + if parsed.Path == "" { + return "", errors.New("path missing from database URL") + } + + // Match the naming schema that our dangling DB cleanup methods expect + dbname := TestDBNamePrefix + suffix + if l := len(dbname); l > 63 { + return "", fmt.Errorf("dbname %v too long (%d), max is 63 bytes. Try a shorter suffix", dbname, l) + } + // Cannot drop test database if we are connected to it, so we must connect + // to a different one. 'postgres' should be present on all postgres installations + parsed.Path = "/postgres" + db, err := sql.Open(string(dialects.Postgres), parsed.String()) + if err != nil { + return "", fmt.Errorf("in order to drop the test database, we need to connect to a separate database"+ + " called 'postgres'. But we are unable to open 'postgres' database: %+v\n", err) + } + defer db.Close() + + _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", dbname)) + if err != nil { + return "", fmt.Errorf("unable to drop postgres migrations test database: %v", err) + } + if withTemplate { + _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s WITH TEMPLATE %s", dbname, PristineDBName)) + } else { + _, err = db.Exec(fmt.Sprintf("CREATE DATABASE %s", dbname)) + } + if err != nil { + return "", fmt.Errorf("unable to create postgres test database with name '%s': %v", dbname, err) + } + parsed.Path = fmt.Sprintf("/%s", dbname) + return parsed.String(), nil +} diff --git a/lintconf.yaml b/lintconf.yaml new file mode 100644 index 00000000000..ff37371d476 --- /dev/null +++ b/lintconf.yaml @@ -0,0 +1,46 @@ +--- +# Copied from: +# https://redhat-cop.github.io/ci/linting-testing-helm-charts.html +# with `min-spaces-from-content` changed to be compatible with prettier. +rules: + braces: + min-spaces-inside: 0 + max-spaces-inside: 0 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + brackets: + min-spaces-inside: 0 + max-spaces-inside: 0 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + colons: + max-spaces-before: 0 + max-spaces-after: 1 + commas: + max-spaces-before: 0 + min-spaces-after: 1 + max-spaces-after: 1 + comments: + require-starting-space: true + min-spaces-from-content: 1 + document-end: disable + document-start: disable # No --- to start a file + empty-lines: + max: 2 + max-start: 0 + max-end: 0 + hyphens: + max-spaces-after: 1 + indentation: + spaces: consistent + indent-sequences: whatever # - list indentation will handle both indentation and without + check-multi-line-strings: false + key-duplicates: enable + line-length: disable # Lines can be any length + new-line-at-end-of-file: disable + new-lines: + type: unix + trailing-spaces: enable + truthy: + level: warning + diff --git a/main.go b/main.go index 2a224c96d29..7e262f85f28 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core" ) +//go:generate make modgraph func main() { os.Exit(core.Main()) } diff --git a/main_test.go b/main_test.go index 032ec4718a2..15b17e32654 100644 --- a/main_test.go +++ b/main_test.go @@ -1,17 +1,41 @@ package main import ( + "fmt" + "net/url" "os" + "path/filepath" + "strconv" + "strings" "testing" + "github.com/google/uuid" + "github.com/hashicorp/consul/sdk/freeport" "github.com/rogpeppe/go-internal/testscript" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/v2/core" + "github.com/smartcontractkit/chainlink/v2/core/config/env" "github.com/smartcontractkit/chainlink/v2/core/static" + "github.com/smartcontractkit/chainlink/v2/internal/testdb" "github.com/smartcontractkit/chainlink/v2/tools/txtar" ) +// special files can be included to allocate additional test resources +const ( + // testDBName triggers initializing of a test database. + // The URL will be set as the value of an env var named by the file. + // + // -- testdb.txt -- + // CL_DATABASE_URL + testDBName = "testdb.txt" + // testPortName triggers injection of a free port as the value of an env var named by the file. + // + // -- testport.txt -- + // PORT + testPortName = "testport.txt" +) + func TestMain(m *testing.M) { os.Exit(testscript.RunMain(m, map[string]func() int{ "chainlink": core.Main, @@ -22,11 +46,14 @@ func TestScripts(t *testing.T) { t.Parallel() visitor := txtar.NewDirVisitor("testdata/scripts", txtar.Recurse, func(path string) error { - t.Run(path, func(t *testing.T) { + t.Run(strings.TrimPrefix(path, "testdata/scripts/"), func(t *testing.T) { t.Parallel() + testscript.Run(t, testscript.Params{ - Dir: path, - Setup: commonEnv, + Dir: path, + Setup: commonEnv, + ContinueOnError: true, + //UpdateScripts: true, // uncomment to update golden files }) }) return nil @@ -35,9 +62,62 @@ func TestScripts(t *testing.T) { require.NoError(t, visitor.Walk()) } -func commonEnv(env *testscript.Env) error { - env.Setenv("HOME", "$WORK/home") - env.Setenv("VERSION", static.Version) - env.Setenv("COMMIT_SHA", static.Sha) +func commonEnv(te *testscript.Env) error { + te.Setenv("HOME", "$WORK/home") + te.Setenv("VERSION", static.Version) + te.Setenv("COMMIT_SHA", static.Sha) + + b, err := os.ReadFile(filepath.Join(te.WorkDir, testPortName)) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to read file %s: %w", testPortName, err) + } else if err == nil { + envVarName := strings.TrimSpace(string(b)) + te.T().Log("test port requested:", envVarName) + + port, ret, err2 := takeFreePort() + if err2 != nil { + return err2 + } + te.Defer(ret) + + te.Setenv(envVarName, strconv.Itoa(port)) + } + + b, err = os.ReadFile(filepath.Join(te.WorkDir, testDBName)) + if err != nil && !os.IsNotExist(err) { + return fmt.Errorf("failed to read file %s: %w", testDBName, err) + } else if err == nil { + envVarName := strings.TrimSpace(string(b)) + te.T().Log("test database requested:", envVarName) + + u2, err2 := initDB() + if err2 != nil { + return err2 + } + + te.Setenv(envVarName, u2) + } return nil } + +func takeFreePort() (int, func(), error) { + ports, err := freeport.Take(1) + if err != nil { + return 0, nil, fmt.Errorf("failed to get free port: %w", err) + } + return ports[0], func() { freeport.Return(ports) }, nil +} + +func initDB() (string, error) { + u, err := url.Parse(string(env.DatabaseURL.Get())) + if err != nil { + return "", fmt.Errorf("failed to parse url: %w", err) + } + + name := strings.ReplaceAll(uuid.NewString(), "-", "_") + "_test" + u2, err := testdb.CreateOrReplace(*u, name, true) + if err != nil { + return "", fmt.Errorf("failed to create DB: %w", err) + } + return u2, nil +} diff --git a/operator_ui/TAG b/operator_ui/TAG index 3b63cc3addb..f5e57863f97 100644 --- a/operator_ui/TAG +++ b/operator_ui/TAG @@ -1 +1 @@ -v0.8.0-2f868c3 +v0.8.0-8da47c3 diff --git a/plugins/utils.go b/plugins/cmd.go similarity index 73% rename from plugins/utils.go rename to plugins/cmd.go index 5e5e4142e86..9a312c53882 100644 --- a/plugins/utils.go +++ b/plugins/cmd.go @@ -7,8 +7,9 @@ import ( // CmdConfig is configuration used to register the LOOP and generate an exec type CmdConfig struct { - ID string // unique string used by the node to track the LOOP. typically supplied by the loop logger name - Cmd string // string value of executable to exec + ID string // unique string used by the node to track the LOOP. typically supplied by the loop logger name + Cmd string // string value of executable to exec + Env []string // environment variables as described in [exec.Cmd.Env] } // NewCmdFactory is helper to ensure synchronization between the loop registry and os cmd to exec the LOOP @@ -19,6 +20,7 @@ func NewCmdFactory(register func(id string) (*RegisteredLoop, error), lcfg CmdCo } return func() *exec.Cmd { cmd := exec.Command(lcfg.Cmd) //#nosec G204 -- we control the value of the cmd so the lint/sec error is a false positive + cmd.Env = append(cmd.Env, lcfg.Env...) cmd.Env = append(cmd.Env, registeredLoop.EnvCfg.AsCmdEnv()...) return cmd }, nil diff --git a/plugins/cmd_test.go b/plugins/cmd_test.go new file mode 100644 index 00000000000..8068977314a --- /dev/null +++ b/plugins/cmd_test.go @@ -0,0 +1,51 @@ +package plugins + +import ( + "fmt" + "strings" + "testing" + + "github.com/smartcontractkit/chainlink-common/pkg/loop" +) + +func TestNewCmdFactory_RegisterSuccess(t *testing.T) { + mockRegister := func(id string) (*RegisteredLoop, error) { + return &RegisteredLoop{EnvCfg: loop.EnvConfig{}}, nil + } + + cmdConfig := CmdConfig{ + ID: "test-loop", + Cmd: "echo", + Env: []string{"TEST_ENV=1"}, + } + + cmdFactory, err := NewCmdFactory(mockRegister, cmdConfig) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + cmd := cmdFactory() + if cmd.Args[0] != "echo" { + t.Errorf("Expected command 'echo', got %s", cmd.Args[0]) + } +} + +func TestNewCmdFactory_RegisterFail(t *testing.T) { + mockRegister := func(id string) (*RegisteredLoop, error) { + return nil, fmt.Errorf("registration failed") + } + + cmdConfig := CmdConfig{ + ID: "test-loop", + Cmd: "echo", + Env: []string{"TEST_ENV=1"}, + } + + _, err := NewCmdFactory(mockRegister, cmdConfig) + if err == nil { + t.Fatal("Expected error, got nil") + } + if !strings.Contains(err.Error(), "failed to register") { + t.Errorf("Unexpected error message: %v", err) + } +} diff --git a/plugins/env.go b/plugins/env.go new file mode 100644 index 00000000000..016a4e862d8 --- /dev/null +++ b/plugins/env.go @@ -0,0 +1,31 @@ +package plugins + +import ( + "os" + + "github.com/hashicorp/go-envparse" +) + +// ParseEnvFile returns a slice of key/value pairs parsed from the file at filepath. +// As a special case, empty filepath returns nil without error. +func ParseEnvFile(filepath string) ([]string, error) { + if filepath == "" { + return nil, nil + } + f, err := os.Open(filepath) + if err != nil { + return nil, err + } + defer func() { + _ = f.Close() + }() + m, err := envparse.Parse(f) + if err != nil { + return nil, err + } + r := make([]string, 0, len(m)) + for k, v := range m { + r = append(r, k+"="+v) + } + return r, nil +} diff --git a/plugins/env_test.go b/plugins/env_test.go new file mode 100644 index 00000000000..6dd171b6cc0 --- /dev/null +++ b/plugins/env_test.go @@ -0,0 +1,25 @@ +package plugins + +import ( + _ "embed" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseEnvFile(t *testing.T) { + t.Run("valid", func(t *testing.T) { + got, err := ParseEnvFile("testdata/valid.env") + require.NoError(t, err) + require.Equal(t, []string{"GOMEMLIMIT=1MiB"}, got) + }) + t.Run("invalid", func(t *testing.T) { + _, err := ParseEnvFile("testdata/invalid.env") + require.Error(t, err) + }) + t.Run("missing", func(t *testing.T) { + _, err := ParseEnvFile("testdata/missing.env") + require.ErrorIs(t, err, os.ErrNotExist) + }) +} diff --git a/plugins/loop_registry.go b/plugins/loop_registry.go index 7a5274803d6..a2fcd8ef379 100644 --- a/plugins/loop_registry.go +++ b/plugins/loop_registry.go @@ -2,19 +2,18 @@ package plugins import ( "errors" + "fmt" "sort" "sync" + "github.com/hashicorp/consul/sdk/freeport" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/config" ) -const ( - pluginDefaultPort = 2112 -) - var ErrExists = errors.New("plugin already registered") type RegisteredLoop struct { @@ -49,8 +48,14 @@ func (m *LoopRegistry) Register(id string) (*RegisteredLoop, error) { if _, exists := m.registry[id]; exists { return nil, ErrExists } - nextPort := pluginDefaultPort + len(m.registry) - envCfg := loop.EnvConfig{PrometheusPort: nextPort} + ports, err := freeport.Take(1) + if err != nil { + return nil, fmt.Errorf("failed to get free port: %v", err) + } + if len(ports) != 1 { + return nil, fmt.Errorf("failed to get free port: no ports returned") + } + envCfg := loop.EnvConfig{PrometheusPort: ports[0]} if m.cfgTracing != nil { envCfg.TracingEnabled = m.cfgTracing.Enabled() diff --git a/plugins/medianpoc/plugin_test.go b/plugins/medianpoc/plugin_test.go index 0d6c0360e43..d4470eef70a 100644 --- a/plugins/medianpoc/plugin_test.go +++ b/plugins/medianpoc/plugin_test.go @@ -7,12 +7,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -72,6 +72,14 @@ func (p provider) OnchainConfigCodec() median.OnchainConfigCodec { return mockOnchainConfigCodec{} } +func (p provider) ChainReader() types.ChainReader { + return nil +} + +func (p provider) Codec() types.Codec { + return nil +} + func TestNewPlugin(t *testing.T) { lggr := logger.TestLogger(t) p := NewPlugin(lggr) diff --git a/plugins/config.go b/plugins/registrar.go similarity index 77% rename from plugins/config.go rename to plugins/registrar.go index 01574d82099..90300b738b6 100644 --- a/plugins/config.go +++ b/plugins/registrar.go @@ -8,7 +8,7 @@ import ( // RegistrarConfig generates contains static configuration inher type RegistrarConfig interface { - RegisterLOOP(loopId string, cmdName string) (func() *exec.Cmd, loop.GRPCOpts, error) + RegisterLOOP(config CmdConfig) (func() *exec.Cmd, loop.GRPCOpts, error) } type registarConfig struct { @@ -27,11 +27,8 @@ func NewRegistrarConfig(grpcOpts loop.GRPCOpts, loopRegistrationFn func(loopId s } // RegisterLOOP calls the configured loopRegistrationFn. The loopRegistrationFn must act as a global registry for LOOPs and must be idempotent. -func (pc *registarConfig) RegisterLOOP(loopID string, cmdName string) (func() *exec.Cmd, loop.GRPCOpts, error) { - cmdFn, err := NewCmdFactory(pc.loopRegistrationFn, CmdConfig{ - ID: loopID, - Cmd: cmdName, - }) +func (pc *registarConfig) RegisterLOOP(cfg CmdConfig) (func() *exec.Cmd, loop.GRPCOpts, error) { + cmdFn, err := NewCmdFactory(pc.loopRegistrationFn, cfg) if err != nil { return nil, loop.GRPCOpts{}, err } diff --git a/plugins/testdata/invalid.env b/plugins/testdata/invalid.env new file mode 100644 index 00000000000..b2f2407bccf --- /dev/null +++ b/plugins/testdata/invalid.env @@ -0,0 +1,2 @@ +FOO BAR +Baz: "Value" diff --git a/plugins/testdata/valid.env b/plugins/testdata/valid.env new file mode 100644 index 00000000000..5a73d037c60 --- /dev/null +++ b/plugins/testdata/valid.env @@ -0,0 +1 @@ +GOMEMLIMIT=1MiB diff --git a/revive.toml b/revive.toml deleted file mode 100644 index daa62cd5487..00000000000 --- a/revive.toml +++ /dev/null @@ -1,53 +0,0 @@ -ignoreGeneratedHeader = false -severity = "warning" -confidence = 0.8 -errorCode = 0 -warningCode = 0 - -[rule.blank-imports] -[rule.context-as-argument] -[rule.context-keys-type] -[rule.dot-imports] -[rule.error-return] -[rule.error-strings] -[rule.error-naming] -[rule.exported] -Disabled = true -[rule.if-return] -[rule.increment-decrement] -[rule.var-naming] -Disabled = true -[rule.var-declaration] -[rule.package-comments] -[rule.range] -[rule.receiver-naming] -[rule.time-naming] -[rule.unexported-return] -Disabled = true -[rule.indent-error-flow] -[rule.errorf] -[rule.empty-block] -[rule.superfluous-else] -[rule.unused-parameter] -Disabled = true -[rule.unreachable-code] -[rule.redefines-builtin-id] -[rule.waitgroup-by-value] -[rule.unconditional-recursion] -[rule.struct-tag] -# [rule.string-format] -[rule.string-of-int] -# [rule.range-val-address] -[rule.range-val-in-closure] -[rule.modifies-value-receiver] -[rule.modifies-parameter] -[rule.identical-branches] -[rule.get-return] -# [rule.flag-parameter] -# [rule.early-return] -[rule.defer] -[rule.constant-logical-expr] -# [rule.confusing-naming] -# [rule.confusing-results] -[rule.bool-literal-in-expr] -[rule.atomic] diff --git a/sonar-project.properties b/sonar-project.properties index c40b5f361e1..6ffaba8b19b 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,9 +3,9 @@ sonar.sources=. sonar.python.version=3.8 # Full exclusions from the static analysis -sonar.exclusions=**/node_modules/**/*,**/mocks/**/*, **/testdata/**/*, **/contracts/typechain/**/*, **/contracts/artifacts/**/*, **/contracts/cache/**/*, **/contracts/scripts/**/*, **/generated/**/*, **/fixtures/**/*, **/docs/**/*, **/tools/**/*, **/*.pb.go, **/*report.xml, **/*.config.ts, **/*.txt, **/*.abi, **/*.bin, **/*_codecgen.go +sonar.exclusions=**/node_modules/**/*,**/mocks/**/*, **/testdata/**/*, **/contracts/typechain/**/*, **/contracts/artifacts/**/*, **/contracts/cache/**/*, **/contracts/scripts/**/*, **/generated/**/*, **/fixtures/**/*, **/docs/**/*, **/tools/**/*, **/*.pb.go, **/*report.xml, **/*.config.ts, **/*.txt, **/*.abi, **/*.bin, **/*_codecgen.go, core/services/relay/evm/types/*_gen.go, core/services/relay/evm/types/gen/main.go, core/services/relay/evm/testfiles/*, **/core/web/assets**, core/scripts/chaincli/handler/debug.go # Coverage exclusions -sonar.coverage.exclusions=**/*.test.ts, **/*_test.go, **/contracts/test/**/*, **/contracts/**/tests/**/*, **/core/**/testutils/**/*, **/core/**/mocks/**/*, **/core/**/cltest/**/*, **/integration-tests/**/*, **/generated/**/*, **/core/scripts**/* , **/*.pb.go, ./plugins/**/*, **/main.go, **/0195_add_not_null_to_evm_chain_id_in_job_specs.go +sonar.coverage.exclusions=**/*.test.ts, **/*_test.go, **/contracts/test/**/*, **/contracts/**/tests/**/*, **/core/**/testutils/**/*, **/core/**/mocks/**/*, **/core/**/cltest/**/*, **/integration-tests/**/*, **/generated/**/*, **/core/scripts**/* , **/*.pb.go, ./plugins/**/*, **/main.go, **/0195_add_not_null_to_evm_chain_id_in_job_specs.go, **/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams/streams.go # Duplication exclusions sonar.cpd.exclusions=**/contracts/**/*.sol, **/config.go, /core/services/ocr2/plugins/ocr2keeper/evm*/* diff --git a/test.txt b/test.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/scripts/health/default.txtar b/testdata/scripts/health/default.txtar new file mode 100644 index 00000000000..15be9da1fe6 --- /dev/null +++ b/testdata/scripts/health/default.txtar @@ -0,0 +1,119 @@ +# start node +exec sh -c 'eval "echo \"$(cat config.toml.tmpl)\" > config.toml"' +exec chainlink node -c config.toml start -p password -a creds & + +# initialize client +env NODEURL=http://localhost:$PORT +exec curl --retry 10 --retry-max-time 60 --retry-connrefused $NODEURL +exec chainlink --remote-node-url $NODEURL admin login -file creds --bypass-version-check + +exec chainlink --remote-node-url $NODEURL health +cmp stdout out.txt + +exec chainlink --remote-node-url $NODEURL health -json +cp stdout compact.json +exec jq . compact.json +cmp stdout out.json + +-- testdb.txt -- +CL_DATABASE_URL +-- testport.txt -- +PORT + +-- password -- +T.tLHkcmwePT/p,]sYuntjwHKAsrhm#4eRs4LuKHwvHejWYAC2JP4M8HimwgmbaZ +-- creds -- +notreal@fakeemail.ch +fj293fbBnlQ!f9vNs + +-- config.toml.tmpl -- +[Webserver] +HTTPPort = $PORT + +-- out.txt -- +-JobSpawner +-Mailbox.Monitor +-Mercury.WSRPCPool +-Mercury.WSRPCPool.CacheSet +-PipelineORM +-PipelineRunner +-PromReporter +-TelemetryManager + +-- out.json -- +{ + "data": [ + { + "type": "checks", + "id": "JobSpawner", + "attributes": { + "name": "JobSpawner", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Mailbox.Monitor", + "attributes": { + "name": "Mailbox.Monitor", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Mercury.WSRPCPool", + "attributes": { + "name": "Mercury.WSRPCPool", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Mercury.WSRPCPool.CacheSet", + "attributes": { + "name": "Mercury.WSRPCPool.CacheSet", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PipelineORM", + "attributes": { + "name": "PipelineORM", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PipelineRunner", + "attributes": { + "name": "PipelineRunner", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PromReporter", + "attributes": { + "name": "PromReporter", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "TelemetryManager", + "attributes": { + "name": "TelemetryManager", + "status": "passing", + "output": "" + } + } + ] +} diff --git a/testdata/scripts/health/help.txtar b/testdata/scripts/health/help.txtar new file mode 100644 index 00000000000..07eb0509e73 --- /dev/null +++ b/testdata/scripts/health/help.txtar @@ -0,0 +1,13 @@ +exec chainlink health --help +cmp stdout out.txt + +-- out.txt -- +NAME: + chainlink health - Prints a health report + +USAGE: + chainlink health [command options] [arguments...] + +OPTIONS: + --json, -j json output + diff --git a/testdata/scripts/health/multi-chain.txtar b/testdata/scripts/health/multi-chain.txtar new file mode 100644 index 00000000000..6a6adb895cb --- /dev/null +++ b/testdata/scripts/health/multi-chain.txtar @@ -0,0 +1,299 @@ +# start node +exec sh -c 'eval "echo \"$(cat config.toml.tmpl)\" > config.toml"' +exec chainlink node -c config.toml start -p password -a creds & + +# initialize client +env NODEURL=http://localhost:$PORT +exec curl --retry 10 --retry-max-time 60 --retry-connrefused $NODEURL +exec chainlink --remote-node-url $NODEURL admin login -file creds --bypass-version-check + +exec chainlink --remote-node-url $NODEURL health +cmp stdout out.txt + +exec chainlink --remote-node-url $NODEURL health -json +cp stdout compact.json +exec jq . compact.json +cmp stdout out.json + +-- testdb.txt -- +CL_DATABASE_URL +-- testport.txt -- +PORT + +-- password -- +T.tLHkcmwePT/p,]sYuntjwHKAsrhm#4eRs4LuKHwvHejWYAC2JP4M8HimwgmbaZ +-- creds -- +notreal@fakeemail.ch +fj293fbBnlQ!f9vNs + +-- config.toml.tmpl -- +[Webserver] +HTTPPort = $PORT + +[[Cosmos]] +ChainID = 'Foo' + +[[Cosmos.Nodes]] +Name = 'primary' +TendermintURL = 'http://tender.mint' + +[[EVM]] +ChainID = '1' + +[[EVM.Nodes]] +Name = 'fake' +WSURL = 'wss://foo.bar/ws' +HTTPURL = 'https://foo.bar' + +[[Solana]] +ChainID = 'Bar' + +[[Solana.Nodes]] +Name = 'primary' +URL = 'http://solana.web' + +[[Starknet]] +ChainID = 'Baz' + +[[Starknet.Nodes]] +Name = 'primary' +URL = 'http://stark.node' + +-- out.txt -- +-Cosmos.Foo.Chain +-Cosmos.Foo.Txm +-EVM.1 +-EVM.1.BalanceMonitor +-EVM.1.HeadBroadcaster +-EVM.1.HeadTracker +!EVM.1.HeadTracker.HeadListener + Listener is not connected +-EVM.1.LogBroadcaster +-EVM.1.Txm +-EVM.1.Txm.BlockHistoryEstimator +-EVM.1.Txm.Broadcaster +-EVM.1.Txm.Confirmer +-EVM.1.Txm.WrappedEvmEstimator +-JobSpawner +-Mailbox.Monitor +-Mercury.WSRPCPool +-Mercury.WSRPCPool.CacheSet +-PipelineORM +-PipelineRunner +-PromReporter +-Solana.Bar +-StarkNet.Baz +-TelemetryManager + +-- out.json -- +{ + "data": [ + { + "type": "checks", + "id": "Cosmos.Foo.Chain", + "attributes": { + "name": "Cosmos.Foo.Chain", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Cosmos.Foo.Txm", + "attributes": { + "name": "Cosmos.Foo.Txm", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.1", + "attributes": { + "name": "EVM.1", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.1.BalanceMonitor", + "attributes": { + "name": "EVM.1.BalanceMonitor", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.1.HeadBroadcaster", + "attributes": { + "name": "EVM.1.HeadBroadcaster", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.1.HeadTracker", + "attributes": { + "name": "EVM.1.HeadTracker", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.1.HeadTracker.HeadListener", + "attributes": { + "name": "EVM.1.HeadTracker.HeadListener", + "status": "failing", + "output": "Listener is not connected" + } + }, + { + "type": "checks", + "id": "EVM.1.LogBroadcaster", + "attributes": { + "name": "EVM.1.LogBroadcaster", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.1.Txm", + "attributes": { + "name": "EVM.1.Txm", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.1.Txm.BlockHistoryEstimator", + "attributes": { + "name": "EVM.1.Txm.BlockHistoryEstimator", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.1.Txm.Broadcaster", + "attributes": { + "name": "EVM.1.Txm.Broadcaster", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.1.Txm.Confirmer", + "attributes": { + "name": "EVM.1.Txm.Confirmer", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "EVM.1.Txm.WrappedEvmEstimator", + "attributes": { + "name": "EVM.1.Txm.WrappedEvmEstimator", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "JobSpawner", + "attributes": { + "name": "JobSpawner", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Mailbox.Monitor", + "attributes": { + "name": "Mailbox.Monitor", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Mercury.WSRPCPool", + "attributes": { + "name": "Mercury.WSRPCPool", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Mercury.WSRPCPool.CacheSet", + "attributes": { + "name": "Mercury.WSRPCPool.CacheSet", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PipelineORM", + "attributes": { + "name": "PipelineORM", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PipelineRunner", + "attributes": { + "name": "PipelineRunner", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "PromReporter", + "attributes": { + "name": "PromReporter", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "Solana.Bar", + "attributes": { + "name": "Solana.Bar", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "StarkNet.Baz", + "attributes": { + "name": "StarkNet.Baz", + "status": "passing", + "output": "" + } + }, + { + "type": "checks", + "id": "TelemetryManager", + "attributes": { + "name": "TelemetryManager", + "status": "passing", + "output": "" + } + } + ] +} diff --git a/testdata/scripts/help.txtar b/testdata/scripts/help.txtar index 1484aceb5df..e4c19f3987d 100644 --- a/testdata/scripts/help.txtar +++ b/testdata/scripts/help.txtar @@ -17,6 +17,7 @@ COMMANDS: blocks Commands for managing blocks bridges Commands for Bridges communicating with External Adapters config Commands for the node's configuration + health Prints a health report jobs Commands for managing Jobs keys Commands for managing various types of keys used by the Chainlink node node, local Commands for admin actions that must be run locally diff --git a/testdata/scripts/keys/eth/create/help.txtar b/testdata/scripts/keys/eth/create/help.txtar new file mode 100644 index 00000000000..d089b220ae4 --- /dev/null +++ b/testdata/scripts/keys/eth/create/help.txtar @@ -0,0 +1,14 @@ +exec chainlink keys eth create --help +cmp stdout out.txt + +-- out.txt -- +NAME: + chainlink keys eth create - Create a key in the node's keystore alongside the existing key; to create an original key, just run the node + +USAGE: + chainlink keys eth create [command options] [arguments...] + +OPTIONS: + --evm-chain-id value, --evmChainID value Chain ID for the key. If left blank, default chain will be used. + --max-gas-price-gwei value, --maxGasPriceGWei value Optional maximum gas price (GWei) for the creating key. (default: 0) + diff --git a/testdata/scripts/keys/eth/list/help.txtar b/testdata/scripts/keys/eth/list/help.txtar new file mode 100644 index 00000000000..d7156fd3e69 --- /dev/null +++ b/testdata/scripts/keys/eth/list/help.txtar @@ -0,0 +1,9 @@ +exec chainlink keys eth list --help +cmp stdout out.txt + +-- out.txt -- +NAME: + chainlink keys eth list - List available Ethereum accounts with their ETH & LINK balances and other metadata + +USAGE: + chainlink keys eth list [arguments...] \ No newline at end of file diff --git a/testdata/scripts/keys/eth/list/unavailable.txtar b/testdata/scripts/keys/eth/list/unavailable.txtar new file mode 100644 index 00000000000..912ad75c1e4 --- /dev/null +++ b/testdata/scripts/keys/eth/list/unavailable.txtar @@ -0,0 +1,38 @@ +# start node +exec sh -c 'eval "echo \"$(cat config.toml.tmpl)\" > config.toml"' +exec chainlink node -c config.toml start -p password -a creds & + +# initialize client +env NODEURL=http://localhost:$PORT +exec curl --retry 10 --retry-max-time 60 --retry-connrefused $NODEURL +exec chainlink --remote-node-url $NODEURL admin login -file creds --bypass-version-check + +exec chainlink --remote-node-url $NODEURL keys eth list +! stdout 'ETH: ' +! stdout 'LINK: ' +! stdout '' +stdout 'ETH: Unknown' +stdout 'LINK: Unknown' + +-- testdb.txt -- +CL_DATABASE_URL +-- testport.txt -- +PORT + +-- password -- +T.tLHkcmwePT/p,]sYuntjwHKAsrhm#4eRs4LuKHwvHejWYAC2JP4M8HimwgmbaZ +-- creds -- +notreal@fakeemail.ch +fj293fbBnlQ!f9vNs + +-- config.toml.tmpl -- +[Webserver] +HTTPPort = $PORT + +[[EVM]] +ChainID = '99' + +[[EVM.Nodes]] +Name = 'fake' +WSURL = 'wss://foo.bar/ws' +HTTPURL = 'https://foo.bar' diff --git a/testdata/scripts/metrics/multi-node.txtar b/testdata/scripts/metrics/multi-node.txtar new file mode 100644 index 00000000000..c3928160443 --- /dev/null +++ b/testdata/scripts/metrics/multi-node.txtar @@ -0,0 +1,78 @@ +# Check that metrics specified in the expected_metrics are present in /metrics response +# start node +exec sh -c 'eval "echo \"$(cat config.toml.tmpl)\" > config.toml"' +exec chainlink node -c config.toml start -p password -a creds & + +# ensure node is up and running +env NODEURL=http://localhost:$PORT +exec curl --retry 10 --retry-max-time 60 --retry-connrefused $NODEURL + + +# Check +chmod 700 ./script.sh +exec sh -c './script.sh' + +-- script.sh -- + +maxRetries=5 +for retriesNum in $(seq 1 $maxRetries); do + passedAllChecks=true + curl $NODEURL/metrics > metrics.txt + while IFS= read -r expectedMetric; do + grep -q $expectedMetric metrics.txt && continue + + if [[ $retriesNum -ge $maxRetries ]]; then + cat metrics.txt + echo "FAIL Expected metric $expectedMetric to be present in GET /metrics response" + exit 1 + fi + + echo "Metric $expectedMetric is not present in GET /metrics response - retrying after 5s" + passedAllChecks=false + sleep 5 + break + done < expected_metrics.txt + + $passedAllChecks && break +done + +-- testdb.txt -- +CL_DATABASE_URL +-- testport.txt -- +PORT + +-- password -- +T.tLHkcmwePT/p,]sYuntjwHKAsrhm#4eRs4LuKHwvHejWYAC2JP4M8HimwgmbaZ +-- creds -- +notreal@fakeemail.ch +fj293fbBnlQ!f9vNs + +-- config.toml.tmpl -- +[Webserver] +HTTPPort = $PORT + +[[EVM]] +ChainID = '68472' + +[[EVM.Nodes]] +Name = 'BlueEVMPrimaryNode' +WSURL = 'wss://primaryfoo.bar/ws' +HTTPURL = 'https://primaryfoo.bar' + +[[EVM.Nodes]] +Name = 'YellowEVMPrimaryNode' +WSURL = 'wss://sendonlyfoo.bar/ws' +HTTPURL = 'https://sendonlyfoo.bar' +SendOnly = true + +-- expected_metrics.txt -- +evm_pool_rpc_node_dials_total{evmChainID="68472",nodeName="BlueEVMPrimaryNode"} +evm_pool_rpc_node_dials_total{evmChainID="68472",nodeName="YellowEVMPrimaryNode"} +multi_node_states{chainId="68472",network="EVM",state="Alive"} +multi_node_states{chainId="68472",network="EVM",state="Closed"} +multi_node_states{chainId="68472",network="EVM",state="Dialed"} +multi_node_states{chainId="68472",network="EVM",state="InvalidChainID"} +multi_node_states{chainId="68472",network="EVM",state="OutOfSync"} +multi_node_states{chainId="68472",network="EVM",state="Undialed"} +multi_node_states{chainId="68472",network="EVM",state="Unreachable"} +multi_node_states{chainId="68472",network="EVM",state="Unusable"} \ No newline at end of file diff --git a/testdata/scripts/node/db/migrate/db.txtar b/testdata/scripts/node/db/migrate/db.txtar new file mode 100644 index 00000000000..f040a937fd0 --- /dev/null +++ b/testdata/scripts/node/db/migrate/db.txtar @@ -0,0 +1,6 @@ +exec chainlink node db migrate +! stdout . +stderr 'goose: no migrations to run. current version:' + +-- testdb.txt -- +CL_DATABASE_URL diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 0b841f694be..8a3c99ee8da 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -52,8 +52,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false @@ -173,19 +171,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -253,6 +238,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + Invalid configuration: invalid secrets: 2 errors: - Database.URL: empty: must be provided and non-empty - Password.Keystore: empty: must be provided and non-empty diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index c1ac26c8d02..187e4d16328 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -96,8 +96,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false @@ -217,19 +215,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -297,6 +282,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 5ae75ffca68..cd61c8e477b 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -96,8 +96,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false @@ -217,19 +215,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -297,6 +282,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index c8b3eb4b98b..f87352fd482 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -96,8 +96,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false @@ -217,19 +215,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -297,6 +282,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index fd591212d08..f2f1f0a4ee1 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -86,8 +86,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false @@ -207,19 +205,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -287,6 +272,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index 020e66da527..0f99fb3f6d8 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -93,8 +93,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false @@ -214,19 +212,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = false -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -294,6 +279,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + [[EVM]] ChainID = '1' AutoCreateKey = true diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index a10d6df537c..01968ffd65d 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -2,18 +2,6 @@ exec chainlink node -c config.toml -s secrets.toml validate cmp stdout out.txt -- config.toml -- -[P2P.V1] -Enabled = true -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' [Tracing] Enabled = true @@ -38,20 +26,6 @@ AllowSimplePasswords = false Keystore = 'xxxxx' # Input Configuration: -[P2P] -[P2P.V1] -Enabled = true -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [Tracing] Enabled = true CollectorTarget = 'otel-collector:4317' @@ -101,8 +75,6 @@ MaxBatchSize = 50 SendInterval = '500ms' SendTimeout = '10s' UseBatchSend = true -URL = '' -ServerPubKey = '' [AuditLogger] Enabled = false @@ -222,19 +194,6 @@ OutgoingMessageBufferSize = 10 PeerID = '' TraceLogging = false -[P2P.V1] -Enabled = true -AnnounceIP = '' -AnnouncePort = 0 -BootstrapCheckInterval = '20s' -DefaultBootstrapPeers = [] -DHTAnnouncementCounterUserPrefix = 0 -DHTLookupInterval = 10 -ListenIP = '0.0.0.0' -ListenPort = 0 -NewStreamTimeout = '10s' -PeerstoreWriteInterval = '5m0s' - [P2P.V2] Enabled = true AnnounceAddresses = [] @@ -302,19 +261,9 @@ LatestReportTTL = '1s' MaxStaleAge = '1h0m0s' LatestReportDeadline = '5s' +[Mercury.TLS] +CertFile = '' + # Configuration warning: -3 errors: - - P2P.V1: is deprecated and will be removed in a future version - - P2P.V1: 10 errors: - - AnnounceIP: is deprecated and will be removed in a future version - - AnnouncePort: is deprecated and will be removed in a future version - - BootstrapCheckInterval: is deprecated and will be removed in a future version - - DefaultBootstrapPeers: is deprecated and will be removed in a future version - - DHTAnnouncementCounterUserPrefix: is deprecated and will be removed in a future version - - DHTLookupInterval: is deprecated and will be removed in a future version - - ListenIP: is deprecated and will be removed in a future version - - ListenPort: is deprecated and will be removed in a future version - - NewStreamTimeout: is deprecated and will be removed in a future version - - PeerstoreWriteInterval: is deprecated and will be removed in a future version - - Tracing.TLSCertPath: invalid value (something): must be empty when Tracing.Mode is 'unencrypted' +Tracing.TLSCertPath: invalid value (something): must be empty when Tracing.Mode is 'unencrypted' Valid configuration. diff --git a/tools/benchmark/job_spec_delete_v2.sh b/tools/benchmark/job_spec_delete_v2.sh index c422d41fd53..e0fd531a228 100644 --- a/tools/benchmark/job_spec_delete_v2.sh +++ b/tools/benchmark/job_spec_delete_v2.sh @@ -116,7 +116,7 @@ contractConfigConfirmations = 3 contractConfigTrackerPollInterval = "1m" contractConfigTrackerSubscribeInterval = "2m" isBootstrapPeer = true -p2pBootstrapPeers = [] +p2pv2Bootstrappers = [] p2pPeerID = "p2p_12D3KooWMk13oppZXmGdRZgaJBFDF6Tc5521YYxKjwkscLSEPrVW" schemaVersion = 1 type = "offchainreporting" diff --git a/tools/bin/cldev b/tools/bin/cldev index af8d8c06135..77d0a7b8bb8 100755 --- a/tools/bin/cldev +++ b/tools/bin/cldev @@ -12,6 +12,6 @@ case "$1" in go run -ldflags "$LDFLAGS" . -- node start -d -p tools/secrets/password.txt -a tools/secrets/apicredentials ;; *) - go run . -- $@ + go run . -- "$@" ;; esac diff --git a/tools/bin/go_core_fuzz b/tools/bin/go_core_fuzz new file mode 100755 index 00000000000..3ea7d9bb0cb --- /dev/null +++ b/tools/bin/go_core_fuzz @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -o pipefail +set +e + +SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"` +OUTPUT_FILE=${OUTPUT_FILE:-"./output.txt"} +USE_TEE="${USE_TEE:-true}" + +echo "Failed tests and panics: ---------------------" +echo "" +GO_LDFLAGS=$(bash tools/bin/ldflags) +use_tee() { + if [ "$USE_TEE" = "true" ]; then + tee "$@" + else + cat > "$@" + fi +} +go test -json -ldflags "$GO_LDFLAGS" github.com/smartcontractkit/chainlink/v2/core/services/relay/evm -fuzz . -fuzztime 12s | use_tee $OUTPUT_FILE +EXITCODE=${PIPESTATUS[0]} + +# Assert no known sensitive strings present in test logger output +printf "\n----------------------------------------------\n\n" +echo "Beginning check of output logs for sensitive strings" +$SCRIPT_PATH/scrub_logs $OUTPUT_FILE +if [[ $? != 0 ]]; then + exit 1 +fi + +echo "Exit code: $EXITCODE" +if [[ $EXITCODE != 0 ]]; then + echo "Encountered test failures." +else + echo "All tests passed!" +fi +exit $EXITCODE diff --git a/tools/bin/modgraph b/tools/bin/modgraph new file mode 100755 index 00000000000..b61264cb021 --- /dev/null +++ b/tools/bin/modgraph @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# Generates go.md + +set -e + +echo "# smartcontractkit Go modules +\`\`\`mermaid +flowchart LR + subgraph chains + chainlink-cosmos + chainlink-evm + chainlink-solana + chainlink-starknet/relayer + end + + subgraph products + chainlink-automation + chainlink-ccip + chainlink-data-streams + chainlink-feeds + chainlink-functions + chainlink-vrf + end + + classDef outline stroke-dasharray:6,fill:none; + class chains,products outline +" +go mod graph | \ + # org only + grep smartcontractkit.*smartcontractkit | \ + # drop prefix + sed s/"github\.com\/smartcontractkit\/"/""/g | \ + # insert edges + sed s/" "/" --> "/ | \ + # drop versions + sed s/"@[^ ]*"/""/g | \ + # insert links + sed s/"\([^ ]*\)$"/"\1\nclick \1 href \"https:\/\/github.com\/smartcontractkit\/\1\""/ | \ + # truncate links to repo + sed s/"\"https:\/\/github.com\/smartcontractkit\/\([^\"\/]*\)\/.*\""/"\"https:\/\/github.com\/smartcontractkit\/\1\""/ | \ + # dedupe lines + awk '!x[$0]++' | \ + # indent + sed 's/^/ /' +echo "\`\`\`" \ No newline at end of file diff --git a/tools/flakeytests/cmd/runner/main.go b/tools/flakeytests/cmd/runner/main.go index f38179f502b..0f36ab25ef9 100644 --- a/tools/flakeytests/cmd/runner/main.go +++ b/tools/flakeytests/cmd/runner/main.go @@ -1,10 +1,12 @@ package main import ( + "context" "flag" "io" "log" "os" + "os/signal" "strings" "github.com/smartcontractkit/chainlink/v2/tools/flakeytests" @@ -13,6 +15,13 @@ import ( const numReruns = 2 func main() { + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) + go func() { + <-ctx.Done() + stop() // restore default exit behavior + log.Println("Cancelling... interrupt again to exit") + }() + grafanaHost := flag.String("grafana_host", "", "grafana host URL") grafanaAuth := flag.String("grafana_auth", "", "grafana basic auth for Loki API") command := flag.String("command", "", "test command being rerun; used to tag metrics") @@ -48,10 +57,10 @@ func main() { readers = append(readers, r) } - ctx := flakeytests.GetGithubMetadata(*ghRepo, *ghEventName, *ghSHA, *ghEventPath, *ghRunID) - rep := flakeytests.NewLokiReporter(*grafanaHost, *grafanaAuth, *command, ctx) + meta := flakeytests.GetGithubMetadata(*ghRepo, *ghEventName, *ghSHA, *ghEventPath, *ghRunID) + rep := flakeytests.NewLokiReporter(*grafanaHost, *grafanaAuth, *command, meta) r := flakeytests.NewRunner(readers, rep, numReruns) - err := r.Run() + err := r.Run(ctx) if err != nil { log.Fatalf("Error re-running flakey tests: %s", err) } diff --git a/tools/flakeytests/reporter.go b/tools/flakeytests/reporter.go index 6696ec29a40..b7c7f66698f 100644 --- a/tools/flakeytests/reporter.go +++ b/tools/flakeytests/reporter.go @@ -2,6 +2,7 @@ package flakeytests import ( "bytes" + "context" "encoding/base64" "encoding/json" "fmt" @@ -11,6 +12,12 @@ import ( "time" ) +const ( + messageType_flakeyTest = "flakey_test" + messageType_runReport = "run_report" + messageType_packagePanic = "package_panic" +) + type pushRequest struct { Streams []stream `json:"streams"` } @@ -20,16 +27,28 @@ type stream struct { Values [][]string `json:"values"` } +type BaseMessage struct { + MessageType string `json:"message_type"` + Context +} + type flakeyTest struct { + BaseMessage Package string `json:"package"` TestName string `json:"test_name"` FQTestName string `json:"fq_test_name"` - Context } -type numFlakes struct { - NumFlakes int `json:"num_flakes"` - Context +type packagePanic struct { + BaseMessage + Package string `json:"package"` +} + +type runReport struct { + BaseMessage + NumPackagePanics int `json:"num_package_panics"` + NumFlakes int `json:"num_flakes"` + NumCombined int `json:"num_combined"` } type Context struct { @@ -48,17 +67,21 @@ type LokiReporter struct { ctx Context } -func (l *LokiReporter) createRequest(flakeyTests map[string]map[string]struct{}) (pushRequest, error) { +func (l *LokiReporter) createRequest(report *Report) (pushRequest, error) { vs := [][]string{} now := l.now() nows := fmt.Sprintf("%d", now.UnixNano()) - for pkg, tests := range flakeyTests { + + for pkg, tests := range report.tests { for t := range tests { d, err := json.Marshal(flakeyTest{ + BaseMessage: BaseMessage{ + MessageType: messageType_flakeyTest, + Context: l.ctx, + }, Package: pkg, TestName: t, FQTestName: fmt.Sprintf("%s:%s", pkg, t), - Context: l.ctx, }) if err != nil { return pushRequest{}, err @@ -67,10 +90,35 @@ func (l *LokiReporter) createRequest(flakeyTests map[string]map[string]struct{}) } } - // Flakes are store in a map[string][]string, so to count them, we can't just do len(flakeyTests), + // Flakes are stored in a map[string][]string, so to count them, we can't just do len(flakeyTests), // as that will get us the number of flakey packages, not the number of flakes tests. // However, we do emit one log line per flakey test above, so use that to count our flakes. - f, err := json.Marshal(numFlakes{NumFlakes: len(vs), Context: l.ctx}) + numFlakes := len(vs) + + for pkg := range report.packagePanics { + d, err := json.Marshal(packagePanic{ + BaseMessage: BaseMessage{ + MessageType: messageType_packagePanic, + Context: l.ctx, + }, + Package: pkg, + }) + if err != nil { + return pushRequest{}, err + } + + vs = append(vs, []string{nows, string(d)}) + } + + f, err := json.Marshal(runReport{ + BaseMessage: BaseMessage{ + MessageType: messageType_runReport, + Context: l.ctx, + }, + NumFlakes: numFlakes, + NumPackagePanics: len(report.packagePanics), + NumCombined: numFlakes + len(report.packagePanics), + }) if err != nil { return pushRequest{}, nil } @@ -91,14 +139,14 @@ func (l *LokiReporter) createRequest(flakeyTests map[string]map[string]struct{}) return pr, nil } -func (l *LokiReporter) makeRequest(pushReq pushRequest) error { +func (l *LokiReporter) makeRequest(ctx context.Context, pushReq pushRequest) error { body, err := json.Marshal(pushReq) if err != nil { return err } u := url.URL{Scheme: "https", Host: l.host, Path: "loki/api/v1/push"} - req, err := http.NewRequest("POST", u.String(), bytes.NewReader(body)) + req, err := http.NewRequestWithContext(ctx, "POST", u.String(), bytes.NewReader(body)) if err != nil { return err } @@ -120,13 +168,13 @@ func (l *LokiReporter) makeRequest(pushReq pushRequest) error { return err } -func (l *LokiReporter) Report(flakeyTests map[string]map[string]struct{}) error { - pushReq, err := l.createRequest(flakeyTests) +func (l *LokiReporter) Report(ctx context.Context, report *Report) error { + pushReq, err := l.createRequest(report) if err != nil { return err } - return l.makeRequest(pushReq) + return l.makeRequest(ctx, pushReq) } func NewLokiReporter(host, auth, command string, ctx Context) *LokiReporter { diff --git a/tools/flakeytests/reporter_test.go b/tools/flakeytests/reporter_test.go index 9cb2c8e9f7d..15650fc7bd1 100644 --- a/tools/flakeytests/reporter_test.go +++ b/tools/flakeytests/reporter_test.go @@ -12,68 +12,131 @@ import ( func TestMakeRequest_SingleTest(t *testing.T) { now := time.Now() ts := fmt.Sprintf("%d", now.UnixNano()) - ft := map[string]map[string]struct{}{ - "core/assets": map[string]struct{}{ - "TestLink": struct{}{}, + r := &Report{ + tests: map[string]map[string]int{ + "core/assets": map[string]int{ + "TestLink": 1, + }, }, } lr := &LokiReporter{auth: "bla", host: "bla", command: "go_core_tests", now: func() time.Time { return now }} - pr, err := lr.createRequest(ft) + pr, err := lr.createRequest(r) require.NoError(t, err) assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, `{"package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink","commit_sha":"","repository":"","event_type":""}`}, - {ts, `{"num_flakes":1,"commit_sha":"","repository":"","event_type":""}`}, + {ts, `{"message_type":"flakey_test","commit_sha":"","repository":"","event_type":"","package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink"}`}, + {ts, `{"message_type":"run_report","commit_sha":"","repository":"","event_type":"","num_package_panics":0,"num_flakes":1,"num_combined":1}`}, }) } func TestMakeRequest_MultipleTests(t *testing.T) { now := time.Now() ts := fmt.Sprintf("%d", now.UnixNano()) - ft := map[string]map[string]struct{}{ - "core/assets": map[string]struct{}{ - "TestLink": struct{}{}, - "TestCore": struct{}{}, + r := &Report{ + tests: map[string]map[string]int{ + "core/assets": map[string]int{ + "TestLink": 1, + "TestCore": 1, + }, }, } lr := &LokiReporter{auth: "bla", host: "bla", command: "go_core_tests", now: func() time.Time { return now }} - pr, err := lr.createRequest(ft) + pr, err := lr.createRequest(r) require.NoError(t, err) assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, `{"package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink","commit_sha":"","repository":"","event_type":""}`}, - {ts, `{"package":"core/assets","test_name":"TestCore","fq_test_name":"core/assets:TestCore","commit_sha":"","repository":"","event_type":""}`}, - {ts, `{"num_flakes":2,"commit_sha":"","repository":"","event_type":""}`}, + {ts, `{"message_type":"flakey_test","commit_sha":"","repository":"","event_type":"","package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink"}`}, + {ts, `{"message_type":"flakey_test","commit_sha":"","repository":"","event_type":"","package":"core/assets","test_name":"TestCore","fq_test_name":"core/assets:TestCore"}`}, + {ts, `{"message_type":"run_report","commit_sha":"","repository":"","event_type":"","num_package_panics":0,"num_flakes":2,"num_combined":2}`}, }) } func TestMakeRequest_NoTests(t *testing.T) { now := time.Now() ts := fmt.Sprintf("%d", now.UnixNano()) - ft := map[string]map[string]struct{}{} + r := NewReport() lr := &LokiReporter{auth: "bla", host: "bla", command: "go_core_tests", now: func() time.Time { return now }} - pr, err := lr.createRequest(ft) + pr, err := lr.createRequest(r) require.NoError(t, err) assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, `{"num_flakes":0,"commit_sha":"","repository":"","event_type":""}`}, + {ts, `{"message_type":"run_report","commit_sha":"","repository":"","event_type":"","num_package_panics":0,"num_flakes":0,"num_combined":0}`}, }) } func TestMakeRequest_WithContext(t *testing.T) { now := time.Now() ts := fmt.Sprintf("%d", now.UnixNano()) - ft := map[string]map[string]struct{}{} + r := NewReport() lr := &LokiReporter{auth: "bla", host: "bla", command: "go_core_tests", now: func() time.Time { return now }, ctx: Context{CommitSHA: "42"}} - pr, err := lr.createRequest(ft) + pr, err := lr.createRequest(r) require.NoError(t, err) assert.Len(t, pr.Streams, 1) assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ - {ts, `{"num_flakes":0,"commit_sha":"42","repository":"","event_type":""}`}, + {ts, `{"message_type":"run_report","commit_sha":"42","repository":"","event_type":"","num_package_panics":0,"num_flakes":0,"num_combined":0}`}, }) } + +func TestMakeRequest_Panics(t *testing.T) { + now := time.Now() + ts := fmt.Sprintf("%d", now.UnixNano()) + r := &Report{ + tests: map[string]map[string]int{ + "core/assets": map[string]int{ + "TestLink": 1, + }, + }, + packagePanics: map[string]int{ + "core/assets": 1, + }, + } + lr := &LokiReporter{auth: "bla", host: "bla", command: "go_core_tests", now: func() time.Time { return now }} + pr, err := lr.createRequest(r) + require.NoError(t, err) + assert.Len(t, pr.Streams, 1) + assert.Equal(t, pr.Streams[0].Stream, map[string]string{"command": "go_core_tests", "app": "flakey-test-reporter"}) + + assert.ElementsMatch(t, pr.Streams[0].Values, [][]string{ + {ts, `{"message_type":"flakey_test","commit_sha":"","repository":"","event_type":"","package":"core/assets","test_name":"TestLink","fq_test_name":"core/assets:TestLink"}`}, + {ts, `{"message_type":"package_panic","commit_sha":"","repository":"","event_type":"","package":"core/assets"}`}, + {ts, `{"message_type":"run_report","commit_sha":"","repository":"","event_type":"","num_package_panics":1,"num_flakes":1,"num_combined":2}`}, + }) +} + +func TestDedupeEntries(t *testing.T) { + r := &Report{ + tests: map[string]map[string]int{ + "core/assets": map[string]int{ + "TestSomethingAboutAssets/test_1": 2, + "TestSomethingAboutAssets": 4, + "TestSomeOtherTest": 1, + "TestSomethingAboutAssets/test_2": 2, + "TestFinalTest/test_1": 1, + }, + "core/services/important_service": map[string]int{ + "TestAnImportantService/a_subtest": 1, + }, + }, + } + + otherReport, err := dedupeEntries(r) + require.NoError(t, err) + + expectedMap := map[string]map[string]int{ + "core/assets": map[string]int{ + "TestSomethingAboutAssets/test_1": 2, + "TestSomeOtherTest": 1, + "TestSomethingAboutAssets/test_2": 2, + "TestFinalTest/test_1": 1, + }, + "core/services/important_service": map[string]int{ + "TestAnImportantService/a_subtest": 1, + }, + } + assert.Equal(t, expectedMap, otherReport.tests) +} diff --git a/tools/flakeytests/runner.go b/tools/flakeytests/runner.go index d935000222f..88ab647e7c1 100644 --- a/tools/flakeytests/runner.go +++ b/tools/flakeytests/runner.go @@ -3,6 +3,7 @@ package flakeytests import ( "bufio" "bytes" + "context" "encoding/json" "errors" "fmt" @@ -11,6 +12,7 @@ import ( "os" "os/exec" "regexp" + "sort" "strings" "time" ) @@ -32,10 +34,10 @@ type tester interface { } type reporter interface { - Report(map[string]map[string]struct{}) error + Report(ctx context.Context, r *Report) error } -type parseFn func(readers ...io.Reader) (map[string]map[string]int, error) +type parseFn func(readers ...io.Reader) (*Report, error) func NewRunner(readers []io.Reader, reporter reporter, numReruns int) *Runner { tc := &testCommand{ @@ -60,9 +62,14 @@ type testCommand struct { func (t *testCommand) test(pkg string, tests []string, w io.Writer) error { replacedPkg := strings.Replace(pkg, t.repo, "", -1) - testFilter := strings.Join(tests, "|") cmd := exec.Command(t.command, fmt.Sprintf(".%s", replacedPkg)) //#nosec - cmd.Env = append(os.Environ(), fmt.Sprintf("TEST_FLAGS=-run %s", testFilter)) + cmd.Env = os.Environ() + + if len(tests) > 0 { + testFilter := strings.Join(tests, "|") + cmd.Env = append(cmd.Env, fmt.Sprintf("TEST_FLAGS=-run %s", testFilter)) + } + cmd.Stdout = io.MultiWriter(os.Stdout, w) cmd.Stderr = io.MultiWriter(os.Stderr, w) t.overrides(cmd) @@ -84,8 +91,8 @@ func newEvent(b []byte) (*TestEvent, error) { return e, err } -func parseOutput(readers ...io.Reader) (map[string]map[string]int, error) { - tests := map[string]map[string]int{} +func parseOutput(readers ...io.Reader) (*Report, error) { + report := NewReport() for _, r := range readers { s := bufio.NewScanner(r) for s.Scan() { @@ -105,24 +112,32 @@ func parseOutput(readers ...io.Reader) (map[string]map[string]int, error) { return nil, err } - // We're only interested in test failures, for which - // both Package and Test would be present. - if e.Package == "" || e.Test == "" { - continue - } - switch e.Action { case "fail": - if tests[e.Package] == nil { - tests[e.Package] = map[string]int{} + // Fail logs come in two forms: + // - with e.Package && e.Test, in which case it indicates a test failure. + // - with e.Package only, which indicates that the package test has failed, + // or possible that there has been a panic in an out-of-process goroutine running + // as part of the tests. + // + // We can ignore the last case because a package failure will be accounted elsewhere, either + // in the form of a failing test entry, or in the form of a panic output log, covered below. + if e.Test == "" { + continue } - tests[e.Package][e.Test]++ + + report.IncTest(e.Package, e.Test) case "output": if panicRe.MatchString(e.Output) { - if tests[e.Package] == nil { - tests[e.Package] = map[string]int{} + // Similar to the above, a panic can come in two forms: + // - attached to a test (i.e. with e.Test != ""), in which case + // we'll treat it like a failing test. + // - package-scoped, in which case we'll treat it as a package panic. + if e.Test != "" { + report.IncTest(e.Package, e.Test) + } else { + report.IncPackagePanic(e.Package) } - tests[e.Package][e.Test]++ } } } @@ -131,75 +146,183 @@ func parseOutput(readers ...io.Reader) (map[string]map[string]int, error) { return nil, err } } - return tests, nil + + return report, nil } type exitCoder interface { ExitCode() int } -func (r *Runner) runTests(failedTests map[string]map[string]int) (map[string]map[string]struct{}, error) { - suspectedFlakes := map[string]map[string]struct{}{} +type Report struct { + tests map[string]map[string]int + packagePanics map[string]int +} + +func NewReport() *Report { + return &Report{ + tests: map[string]map[string]int{}, + packagePanics: map[string]int{}, + } +} + +func (r *Report) HasFlakes() bool { + return len(r.tests) > 0 || len(r.packagePanics) > 0 +} + +func (r *Report) SetTest(pkg, test string, val int) { + if r.tests[pkg] == nil { + r.tests[pkg] = map[string]int{} + } + r.tests[pkg][test] = val +} + +func (r *Report) IncTest(pkg string, test string) { + if r.tests[pkg] == nil { + r.tests[pkg] = map[string]int{} + } + r.tests[pkg][test]++ +} - for pkg, tests := range failedTests { +func (r *Report) IncPackagePanic(pkg string) { + r.packagePanics[pkg]++ +} + +func (r *Runner) runTest(pkg string, tests []string) (*Report, error) { + var out bytes.Buffer + err := r.testCommand.test(pkg, tests, &out) + if err != nil { + log.Printf("Test command errored: %s\n", err) + // There was an error because the command failed with a non-zero + // exit code. This could just mean that the test failed again, so let's + // keep going. + var exErr exitCoder + if errors.As(err, &exErr) && exErr.ExitCode() > 0 { + return r.parse(&out) + } + return nil, err + } + + return r.parse(&out) +} + +func (r *Runner) runTests(rep *Report) (*Report, error) { + report := NewReport() + + // We need to deal with two types of flakes here: + // - flakes where we know the test that failed; in this case, we just rerun the failing test in question + // - flakes where we don't know what test failed. These are flakes where a panic occurred in an out-of-process goroutine, + // thus failing the package as a whole. For these, we'll rerun the whole package again. + for pkg, tests := range rep.tests { ts := []string{} for test := range tests { ts = append(ts, test) } - log.Printf("Executing test command with parameters: pkg=%s, tests=%+v, numReruns=%d\n", pkg, ts, r.numReruns) + log.Printf("[FLAKEY_TEST] Executing test command with parameters: pkg=%s, tests=%+v, numReruns=%d\n", pkg, ts, r.numReruns) for i := 0; i < r.numReruns; i++ { - var out bytes.Buffer - - err := r.testCommand.test(pkg, ts, &out) + pr, err := r.runTest(pkg, ts) if err != nil { - log.Printf("Test command errored: %s\n", err) - // There was an error because the command failed with a non-zero - // exit code. This could just mean that the test failed again, so let's - // keep going. - var exErr exitCoder - if errors.As(err, &exErr) && exErr.ExitCode() > 0 { - continue + return report, err + } + + for t := range tests { + failures := pr.tests[pkg][t] + if failures == 0 { + report.SetTest(pkg, t, 1) } - return suspectedFlakes, err } - fr, err := r.parse(&out) + } + } + + for pkg := range rep.packagePanics { + log.Printf("[PACKAGE_PANIC]: Executing test command with parameters: pkg=%s, numReruns=%d\n", pkg, r.numReruns) + for i := 0; i < r.numReruns; i++ { + pr, err := r.runTest(pkg, []string{}) if err != nil { - return nil, err + return report, err } - for t := range tests { - failures := fr[pkg][t] - if failures == 0 { - if suspectedFlakes[pkg] == nil { - suspectedFlakes[pkg] = map[string]struct{}{} - } - suspectedFlakes[pkg][t] = struct{}{} - } + if pr.packagePanics[pkg] == 0 { + report.IncPackagePanic(pkg) + } + } + } + + return report, nil +} + +func isSubtest(tn string) bool { + return strings.Contains(tn, "/") +} + +func isSubtestOf(st, mt string) bool { + return isSubtest(st) && strings.Contains(st, mt) +} + +func dedupeEntries(report *Report) (*Report, error) { + out := NewReport() + out.packagePanics = report.packagePanics + for pkg, tests := range report.tests { + // Sort the test names + testNames := make([]string, 0, len(tests)) + for t := range tests { + testNames = append(testNames, t) + } + + sort.Strings(testNames) + + for i, tn := range testNames { + // Is this the last element? If it is, then add it to the deduped set. + // This is because a) it's a main test, in which case we add it because + // it has no subtests following it, or b) it's a subtest, which we always add. + if i == len(testNames)-1 { + out.SetTest(pkg, tn, report.tests[pkg][tn]) + continue } + + // Next, let's compare the current item to the next one in the alphabetical order. + // In all cases we want to add the current item, UNLESS the current item is a main test, + // and the following one is a subtest of the current item. + nextItem := testNames[i+1] + if !isSubtest(tn) && isSubtestOf(nextItem, tn) { + continue + } + + out.SetTest(pkg, tn, report.tests[pkg][tn]) } + } - return suspectedFlakes, nil + return out, nil } -func (r *Runner) Run() error { - failedTests, err := r.parse(r.readers...) +func (r *Runner) Run(ctx context.Context) error { + parseReport, err := r.parse(r.readers...) if err != nil { return err } - suspectedFlakes, err := r.runTests(failedTests) + report, err := r.runTests(parseReport) if err != nil { return err } - if len(suspectedFlakes) > 0 { - log.Printf("ERROR: Suspected flakes found: %+v\n", suspectedFlakes) + if report.HasFlakes() { + log.Printf("ERROR: Suspected flakes found: %+v\n", report) } else { log.Print("SUCCESS: No suspected flakes detected") } - return r.reporter.Report(suspectedFlakes) + // Before reporting the errors, let's dedupe some entries: + // In actuality, a failing subtest will produce two failing test entries, + // namely one for the test as a whole, and one for the subtest. + // This leads to inaccurate metrics since a failing subtest is double-counted. + report, err = dedupeEntries(report) + if err != nil { + return err + } + + return r.reporter.Report(ctx, report) } diff --git a/tools/flakeytests/runner_test.go b/tools/flakeytests/runner_test.go index 31f300dcbee..ee069a1655d 100644 --- a/tools/flakeytests/runner_test.go +++ b/tools/flakeytests/runner_test.go @@ -1,6 +1,7 @@ package flakeytests import ( + "context" "io" "os" "os/exec" @@ -9,19 +10,21 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" ) type mockReporter struct { - entries map[string]map[string]struct{} + report *Report } -func (m *mockReporter) Report(entries map[string]map[string]struct{}) error { - m.entries = entries +func (m *mockReporter) Report(_ context.Context, report *Report) error { + m.report = report return nil } func newMockReporter() *mockReporter { - return &mockReporter{entries: map[string]map[string]struct{}{}} + return &mockReporter{report: NewReport()} } func TestParser(t *testing.T) { @@ -29,9 +32,10 @@ func TestParser(t *testing.T) { ` r := strings.NewReader(output) - ts, err := parseOutput(r) + pr, err := parseOutput(r) require.NoError(t, err) + ts := pr.tests assert.Len(t, ts, 1) assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"], 1) assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"], 1) @@ -44,9 +48,10 @@ func TestParser_SkipsNonJSON(t *testing.T) { ` r := strings.NewReader(output) - ts, err := parseOutput(r) + pr, err := parseOutput(r) require.NoError(t, err) + ts := pr.tests assert.Len(t, ts, 1) assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"], 1) assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"], 1) @@ -58,9 +63,10 @@ func TestParser_PanicDueToLogging(t *testing.T) { ` r := strings.NewReader(output) - ts, err := parseOutput(r) + pr, err := parseOutput(r) require.NoError(t, err) + ts := pr.tests assert.Len(t, ts, 1) assert.Len(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"], 1) assert.Equal(t, ts["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestAssets_LinkScanValue"], 1) @@ -85,7 +91,7 @@ func TestParser_SuccessfulOutput(t *testing.T) { r := strings.NewReader(output) ts, err := parseOutput(r) require.NoError(t, err) - assert.Len(t, ts, 0) + assert.Len(t, ts.tests, 0) } type testAdapter func(string, []string, io.Writer) error @@ -117,10 +123,10 @@ func TestRunner_WithFlake(t *testing.T) { // This will report a flake since we've mocked the rerun // to only report one failure (not two as expected). - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) - assert.Len(t, m.entries, 1) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] + assert.Len(t, m.report.tests, 1) + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } @@ -152,10 +158,10 @@ func TestRunner_WithFailedPackage(t *testing.T) { // This will report a flake since we've mocked the rerun // to only report one failure (not two as expected). - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) - assert.Len(t, m.entries, 1) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] + assert.Len(t, m.report.tests, 1) + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } @@ -178,9 +184,9 @@ func TestRunner_AllFailures(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) - assert.Len(t, m.entries, 0) + assert.Len(t, m.report.tests, 0) } func TestRunner_RerunSuccessful(t *testing.T) { @@ -204,9 +210,9 @@ func TestRunner_RerunSuccessful(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } @@ -226,9 +232,9 @@ func TestRunner_RootLevelTest(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/"]["TestConfigDocs"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/"]["TestConfigDocs"] assert.True(t, ok) } @@ -253,9 +259,9 @@ func TestRunner_RerunFailsWithNonzeroExitCode(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } @@ -290,15 +296,30 @@ func TestRunner_RerunWithNonZeroExitCodeDoesntStopCommand(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) calls := index assert.Equal(t, 4, calls) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"]["TestLink"] assert.True(t, ok) } +// Used for integration tests +func TestSkippedForTests_Subtests(t *testing.T) { + if os.Getenv("FLAKEY_TEST_RUNNER_RUN_FIXTURE_TEST") != "1" { + t.Skip() + } + + t.Run("1: should fail", func(t *testing.T) { + assert.False(t, true) + }) + + t.Run("2: should fail", func(t *testing.T) { + assert.False(t, true) + }) +} + // Used for integration tests func TestSkippedForTests(t *testing.T) { if os.Getenv("FLAKEY_TEST_RUNNER_RUN_FIXTURE_TEST") != "1" { @@ -319,7 +340,51 @@ func TestSkippedForTests_Success(t *testing.T) { assert.True(t, true) } -func TestParsesPanicCorrectly(t *testing.T) { +func TestIntegration_DealsWithSubtests(t *testing.T) { + if testing.Short() { + t.Skip() + } + + output := ` +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/tools/flakeytests/","Test":"TestSkippedForTests_Subtests/1:_should_fail","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/tools/flakeytests/","Test":"TestSkippedForTests_Subtests","Elapsed":0} +{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/tools/flakeytests/","Test":"TestSkippedForTests_Subtests/2:_should_fail","Elapsed":0} +` + + m := newMockReporter() + tc := &testCommand{ + repo: "github.com/smartcontractkit/chainlink/v2/tools/flakeytests", + command: "../bin/go_core_tests", + overrides: func(cmd *exec.Cmd) { + cmd.Env = append(cmd.Env, "FLAKEY_TESTRUNNER_RUN_FIXTURE_TEST=1") + cmd.Stdout = io.Discard + cmd.Stderr = io.Discard + }, + } + r := &Runner{ + numReruns: 2, + readers: []io.Reader{strings.NewReader(output)}, + testCommand: tc, + parse: parseOutput, + reporter: m, + } + + err := r.Run(tests.Context(t)) + require.NoError(t, err) + expectedTests := map[string]map[string]int{ + "github.com/smartcontractkit/chainlink/v2/tools/flakeytests/": { + "TestSkippedForTests_Subtests/1:_should_fail": 1, + "TestSkippedForTests_Subtests/2:_should_fail": 1, + }, + } + assert.Equal(t, expectedTests, m.report.tests) +} + +func TestIntegration_ParsesPanics(t *testing.T) { + if testing.Short() { + t.Skip() + } + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/tools/flakeytests/","Test":"TestSkippedForTests","Elapsed":0}` m := newMockReporter() @@ -340,13 +405,17 @@ func TestParsesPanicCorrectly(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/tools/flakeytests"]["TestSkippedForTests"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/tools/flakeytests"]["TestSkippedForTests"] assert.False(t, ok) } func TestIntegration(t *testing.T) { + if testing.Short() { + t.Skip() + } + output := `{"Time":"2023-09-07T15:39:46.378315+01:00","Action":"fail","Package":"github.com/smartcontractkit/chainlink/v2/tools/flakeytests/","Test":"TestSkippedForTests_Success","Elapsed":0}` m := newMockReporter() @@ -367,8 +436,8 @@ func TestIntegration(t *testing.T) { reporter: m, } - err := r.Run() + err := r.Run(tests.Context(t)) require.NoError(t, err) - _, ok := m.entries["github.com/smartcontractkit/chainlink/v2/tools/flakeytests"]["TestSkippedForTests_Success"] + _, ok := m.report.tests["github.com/smartcontractkit/chainlink/v2/tools/flakeytests"]["TestSkippedForTests_Success"] assert.False(t, ok) }